@deix/rossini-identity-management 0.1.0 → 0.1.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/lib/app/[locale]/groups/{page.js → page.jsx} +1 -1
- package/lib/app/[locale]/{layout.js → layout.jsx} +4 -3
- package/lib/app/[locale]/users/{page.js → page.jsx} +1 -1
- package/lib/app/{layout.js → layout.jsx} +7 -3
- package/lib/components/AddItemDialog.jsx +50 -0
- package/lib/components/DeleteConfirmationDialog.jsx +44 -0
- package/lib/components/SearchField.jsx +18 -0
- package/lib/components/groups/CreateGroupDialog.d.ts.map +1 -1
- package/lib/components/groups/{CreateGroupDialog.js → CreateGroupDialog.jsx} +9 -8
- package/lib/components/groups/GroupDetails.d.ts.map +1 -1
- package/lib/components/groups/{GroupDetails.js → GroupDetails.jsx} +5 -6
- package/lib/components/groups/GroupForm.jsx +46 -0
- package/lib/components/groups/GroupTabs.d.ts.map +1 -1
- package/lib/components/groups/GroupTabs.jsx +33 -0
- package/lib/components/groups/GroupUsers.d.ts.map +1 -1
- package/lib/components/groups/GroupUsers.jsx +88 -0
- package/lib/components/groups/Groups.d.ts.map +1 -1
- package/lib/components/groups/{Groups.js → Groups.jsx} +45 -30
- package/lib/components/groups/GroupsTable.jsx +55 -0
- package/lib/components/users/CreateUserDialog.d.ts.map +1 -1
- package/lib/components/users/{CreateUserDialog.js → CreateUserDialog.jsx} +9 -8
- package/lib/components/users/UserCredentials.d.ts.map +1 -1
- package/lib/components/users/{UserCredentials.js → UserCredentials.jsx} +8 -6
- package/lib/components/users/UserDetails.d.ts.map +1 -1
- package/lib/components/users/{UserDetails.js → UserDetails.jsx} +5 -6
- package/lib/components/users/UserForm.jsx +75 -0
- package/lib/components/users/UserGroups.d.ts.map +1 -1
- package/lib/components/users/UserGroups.jsx +78 -0
- package/lib/components/users/Users.d.ts.map +1 -1
- package/lib/components/users/{Users.js → Users.jsx} +45 -30
- package/lib/components/users/UsersTable.jsx +76 -0
- package/lib/components/users/UsersTabs.d.ts.map +1 -1
- package/lib/components/users/UsersTabs.jsx +36 -0
- package/lib/config/{index.js → index.jsx} +3 -1
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/utils/hooks/useAPIClient.d.ts +10 -0
- package/lib/utils/hooks/useAPIClient.d.ts.map +1 -0
- package/lib/utils/hooks/useAPIClient.jsx +18 -0
- package/package.json +1 -1
- package/lib/components/AddItemDialog.js +0 -45
- package/lib/components/DeleteConfirmationDialog.js +0 -35
- package/lib/components/SearchField.js +0 -16
- package/lib/components/groups/GroupForm.js +0 -38
- package/lib/components/groups/GroupTabs.js +0 -29
- package/lib/components/groups/GroupUsers.js +0 -74
- package/lib/components/groups/GroupsTable.js +0 -43
- package/lib/components/users/UserForm.js +0 -62
- package/lib/components/users/UserGroups.js +0 -64
- package/lib/components/users/UsersTable.js +0 -62
- package/lib/components/users/UsersTabs.js +0 -32
|
@@ -4,6 +4,6 @@ import { useConfig } from '../../../config';
|
|
|
4
4
|
import Groups from '../../../components/groups/Groups';
|
|
5
5
|
const GroupsPage = () => {
|
|
6
6
|
const config = useConfig();
|
|
7
|
-
return
|
|
7
|
+
return <Groups apiUrl={config.generalProperties.apiURL}/>;
|
|
8
8
|
};
|
|
9
9
|
export default GroupsPage;
|
|
@@ -18,7 +18,8 @@ export default function RootLayout({ children, }) {
|
|
|
18
18
|
},
|
|
19
19
|
},
|
|
20
20
|
});
|
|
21
|
-
return (
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
return (<QueryClientProvider client={queryClient}>
|
|
22
|
+
<PageProvider>{children}</PageProvider>
|
|
23
|
+
<ReactQueryDevtools initialIsOpen={false} buttonPosition='bottom-right'/>
|
|
24
|
+
</QueryClientProvider>);
|
|
24
25
|
}
|
|
@@ -4,6 +4,6 @@ import { useConfig } from '../../../config';
|
|
|
4
4
|
import Users from '../../../components/users/Users';
|
|
5
5
|
const UsersPage = () => {
|
|
6
6
|
const config = useConfig();
|
|
7
|
-
return
|
|
7
|
+
return <Users apiUrl={config.generalProperties.apiURL}/>;
|
|
8
8
|
};
|
|
9
9
|
export default UsersPage;
|
|
@@ -14,7 +14,11 @@ export default function RootLayout({ children, }) {
|
|
|
14
14
|
LOGOUT_URL: process.env.LOGOUT_URL || '',
|
|
15
15
|
ACCOUNT_SETTINGS_URL: process.env.ACCOUNT_SETTINGS_URL || '',
|
|
16
16
|
};
|
|
17
|
-
return (
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
return (<html lang='en'>
|
|
18
|
+
<body>
|
|
19
|
+
<ConfigProvider publicRuntimeEnv={publicRuntimeEnv}>
|
|
20
|
+
{children}
|
|
21
|
+
</ConfigProvider>
|
|
22
|
+
</body>
|
|
23
|
+
</html>);
|
|
20
24
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Autocomplete, Button, Dialog, DialogActions, DialogContent, DialogTitle, TextField, } from '@mui/material';
|
|
3
|
+
import { useLocale } from '@deix/rossini-core';
|
|
4
|
+
import { useEffect, useState } from 'react';
|
|
5
|
+
const translations = {
|
|
6
|
+
ok: {
|
|
7
|
+
en: 'Add',
|
|
8
|
+
it: 'Aggiungi',
|
|
9
|
+
},
|
|
10
|
+
cancel: {
|
|
11
|
+
en: 'Cancel',
|
|
12
|
+
it: 'Annulla',
|
|
13
|
+
},
|
|
14
|
+
search: {
|
|
15
|
+
en: 'Search...',
|
|
16
|
+
it: 'Cerca...',
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
const AddItemDialog = ({ title, options, open, onClose, onConfirm, }) => {
|
|
20
|
+
const locale = useLocale();
|
|
21
|
+
const [value, setValue] = useState(null);
|
|
22
|
+
// Reset the value when the dialog is closed
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (!open) {
|
|
25
|
+
setValue(null);
|
|
26
|
+
}
|
|
27
|
+
}, [open]);
|
|
28
|
+
return (<Dialog open={open} fullWidth maxWidth='sm' onClose={onClose}>
|
|
29
|
+
<DialogTitle>{title[locale]}</DialogTitle>
|
|
30
|
+
<DialogContent>
|
|
31
|
+
<Autocomplete
|
|
32
|
+
// multiple
|
|
33
|
+
options={options ?? []} getOptionLabel={(option) => option.label} getOptionKey={(option) => option.value} isOptionEqualToValue={(option, value) => option.value === value.value} renderInput={(params) => (<TextField {...params} label={translations.search[locale]} placeholder=''/>)} onChange={(event, newValue) => {
|
|
34
|
+
setValue(newValue);
|
|
35
|
+
}} value={value}/>
|
|
36
|
+
</DialogContent>
|
|
37
|
+
<DialogActions>
|
|
38
|
+
<Button size='small' variant='outlined' onClick={onClose}>
|
|
39
|
+
{translations.cancel[locale]}
|
|
40
|
+
</Button>
|
|
41
|
+
<Button variant='contained' onClick={() => {
|
|
42
|
+
onConfirm(value);
|
|
43
|
+
onClose();
|
|
44
|
+
}}>
|
|
45
|
+
{translations.ok[locale]}
|
|
46
|
+
</Button>
|
|
47
|
+
</DialogActions>
|
|
48
|
+
</Dialog>);
|
|
49
|
+
};
|
|
50
|
+
export default AddItemDialog;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography, } from '@mui/material';
|
|
3
|
+
import { useLocale } from '@deix/rossini-core';
|
|
4
|
+
const translations = {
|
|
5
|
+
title: {
|
|
6
|
+
en: 'Delete item?',
|
|
7
|
+
it: 'Cancellare elemento?',
|
|
8
|
+
},
|
|
9
|
+
message: {
|
|
10
|
+
en: 'This is a permanent action',
|
|
11
|
+
it: "Questa è un'azione permanente",
|
|
12
|
+
},
|
|
13
|
+
yes: {
|
|
14
|
+
en: 'Yes',
|
|
15
|
+
it: 'Si',
|
|
16
|
+
},
|
|
17
|
+
no: {
|
|
18
|
+
en: 'No',
|
|
19
|
+
it: 'No',
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
const DeleteConfirmationDialog = ({ open, onClose, onConfirm, }) => {
|
|
23
|
+
const locale = useLocale();
|
|
24
|
+
return (<Dialog open={open} fullWidth maxWidth='sm' onClose={onClose}>
|
|
25
|
+
<DialogTitle>{translations.title[locale]}</DialogTitle>
|
|
26
|
+
<DialogContent>
|
|
27
|
+
<Typography variant='caption'>
|
|
28
|
+
{translations.message[locale]}
|
|
29
|
+
</Typography>
|
|
30
|
+
</DialogContent>
|
|
31
|
+
<DialogActions>
|
|
32
|
+
<Button size='small' variant='outlined' onClick={onClose}>
|
|
33
|
+
{translations.no[locale]}
|
|
34
|
+
</Button>
|
|
35
|
+
<Button size='small' variant='contained' onClick={() => {
|
|
36
|
+
onConfirm();
|
|
37
|
+
onClose();
|
|
38
|
+
}}>
|
|
39
|
+
{translations.yes[locale]}
|
|
40
|
+
</Button>
|
|
41
|
+
</DialogActions>
|
|
42
|
+
</Dialog>);
|
|
43
|
+
};
|
|
44
|
+
export default DeleteConfirmationDialog;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import SearchIcon from '@mui/icons-material/Search';
|
|
3
|
+
import { IconButton, TextField, } from '@mui/material';
|
|
4
|
+
import { useState } from 'react';
|
|
5
|
+
const SearchField = ({ placeholder = 'Search...', onSearch, ...props }) => {
|
|
6
|
+
const [value, setValue] = useState('');
|
|
7
|
+
return (<>
|
|
8
|
+
<TextField size='small' placeholder={placeholder} value={value} onChange={(evt) => {
|
|
9
|
+
setValue(evt.target.value);
|
|
10
|
+
onSearch(evt.target.value);
|
|
11
|
+
}} {...props} InputProps={{
|
|
12
|
+
endAdornment: (<IconButton size='small' onClick={() => onSearch(value)}>
|
|
13
|
+
<SearchIcon />
|
|
14
|
+
</IconButton>),
|
|
15
|
+
}}/>
|
|
16
|
+
</>);
|
|
17
|
+
};
|
|
18
|
+
export default SearchField;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateGroupDialog.d.ts","sourceRoot":"","sources":["../../../src/components/groups/CreateGroupDialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAW1B,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,iBAAiB,sBAAuB,sBAAsB,
|
|
1
|
+
{"version":3,"file":"CreateGroupDialog.d.ts","sourceRoot":"","sources":["../../../src/components/groups/CreateGroupDialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAW1B,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,iBAAiB,sBAAuB,sBAAsB,sBAoBnE,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useLocale } from '@deix/rossini-core';
|
|
3
3
|
import { Dialog, DialogContent, DialogTitle } from '@mui/material';
|
|
4
4
|
import { useQueryClient } from '@tanstack/react-query';
|
|
5
|
-
import { useConfig } from '../../config';
|
|
6
5
|
import groupsTranslations from '../../lang/groups';
|
|
7
6
|
import { useAddGroup } from '../../utils/hooks/groups';
|
|
8
7
|
import GroupForm from './GroupForm';
|
|
8
|
+
import { useAPIClient } from '../../utils/hooks/useAPIClient';
|
|
9
9
|
const CreateGroupDialog = ({ open, onClose }) => {
|
|
10
10
|
const locale = useLocale();
|
|
11
|
-
const
|
|
12
|
-
const apiClient = useAPI(config.generalProperties.apiURL);
|
|
11
|
+
const apiClient = useAPIClient();
|
|
13
12
|
const queryClient = useQueryClient();
|
|
14
13
|
const { mutate: addGroup } = useAddGroup(queryClient, apiClient);
|
|
15
14
|
const handleSave = (group) => {
|
|
16
15
|
addGroup(group);
|
|
17
16
|
onClose();
|
|
18
17
|
};
|
|
19
|
-
return (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
return (<Dialog open={open} fullWidth maxWidth='sm' onClose={onClose}>
|
|
19
|
+
<DialogTitle>{groupsTranslations.create[locale]}</DialogTitle>
|
|
20
|
+
<DialogContent>
|
|
21
|
+
<GroupForm mode='create' onSave={handleSave} onCancel={onClose}/>
|
|
22
|
+
</DialogContent>
|
|
23
|
+
</Dialog>);
|
|
23
24
|
};
|
|
24
25
|
export default CreateGroupDialog;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GroupDetails.d.ts","sourceRoot":"","sources":["../../../src/components/groups/GroupDetails.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"GroupDetails.d.ts","sourceRoot":"","sources":["../../../src/components/groups/GroupDetails.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAK3C,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,KAAK,CAAC;CACd;AAED,QAAA,MAAM,YAAY,cAAe,iBAAiB,sBAmBjD,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { useAPI } from '@deix/rossini-core';
|
|
3
2
|
import { useQueryClient } from '@tanstack/react-query';
|
|
4
|
-
import { useConfig } from '../../config';
|
|
5
3
|
import { useUpdateGroup } from '../../utils/hooks/groups';
|
|
6
4
|
import GroupForm from './GroupForm';
|
|
5
|
+
import { useAPIClient } from '../../utils/hooks/useAPIClient';
|
|
7
6
|
const GroupDetails = ({ group }) => {
|
|
8
|
-
const
|
|
9
|
-
const apiClient = useAPI(config.generalProperties.apiURL);
|
|
7
|
+
const apiClient = useAPIClient();
|
|
10
8
|
const queryClient = useQueryClient();
|
|
11
9
|
const { mutate: updateGroup } = useUpdateGroup(queryClient, apiClient);
|
|
12
10
|
const handleUpdate = (group) => {
|
|
13
11
|
updateGroup(group);
|
|
14
12
|
};
|
|
15
|
-
return (
|
|
16
|
-
|
|
13
|
+
return (<>
|
|
14
|
+
<GroupForm mode='modify' group={group} onSave={handleUpdate} onCancel={() => { }}/>
|
|
15
|
+
</>);
|
|
17
16
|
};
|
|
18
17
|
export default GroupDetails;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useLocale } from '@deix/rossini-core';
|
|
3
|
+
import { Button, Grid, TextField } from '@mui/material';
|
|
4
|
+
import { Controller, useForm } from 'react-hook-form';
|
|
5
|
+
import { useEffect } from 'react';
|
|
6
|
+
import groupsTranslations from '../../lang/groups';
|
|
7
|
+
const GroupForm = ({ group, onCancel, onSave, mode }) => {
|
|
8
|
+
const locale = useLocale();
|
|
9
|
+
const { control, handleSubmit, setValue } = useForm({
|
|
10
|
+
defaultValues: {
|
|
11
|
+
id: group?.id,
|
|
12
|
+
name: group?.name,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
if (group) {
|
|
17
|
+
setValue('id', group?.id);
|
|
18
|
+
setValue('name', group?.name);
|
|
19
|
+
}
|
|
20
|
+
}, [group, setValue]);
|
|
21
|
+
const onSubmit = (data) => {
|
|
22
|
+
onSave(data);
|
|
23
|
+
};
|
|
24
|
+
return (<form onSubmit={(event) => void handleSubmit(onSubmit)(event)}>
|
|
25
|
+
<Grid container spacing={2} sx={{ mt: 2, maxWidth: 'sm' }} justifyContent='stretch'>
|
|
26
|
+
<Grid item xs={12}>
|
|
27
|
+
<Controller name='name' control={control} render={({ field }) => (<TextField size='small' fullWidth label={groupsTranslations.name[locale]} sx={{ flexShrink: 0 }} {...field}/>)}/>
|
|
28
|
+
</Grid>
|
|
29
|
+
<Grid item sx={{
|
|
30
|
+
mt: 2,
|
|
31
|
+
display: 'flex',
|
|
32
|
+
justifyContent: 'flex-end',
|
|
33
|
+
gap: 2,
|
|
34
|
+
width: '100%',
|
|
35
|
+
}}>
|
|
36
|
+
{mode === 'create' && (<Button variant='outlined' onClick={onCancel}>
|
|
37
|
+
{groupsTranslations.cancel[locale]}
|
|
38
|
+
</Button>)}
|
|
39
|
+
<Button variant='contained' type='submit'>
|
|
40
|
+
{groupsTranslations.save[locale]}
|
|
41
|
+
</Button>
|
|
42
|
+
</Grid>
|
|
43
|
+
</Grid>
|
|
44
|
+
</form>);
|
|
45
|
+
};
|
|
46
|
+
export default GroupForm;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GroupTabs.d.ts","sourceRoot":"","sources":["../../../src/components/groups/GroupTabs.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,OAAO,EAAE,iBAAiB,EAAa,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAK3C,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,iBAAiB,CAAC;IACzB,SAAS,EAAE,KAAK,CAAC,iBAAiB,CAAC;QAAE,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,KAAK,CAAC;IACb,cAAc,CAAC,EAAE,QAAQ,EAAE,CAAC;CAC7B;AAED,QAAA,MAAM,SAAS,8BAAoC,cAAc,
|
|
1
|
+
{"version":3,"file":"GroupTabs.d.ts","sourceRoot":"","sources":["../../../src/components/groups/GroupTabs.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,OAAO,EAAE,iBAAiB,EAAa,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAK3C,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,iBAAiB,CAAC;IACzB,SAAS,EAAE,KAAK,CAAC,iBAAiB,CAAC;QAAE,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,KAAK,CAAC;IACb,cAAc,CAAC,EAAE,QAAQ,EAAE,CAAC;CAC7B;AAED,QAAA,MAAM,SAAS,8BAAoC,cAAc,sBA4ChE,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
import { Box, Tab, Tabs } from '@mui/material';
|
|
4
|
+
import { useLocale } from '@deix/rossini-core';
|
|
5
|
+
import GroupDetails from './GroupDetails';
|
|
6
|
+
import groupsTranslations from '../../lang/groups';
|
|
7
|
+
import GroupUsers from './GroupUsers';
|
|
8
|
+
const GroupTabs = ({ group, additionalTabs = [] }) => {
|
|
9
|
+
const locale = useLocale();
|
|
10
|
+
const [selectedTab, setSelectedTab] = useState('DETAILS');
|
|
11
|
+
return (<Box sx={{
|
|
12
|
+
flexGrow: 1,
|
|
13
|
+
maxWidth: '100%',
|
|
14
|
+
overflowX: 'hidden',
|
|
15
|
+
alignSelf: 'stretch',
|
|
16
|
+
}}>
|
|
17
|
+
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
|
18
|
+
<Tabs value={selectedTab} onChange={(_evt, newValue) => {
|
|
19
|
+
setSelectedTab(newValue);
|
|
20
|
+
}} aria-label='basic tabs example'>
|
|
21
|
+
<Tab label={groupsTranslations.details[locale]} value='DETAILS'/>
|
|
22
|
+
<Tab label={groupsTranslations.users[locale]} value='USERS'/>
|
|
23
|
+
{additionalTabs.map((tab, index) => (<Tab key={`tab${index}`} label={tab.title[locale]} value={`ADDITIONAL_TAB_${index}`}/>))}
|
|
24
|
+
</Tabs>
|
|
25
|
+
</Box>
|
|
26
|
+
<Box sx={{ p: 1 }}>
|
|
27
|
+
{selectedTab === 'DETAILS' && <GroupDetails group={group}/>}
|
|
28
|
+
{selectedTab === 'USERS' && <GroupUsers group={group}/>}
|
|
29
|
+
{additionalTabs.map((tab, index) => selectedTab === `ADDITIONAL_TAB_${index}` && (<tab.component key={`tab${index}`} group={group}/>))}
|
|
30
|
+
</Box>
|
|
31
|
+
</Box>);
|
|
32
|
+
};
|
|
33
|
+
export default GroupTabs;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GroupUsers.d.ts","sourceRoot":"","sources":["../../../src/components/groups/GroupUsers.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAe1B,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"GroupUsers.d.ts","sourceRoot":"","sources":["../../../src/components/groups/GroupUsers.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAe1B,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AA8B3C,UAAU,eAAe;IACvB,KAAK,EAAE,KAAK,CAAC;CACd;AAED,QAAA,MAAM,UAAU,cAAe,eAAe,sBA8F7C,CAAC;AAEF,eAAe,UAAU,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Box, Button, IconButton, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, } from '@mui/material';
|
|
3
|
+
import AddIcon from '@mui/icons-material/Add';
|
|
4
|
+
import DeleteIcon from '@mui/icons-material/Delete';
|
|
5
|
+
import { isStringTranslation, useLocale } from '@deix/rossini-core';
|
|
6
|
+
import { useAddUserToGroup, useRemoveUserFromGroup, useUsers, } from '../../utils/hooks/users';
|
|
7
|
+
import { useState } from 'react';
|
|
8
|
+
import DeleteConfirmationDialog from '../DeleteConfirmationDialog';
|
|
9
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
10
|
+
import AddItemDialog from '../AddItemDialog';
|
|
11
|
+
import { useGroupUsers } from '../../utils/hooks/groups';
|
|
12
|
+
import groupsTranslations from '../../lang/groups';
|
|
13
|
+
import { useAPIClient } from '../../utils/hooks/useAPIClient';
|
|
14
|
+
const groupUsersTableColumns = [
|
|
15
|
+
{
|
|
16
|
+
id: 'username',
|
|
17
|
+
label: { en: 'Username', it: 'Username' },
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: 'firstName',
|
|
21
|
+
label: { en: 'First name', it: 'Nome' },
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: 'lastName',
|
|
25
|
+
label: { en: 'Last name', it: 'Cognome' },
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
const GroupUsers = ({ group }) => {
|
|
29
|
+
const locale = useLocale();
|
|
30
|
+
const apiClient = useAPIClient();
|
|
31
|
+
const queryClient = useQueryClient();
|
|
32
|
+
const { data: users } = useUsers(apiClient);
|
|
33
|
+
const { data: groupUsers } = useGroupUsers(group?.id, apiClient);
|
|
34
|
+
const { mutate: addUserToGroup } = useAddUserToGroup(queryClient, apiClient);
|
|
35
|
+
const { mutate: removeUserFromGroup } = useRemoveUserFromGroup(queryClient, apiClient);
|
|
36
|
+
const [openAddUserDialog, setOpenAddUserDialog] = useState(false);
|
|
37
|
+
const [openConfirmationDialog, setOpenConfirmationDialog] = useState(false);
|
|
38
|
+
const [deleteId, setDeleteId] = useState();
|
|
39
|
+
return (<>
|
|
40
|
+
{groupUsers && groupUsers.length > 0 && (<Box maxWidth='md'>
|
|
41
|
+
<TableContainer>
|
|
42
|
+
<Table size='small'>
|
|
43
|
+
<TableHead>
|
|
44
|
+
<TableRow>
|
|
45
|
+
{groupUsersTableColumns.map((col) => (<TableCell key={col.id} align={col.align || 'inherit'}>
|
|
46
|
+
{isStringTranslation(col.label)
|
|
47
|
+
? col.label[locale]
|
|
48
|
+
: col.label}
|
|
49
|
+
</TableCell>))}
|
|
50
|
+
<TableCell padding='none'>{''}</TableCell>
|
|
51
|
+
</TableRow>
|
|
52
|
+
</TableHead>
|
|
53
|
+
<TableBody>
|
|
54
|
+
{groupUsers?.map((user, rowIdx) => (<TableRow key={rowIdx}>
|
|
55
|
+
<TableCell>{user.username}</TableCell>
|
|
56
|
+
<TableCell>{user.firstName}</TableCell>
|
|
57
|
+
<TableCell>{user.lastName}</TableCell>
|
|
58
|
+
<TableCell padding='none' align='right'>
|
|
59
|
+
<IconButton size='small' onClick={(evt) => {
|
|
60
|
+
evt.stopPropagation();
|
|
61
|
+
setOpenConfirmationDialog(true);
|
|
62
|
+
setDeleteId(user.id);
|
|
63
|
+
}}>
|
|
64
|
+
<DeleteIcon />
|
|
65
|
+
</IconButton>
|
|
66
|
+
</TableCell>
|
|
67
|
+
</TableRow>))}
|
|
68
|
+
</TableBody>
|
|
69
|
+
</Table>
|
|
70
|
+
</TableContainer>
|
|
71
|
+
</Box>)}
|
|
72
|
+
<Button variant='outlined' startIcon={<AddIcon />} onClick={() => setOpenAddUserDialog(true)} sx={{ marginTop: 2 }}>
|
|
73
|
+
{groupsTranslations.addUser[locale]}
|
|
74
|
+
</Button>
|
|
75
|
+
<AddItemDialog open={openAddUserDialog} onClose={() => setOpenAddUserDialog(false)} onConfirm={(value) => {
|
|
76
|
+
if (value) {
|
|
77
|
+
addUserToGroup({ userId: value?.value, groupId: group.id });
|
|
78
|
+
}
|
|
79
|
+
}} title={groupsTranslations.addUser} options={users?.map((user) => ({
|
|
80
|
+
value: user.id,
|
|
81
|
+
label: user.username || '',
|
|
82
|
+
}))}/>
|
|
83
|
+
<DeleteConfirmationDialog open={openConfirmationDialog} onClose={() => setOpenConfirmationDialog(false)} onConfirm={() => deleteId
|
|
84
|
+
? removeUserFromGroup({ userId: deleteId, groupId: group.id })
|
|
85
|
+
: {}}/>
|
|
86
|
+
</>);
|
|
87
|
+
};
|
|
88
|
+
export default GroupUsers;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Groups.d.ts","sourceRoot":"","sources":["../../../src/components/groups/Groups.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAanD,OAAkB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"Groups.d.ts","sourceRoot":"","sources":["../../../src/components/groups/Groups.tsx"],"names":[],"mappings":"AAEA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAanD,OAAkB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAIlD,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,QAAQ,EAAE,CAAC;CAC7B;AAED,QAAA,MAAM,MAAM,+BAAqC,WAAW,sBAuH3D,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -12,6 +12,7 @@ import groupsTranslations from '../../lang/groups';
|
|
|
12
12
|
import { useDeleteGroup, useGroups } from '../../utils/hooks/groups';
|
|
13
13
|
import GroupTabs from './GroupTabs';
|
|
14
14
|
import { useQueryClient } from '@tanstack/react-query';
|
|
15
|
+
import { APIClientProvider } from '../../utils/hooks/useAPIClient';
|
|
15
16
|
const Groups = ({ apiUrl, additionalTabs = [] }) => {
|
|
16
17
|
const locale = useLocale();
|
|
17
18
|
const apiClient = useAPI(apiUrl);
|
|
@@ -34,45 +35,59 @@ const Groups = ({ apiUrl, additionalTabs = [] }) => {
|
|
|
34
35
|
deleteGroup(id);
|
|
35
36
|
setSelectedGroup(undefined);
|
|
36
37
|
};
|
|
37
|
-
return (
|
|
38
|
+
return (<APIClientProvider baseURL={apiUrl}>
|
|
39
|
+
<Box sx={{
|
|
38
40
|
flexGrow: 1,
|
|
39
41
|
maxWidth: '100%',
|
|
40
42
|
overflowX: 'hidden',
|
|
41
43
|
paddingTop: 3,
|
|
42
44
|
paddingLeft: 3,
|
|
43
45
|
paddingRight: 3,
|
|
44
|
-
}
|
|
45
|
-
!selectedGroup && (
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
46
|
+
}}>
|
|
47
|
+
{!selectedGroup && (<>
|
|
48
|
+
<Grid container spacing={2} sx={{ marginBottom: 2 }}>
|
|
49
|
+
<Grid item>
|
|
50
|
+
<SearchField placeholder={groupsTranslations.search[locale]} onSearch={(value) => setSearchString(value)}/>
|
|
51
|
+
</Grid>
|
|
52
|
+
<Grid item>
|
|
53
|
+
<Button variant='contained' startIcon={<GroupAddIcon />} onClick={() => {
|
|
54
|
+
setOpenGroupDialog(true);
|
|
55
|
+
setSelectedGroup(undefined);
|
|
56
|
+
}}>
|
|
57
|
+
{groupsTranslations.new[locale]}
|
|
58
|
+
</Button>
|
|
59
|
+
</Grid>
|
|
60
|
+
</Grid>
|
|
61
|
+
<GroupsTable groups={filteredGroups} selectedGroup={selectedGroup} setSelectedGroup={(group) => {
|
|
62
|
+
setSelectedGroup(group);
|
|
63
|
+
}} onDelete={handleDelete}/>
|
|
64
|
+
</>)}
|
|
65
|
+
{selectedGroup && (<Box sx={{
|
|
58
66
|
display: 'flex',
|
|
59
67
|
flexDirection: 'column',
|
|
60
68
|
alignItems: 'flex-start',
|
|
61
69
|
width: '100%',
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
70
|
+
}}>
|
|
71
|
+
<Box sx={{
|
|
72
|
+
display: 'flex',
|
|
73
|
+
flexDirection: 'row',
|
|
74
|
+
alignItems: 'center',
|
|
75
|
+
}}>
|
|
76
|
+
<IconButton aria-label='delete' color='primary' onClick={() => setSelectedGroup(undefined)} sx={{ mr: 2 }}>
|
|
77
|
+
<ArrowBackIcon />
|
|
78
|
+
</IconButton>
|
|
79
|
+
<Link underline='none' href='#' onClick={() => setSelectedGroup(undefined)}>
|
|
80
|
+
{groupsTranslations.title[locale]}
|
|
81
|
+
</Link>
|
|
82
|
+
<KeyboardArrowRightIcon />
|
|
83
|
+
{selectedGroup.name}
|
|
84
|
+
</Box>
|
|
85
|
+
<GroupTabs group={selectedGroup} additionalTabs={additionalTabs}/>
|
|
86
|
+
</Box>)}
|
|
87
|
+
<CreateGroupDialog open={openGroupDialog} onClose={() => {
|
|
88
|
+
setOpenGroupDialog(false);
|
|
89
|
+
}}/>
|
|
90
|
+
</Box>
|
|
91
|
+
</APIClientProvider>);
|
|
77
92
|
};
|
|
78
93
|
export default Groups;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { isStringTranslation, useLocale } from '@deix/rossini-core';
|
|
3
|
+
import DeleteIcon from '@mui/icons-material/Delete';
|
|
4
|
+
import { IconButton, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, useTheme, } from '@mui/material';
|
|
5
|
+
import { useState } from 'react';
|
|
6
|
+
import DeleteConfirmationDialog from '../DeleteConfirmationDialog';
|
|
7
|
+
const groupsTableColumns = [
|
|
8
|
+
{
|
|
9
|
+
id: 'name',
|
|
10
|
+
label: { en: 'Name', it: 'Nome' },
|
|
11
|
+
},
|
|
12
|
+
];
|
|
13
|
+
const GroupsTable = ({ groups = [], selectedGroup, setSelectedGroup, onDelete, }) => {
|
|
14
|
+
const locale = useLocale();
|
|
15
|
+
const muiTheme = useTheme();
|
|
16
|
+
const [openConfirmationDialog, setOpenConfirmationDialog] = useState(false);
|
|
17
|
+
const [deleteId, setDeleteId] = useState();
|
|
18
|
+
return (<>
|
|
19
|
+
<TableContainer>
|
|
20
|
+
<Table size='small'>
|
|
21
|
+
<TableHead>
|
|
22
|
+
<TableRow>
|
|
23
|
+
{groupsTableColumns.map((col) => (<TableCell key={col.id} align={col.align || 'inherit'}>
|
|
24
|
+
{isStringTranslation(col.label)
|
|
25
|
+
? col.label[locale]
|
|
26
|
+
: col.label}
|
|
27
|
+
</TableCell>))}
|
|
28
|
+
<TableCell padding='none'>{''}</TableCell>
|
|
29
|
+
</TableRow>
|
|
30
|
+
</TableHead>
|
|
31
|
+
<TableBody>
|
|
32
|
+
{groups.map((group, rowIdx) => (<TableRow key={rowIdx} onClick={() => setSelectedGroup(group)} sx={{
|
|
33
|
+
cursor: 'pointer',
|
|
34
|
+
background: selectedGroup && group.id === selectedGroup.id
|
|
35
|
+
? muiTheme.palette.primary.light
|
|
36
|
+
: undefined,
|
|
37
|
+
}}>
|
|
38
|
+
<TableCell>{group.name}</TableCell>
|
|
39
|
+
<TableCell padding='none' align='right'>
|
|
40
|
+
<IconButton size='small' onClick={(evt) => {
|
|
41
|
+
evt.stopPropagation();
|
|
42
|
+
setOpenConfirmationDialog(true);
|
|
43
|
+
setDeleteId(group.id);
|
|
44
|
+
}}>
|
|
45
|
+
<DeleteIcon />
|
|
46
|
+
</IconButton>
|
|
47
|
+
</TableCell>
|
|
48
|
+
</TableRow>))}
|
|
49
|
+
</TableBody>
|
|
50
|
+
</Table>
|
|
51
|
+
</TableContainer>
|
|
52
|
+
<DeleteConfirmationDialog open={openConfirmationDialog} onClose={() => setOpenConfirmationDialog(false)} onConfirm={() => (deleteId ? onDelete(deleteId) : {})}/>
|
|
53
|
+
</>);
|
|
54
|
+
};
|
|
55
|
+
export default GroupsTable;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateUserDialog.d.ts","sourceRoot":"","sources":["../../../src/components/users/CreateUserDialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAS1B,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,gBAAgB,sBAAuB,qBAAqB,
|
|
1
|
+
{"version":3,"file":"CreateUserDialog.d.ts","sourceRoot":"","sources":["../../../src/components/users/CreateUserDialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAS1B,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,gBAAgB,sBAAuB,qBAAqB,sBAoBjE,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useLocale } from '@deix/rossini-core';
|
|
3
3
|
import { Dialog, DialogContent, DialogTitle } from '@mui/material';
|
|
4
4
|
import { useQueryClient } from '@tanstack/react-query';
|
|
5
|
-
import { useConfig } from '../../config';
|
|
6
5
|
import { useAddUser } from '../../utils/hooks/users';
|
|
7
6
|
import UserForm from './UserForm';
|
|
8
7
|
import usersTranslations from '../../lang/users';
|
|
8
|
+
import { useAPIClient } from '../../utils/hooks/useAPIClient';
|
|
9
9
|
const CreateUserDialog = ({ open, onClose }) => {
|
|
10
10
|
const locale = useLocale();
|
|
11
|
-
const
|
|
12
|
-
const apiClient = useAPI(config.generalProperties.apiURL);
|
|
11
|
+
const apiClient = useAPIClient();
|
|
13
12
|
const queryClient = useQueryClient();
|
|
14
13
|
const { mutate: addUser } = useAddUser(queryClient, apiClient);
|
|
15
14
|
const handleSave = (userFormData) => {
|
|
16
15
|
addUser(userFormData);
|
|
17
16
|
onClose();
|
|
18
17
|
};
|
|
19
|
-
return (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
return (<Dialog open={open} fullWidth maxWidth='sm' onClose={onClose}>
|
|
19
|
+
<DialogTitle>{usersTranslations.create[locale]}</DialogTitle>
|
|
20
|
+
<DialogContent>
|
|
21
|
+
<UserForm mode='create' onSave={handleSave} onCancel={onClose}/>
|
|
22
|
+
</DialogContent>
|
|
23
|
+
</Dialog>);
|
|
23
24
|
};
|
|
24
25
|
export default CreateUserDialog;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserCredentials.d.ts","sourceRoot":"","sources":["../../../src/components/users/UserCredentials.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAOzC,UAAU,oBAAoB;IAC5B,IAAI,EAAE,IAAI,CAAC;CACZ;AAED,QAAA,MAAM,eAAe,aAAc,oBAAoB,
|
|
1
|
+
{"version":3,"file":"UserCredentials.d.ts","sourceRoot":"","sources":["../../../src/components/users/UserCredentials.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAOzC,UAAU,oBAAoB;IAC5B,IAAI,EAAE,IAAI,CAAC;CACZ;AAED,QAAA,MAAM,eAAe,aAAc,oBAAoB,sBAkBtD,CAAC;AAEF,eAAe,eAAe,CAAC"}
|