@fluxo-dev/shell 0.0.8
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/.babelrc +12 -0
- package/.eslintrc.json +18 -0
- package/README.md +7 -0
- package/jest.config.ts +11 -0
- package/package.json +4 -0
- package/project.json +43 -0
- package/src/index.ts +1 -0
- package/src/lib/app.module.css +1 -0
- package/src/lib/app.spec.tsx +17 -0
- package/src/lib/app.tsx +374 -0
- package/src/lib/components/error-page/404.tsx +16 -0
- package/src/lib/components/routes/main-routes.tsx +26 -0
- package/src/lib/layouts/blank/blank-layout.tsx +10 -0
- package/src/lib/layouts/main/app-bar.tsx +192 -0
- package/src/lib/layouts/main/app-layout.tsx +52 -0
- package/src/lib/layouts/main/content.tsx +10 -0
- package/src/lib/layouts/main/footer-bar.tsx +76 -0
- package/src/lib/layouts/main/navbar-item.module.css +49 -0
- package/src/lib/layouts/main/navbar-item.tsx +129 -0
- package/src/lib/layouts/main/navbar.tsx +38 -0
- package/src/lib/layouts/main/search-bar.tsx +44 -0
- package/src/lib/layouts/main/shell-spotlight.tsx +58 -0
- package/src/lib/models/app-jit.ts +6 -0
- package/src/lib/pages/general/fluxo-plugin-loader.tsx +22 -0
- package/src/lib/pages/login/account-confirmation.tsx +86 -0
- package/src/lib/pages/login/change-password.tsx +58 -0
- package/src/lib/pages/login/forgot-password.tsx +53 -0
- package/src/lib/pages/login/login-page.tsx +70 -0
- package/src/lib/pages/login/reset-password.tsx +91 -0
- package/src/lib/pages/settings/apps/add-jit-app.tsx +79 -0
- package/src/lib/pages/settings/apps/app-item.tsx +157 -0
- package/src/lib/pages/settings/apps/app-jit-item.tsx +105 -0
- package/src/lib/pages/settings/apps/apps-list.tsx +171 -0
- package/src/lib/pages/settings/apps/embedded-module-item.tsx +66 -0
- package/src/lib/pages/settings/apps/install-or-upgrade-app.tsx +105 -0
- package/src/lib/pages/settings/menu-designer/custom-node.module.css +34 -0
- package/src/lib/pages/settings/menu-designer/custom-node.tsx +160 -0
- package/src/lib/pages/settings/menu-designer/menu-create-form.tsx +109 -0
- package/src/lib/pages/settings/menu-designer/menu-designer.module.css +19 -0
- package/src/lib/pages/settings/menu-designer/menu-designer.tsx +463 -0
- package/src/lib/pages/settings/menu-designer/menu-item-edit.tsx +115 -0
- package/src/lib/pages/settings/menu-designer/placeholder.module.css +8 -0
- package/src/lib/pages/settings/menu-designer/placeholder.tsx +13 -0
- package/src/lib/pages/settings/security/components/domani-role/domain-role-form.tsx +67 -0
- package/src/lib/pages/settings/security/components/domani-role/domain-role-grid.tsx +139 -0
- package/src/lib/pages/settings/security/components/permission/create-custom-permission-form.tsx +64 -0
- package/src/lib/pages/settings/security/components/permission/create-scope-form.tsx +158 -0
- package/src/lib/pages/settings/security/components/permission/permission-grid.tsx +304 -0
- package/src/lib/pages/settings/security/components/permission/permission-navigator.tsx +320 -0
- package/src/lib/pages/settings/security/components/permission/update-permission.tsx +54 -0
- package/src/lib/pages/settings/security/components/route-rule/route-rule-create-form.tsx +59 -0
- package/src/lib/pages/settings/security/components/route-rule/route-rule-grid.tsx +229 -0
- package/src/lib/pages/settings/security/components/user/user-form.tsx +123 -0
- package/src/lib/pages/settings/security/components/user/users-grid.tsx +127 -0
- package/src/lib/pages/settings/settings.tsx +298 -0
- package/src/lib/pages/settings/token/token-row.tsx +69 -0
- package/src/lib/pages/settings/token/tokens.tsx +73 -0
- package/src/lib/pages/settings/ui/ui.tsx +149 -0
- package/src/lib/services/app-jit-manager.ts +92 -0
- package/src/lib/services/app-menu.service.ts +35 -0
- package/src/lib/utils/icon-factory.tsx +25 -0
- package/src/lib/utils/security/only-not-logged-route.tsx +17 -0
- package/src/lib/utils/security/protected-route.tsx +47 -0
- package/tsconfig.json +20 -0
- package/tsconfig.lib.json +24 -0
- package/tsconfig.spec.json +20 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import React, {useState} from "react";
|
|
2
|
+
import {FluxoClientSys, RouteRule} from "@fluxo-dev/api-client-base";
|
|
3
|
+
import {showNotification} from "@mantine/notifications";
|
|
4
|
+
import {Alert, Button, Divider, Group, Stack, TextInput} from "@mantine/core";
|
|
5
|
+
import {IconInfoCircle} from "@tabler/icons-react";
|
|
6
|
+
|
|
7
|
+
export interface RouteRuleCreateFormProps {
|
|
8
|
+
scope: string;
|
|
9
|
+
packageName: string;
|
|
10
|
+
onCanceled: () => void;
|
|
11
|
+
onCreated: () => void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function RouteRuleCreateForm(props: RouteRuleCreateFormProps) {
|
|
15
|
+
const [identifier, setIdentifier] = useState<string>('');
|
|
16
|
+
|
|
17
|
+
const createRouteRule = () => {
|
|
18
|
+
if(!identifier) return;
|
|
19
|
+
|
|
20
|
+
const command: RouteRule = {
|
|
21
|
+
scope: props.scope,
|
|
22
|
+
packageName: props.packageName,
|
|
23
|
+
route: identifier,
|
|
24
|
+
}
|
|
25
|
+
FluxoClientSys.Instance.security.routeRule.create(command)
|
|
26
|
+
.then(() => {
|
|
27
|
+
showNotification({
|
|
28
|
+
title: 'Regola creata',
|
|
29
|
+
message: `La regola ${props.scope}.${props.packageName}.${identifier} è stato creata con successo.`,
|
|
30
|
+
color: 'green'
|
|
31
|
+
})
|
|
32
|
+
props.onCreated();
|
|
33
|
+
})
|
|
34
|
+
.catch(() => {
|
|
35
|
+
showNotification({
|
|
36
|
+
title: 'Errore',
|
|
37
|
+
message: `Si è verificato un errore durante la creazione della regola ${props.scope}.${props.packageName}.${identifier}.`,
|
|
38
|
+
color: 'red'
|
|
39
|
+
})
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<Stack>
|
|
45
|
+
<TextInput label={"Identificatore"} placeholder={'Es: create'} required onChange={(v) => setIdentifier(v.target.value)} />
|
|
46
|
+
|
|
47
|
+
<p>Rotta: {`${props.scope}/${props.packageName}/${identifier}`}</p>
|
|
48
|
+
<Divider />
|
|
49
|
+
<Group justify={'right'}>
|
|
50
|
+
<Button variant={'subtle'} onClick={props.onCanceled}>Annulla</Button>
|
|
51
|
+
<Button
|
|
52
|
+
disabled={!identifier}
|
|
53
|
+
onClick={createRouteRule}>
|
|
54
|
+
Salva
|
|
55
|
+
</Button>
|
|
56
|
+
</Group>
|
|
57
|
+
</Stack>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import {ActionIcon, Button, Center, Divider, Grid, Group, Modal, Select, Stack, Table, Text} from "@mantine/core";
|
|
2
|
+
import {DataCard} from "@fluxo-dev/ui-components";
|
|
3
|
+
import React, {useEffect, useState} from "react";
|
|
4
|
+
import {FluxoClientSys, PermissionScope, RouteRule} from "@fluxo-dev/api-client-base";
|
|
5
|
+
import {IconCloudOff, IconLock, IconPlus, IconTrash} from "@tabler/icons-react";
|
|
6
|
+
import {PermissionNavigator} from "../permission/permission-navigator";
|
|
7
|
+
import {RouteRuleCreateForm} from "./route-rule-create-form";
|
|
8
|
+
import {showNotification} from "@mantine/notifications";
|
|
9
|
+
|
|
10
|
+
export function RouteRuleGrid() {
|
|
11
|
+
|
|
12
|
+
const [permissionScopes, setPermissionScopes] = useState<PermissionScope[]>([]);
|
|
13
|
+
const [permissionScopesLoaded, setPermissionScopesLoaded] = useState<boolean>(false);
|
|
14
|
+
|
|
15
|
+
const [currentScope, setCurrentScope] = useState<string | null>(null);
|
|
16
|
+
const [currentPackageName, setCurrentPackageName] = useState<string | null>(null);
|
|
17
|
+
const [routeRules, setRouteRules] = useState<RouteRule[]>([]);
|
|
18
|
+
const [permissionLoading, setPermissionLoading] = useState<boolean>(false);
|
|
19
|
+
|
|
20
|
+
const [currentRouteRule, setCurrentRouteRule] = useState<RouteRule | undefined>();
|
|
21
|
+
const [managePermissionModalOpened, setManagePermissionModalOpened] = useState<boolean>(false);
|
|
22
|
+
|
|
23
|
+
const [createRouteRuleModalOpened, setCreateRouteRuleModalOpened] = useState<boolean>(false);
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
loadPermissionScopes();
|
|
27
|
+
}, [])
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if(currentScope && currentPackageName)
|
|
31
|
+
getRouteRulesForScope();
|
|
32
|
+
else
|
|
33
|
+
setRouteRules([]);
|
|
34
|
+
}, [currentScope, currentPackageName]);
|
|
35
|
+
|
|
36
|
+
const getRouteRulesForScope = () => {
|
|
37
|
+
|
|
38
|
+
if(!currentScope || !currentPackageName) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
setPermissionLoading(true);
|
|
43
|
+
|
|
44
|
+
FluxoClientSys.Instance.security.routeRule.getRouteRulesForScope(currentScope, currentPackageName)
|
|
45
|
+
.then((res) => {
|
|
46
|
+
setRouteRules(res);
|
|
47
|
+
setPermissionLoading(false);
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const loadPermissionScopes = () => {
|
|
52
|
+
FluxoClientSys.Instance.security.permission.getPermissionScopes()
|
|
53
|
+
.then((res) => {
|
|
54
|
+
setPermissionScopes(res);
|
|
55
|
+
setPermissionScopesLoaded(true);
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const deleteRouteRule = (routeRule: RouteRule) => {
|
|
60
|
+
FluxoClientSys.Instance.security.routeRule.delete(routeRule.id!.toString())
|
|
61
|
+
.then(() => {
|
|
62
|
+
showNotification({
|
|
63
|
+
title: 'Regola eliminata',
|
|
64
|
+
message: `La regola ${routeRule.scope}.${routeRule.packageName}.${routeRule.route} è stato eliminata con successo.`,
|
|
65
|
+
color: 'green'
|
|
66
|
+
})
|
|
67
|
+
getRouteRulesForScope();
|
|
68
|
+
})
|
|
69
|
+
.catch(() => {
|
|
70
|
+
showNotification({
|
|
71
|
+
title: 'Errore',
|
|
72
|
+
message: `Si è verificato un errore durante l'eliminazione della regola ${routeRule.scope}.${routeRule.packageName}.${routeRule.route}.`,
|
|
73
|
+
color: 'red'
|
|
74
|
+
})
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const getScopes = () => {
|
|
79
|
+
if(permissionScopes === undefined) return [];
|
|
80
|
+
return [...new Set(permissionScopes.map(a => a.scope))];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const getPackageNames = (scope: string | null) => {
|
|
84
|
+
if(permissionScopes === undefined || !scope) return [];
|
|
85
|
+
return [...new Set(permissionScopes.filter(a => a.scope === scope).map(a => a.packageName))];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<DataCard title={'Regole sulle rotte'}>
|
|
90
|
+
<Stack>
|
|
91
|
+
<Grid>
|
|
92
|
+
<Grid.Col span={6}>
|
|
93
|
+
<Select
|
|
94
|
+
data={getScopes()}
|
|
95
|
+
searchable
|
|
96
|
+
placeholder={'Seleziona uno scope'}
|
|
97
|
+
value={currentScope}
|
|
98
|
+
label={'Scope'}
|
|
99
|
+
onChange={(v) => {
|
|
100
|
+
setCurrentScope(v)
|
|
101
|
+
setCurrentPackageName(null);
|
|
102
|
+
}} />
|
|
103
|
+
</Grid.Col>
|
|
104
|
+
<Grid.Col span={6}>
|
|
105
|
+
<Select
|
|
106
|
+
disabled={!currentScope}
|
|
107
|
+
searchable
|
|
108
|
+
placeholder={'Seleziona un package name'}
|
|
109
|
+
data={getPackageNames(currentScope)}
|
|
110
|
+
value={currentPackageName}
|
|
111
|
+
label={'Package name'}
|
|
112
|
+
onChange={(v) => {
|
|
113
|
+
setCurrentPackageName(v)
|
|
114
|
+
}} />
|
|
115
|
+
</Grid.Col>
|
|
116
|
+
</Grid>
|
|
117
|
+
|
|
118
|
+
<Divider />
|
|
119
|
+
|
|
120
|
+
{(currentScope && currentPackageName && !permissionLoading && routeRules.length) === 0 &&
|
|
121
|
+
<Stack>
|
|
122
|
+
<Group justify={'right'} align={'center'}>
|
|
123
|
+
<Button leftSection={<IconPlus size={18}/>} onClick={() => setCreateRouteRuleModalOpened(true)}>Nuova regola</Button>
|
|
124
|
+
</Group>
|
|
125
|
+
<Center>
|
|
126
|
+
<Text size={'md'}>Nessuna regola esistente.</Text>
|
|
127
|
+
</Center>
|
|
128
|
+
</Stack>
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
{(!currentScope || !currentPackageName) &&
|
|
132
|
+
<Stack align={'center'} mt={32} mb={32}>
|
|
133
|
+
<IconCloudOff color={'gray'} size={64} />
|
|
134
|
+
<Center>
|
|
135
|
+
<Text size={'md'}>Seleziona uno scope e un package name per visualizzare i permessi associati.</Text>
|
|
136
|
+
</Center>
|
|
137
|
+
</Stack>
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
{!permissionLoading && routeRules.length > 0 &&
|
|
141
|
+
<Stack>
|
|
142
|
+
<Group justify={'right'} align={'center'}>
|
|
143
|
+
<Button leftSection={<IconPlus size={18}/>} onClick={() => setCreateRouteRuleModalOpened(true)}>Nuova regola</Button>
|
|
144
|
+
</Group>
|
|
145
|
+
<Table highlightOnHover>
|
|
146
|
+
<Table.Thead>
|
|
147
|
+
<Table.Tr>
|
|
148
|
+
<Table.Th>Id</Table.Th>
|
|
149
|
+
<Table.Th>Scope</Table.Th>
|
|
150
|
+
<Table.Th>Rotta</Table.Th>
|
|
151
|
+
<Table.Th>Permessi</Table.Th>
|
|
152
|
+
<Table.Th style={{maxWidth: 80, width: 80}}>Azioni</Table.Th>
|
|
153
|
+
</Table.Tr>
|
|
154
|
+
</Table.Thead>
|
|
155
|
+
<Table.Tbody>
|
|
156
|
+
{routeRules.map((element, i) => {
|
|
157
|
+
return (
|
|
158
|
+
<Table.Tr key={i}>
|
|
159
|
+
<Table.Td>{element.id}</Table.Td>
|
|
160
|
+
<Table.Td>{`${element.scope}.${element.packageName}`}</Table.Td>
|
|
161
|
+
<Table.Td>{`/${element.scope}/${element.packageName}/${element.route}`}</Table.Td>
|
|
162
|
+
<Table.Td>{element.permissionsCount}</Table.Td>
|
|
163
|
+
<Table.Td style={{maxWidth: 130, width: 130}}>
|
|
164
|
+
<Group>
|
|
165
|
+
<ActionIcon onClick={() => {
|
|
166
|
+
setCurrentRouteRule(element);
|
|
167
|
+
setManagePermissionModalOpened(true);
|
|
168
|
+
}}>
|
|
169
|
+
<IconLock size={18} />
|
|
170
|
+
</ActionIcon>
|
|
171
|
+
<ActionIcon onClick={() => {
|
|
172
|
+
deleteRouteRule(element);
|
|
173
|
+
}}>
|
|
174
|
+
<IconTrash size={18} />
|
|
175
|
+
</ActionIcon>
|
|
176
|
+
</Group>
|
|
177
|
+
|
|
178
|
+
</Table.Td>
|
|
179
|
+
</Table.Tr>
|
|
180
|
+
)
|
|
181
|
+
})}
|
|
182
|
+
</Table.Tbody>
|
|
183
|
+
</Table>
|
|
184
|
+
</Stack>
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
</Stack>
|
|
188
|
+
|
|
189
|
+
{currentRouteRule &&
|
|
190
|
+
<Modal
|
|
191
|
+
size={'60%'}
|
|
192
|
+
centered
|
|
193
|
+
opened={managePermissionModalOpened}
|
|
194
|
+
onClose={() => {
|
|
195
|
+
getRouteRulesForScope();
|
|
196
|
+
setManagePermissionModalOpened(false);
|
|
197
|
+
setCurrentRouteRule(undefined);
|
|
198
|
+
}}
|
|
199
|
+
title={`Gestione permessi ${currentRouteRule.route}`}>
|
|
200
|
+
<PermissionNavigator
|
|
201
|
+
context={{type: 'route-rule', id: currentRouteRule.id!.toString()}}
|
|
202
|
+
onUpdate={() => {}}
|
|
203
|
+
/>
|
|
204
|
+
</Modal>
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
<Modal
|
|
208
|
+
size={'60%'}
|
|
209
|
+
centered
|
|
210
|
+
opened={createRouteRuleModalOpened}
|
|
211
|
+
onClose={() => {
|
|
212
|
+
getRouteRulesForScope();
|
|
213
|
+
setCreateRouteRuleModalOpened(false);
|
|
214
|
+
}}
|
|
215
|
+
title={`Crea nuova regola`}>
|
|
216
|
+
<RouteRuleCreateForm
|
|
217
|
+
scope={currentScope!}
|
|
218
|
+
packageName={currentPackageName!}
|
|
219
|
+
onCreated={() => {
|
|
220
|
+
getRouteRulesForScope();
|
|
221
|
+
setCreateRouteRuleModalOpened(false);
|
|
222
|
+
}}
|
|
223
|
+
onCanceled={() => {setCreateRouteRuleModalOpened(false)}}
|
|
224
|
+
/>
|
|
225
|
+
</Modal>
|
|
226
|
+
|
|
227
|
+
</DataCard>
|
|
228
|
+
)
|
|
229
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import {DomainRole, FluxoClientSys, User, UserService} from "@fluxo-dev/api-client-base";
|
|
2
|
+
import { Button, MultiSelect, Stack, TextInput } from "@mantine/core";
|
|
3
|
+
import { useForm } from "@mantine/form";
|
|
4
|
+
import { showNotification } from "@mantine/notifications";
|
|
5
|
+
import { IconFilePlus } from '@tabler/icons-react';
|
|
6
|
+
import {useEffect, useState} from "react";
|
|
7
|
+
|
|
8
|
+
export interface UserFormProps {
|
|
9
|
+
user?: User,
|
|
10
|
+
onCreate: () => void
|
|
11
|
+
}
|
|
12
|
+
function UserForm(props: UserFormProps) {
|
|
13
|
+
const userService = new UserService();
|
|
14
|
+
const roles = [
|
|
15
|
+
{ value: 'administrator', label: 'Amministratore' },
|
|
16
|
+
{ value: 'user', label: 'Utente' }
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const [domainRoles, setDomainRoles] = useState<DomainRole[]>([]);
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
|
|
23
|
+
FluxoClientSys.Instance.security.domainRole.find(999,0)
|
|
24
|
+
.then((res) => {
|
|
25
|
+
setDomainRoles(res.results);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
}, []);
|
|
29
|
+
|
|
30
|
+
const generalForm = useForm({
|
|
31
|
+
initialValues: {
|
|
32
|
+
user: {
|
|
33
|
+
firstName: props.user?.userData?.FirstName ?? '',
|
|
34
|
+
lastName: props.user?.userData?.LastName ?? '',
|
|
35
|
+
email: props.user?.email ?? '',
|
|
36
|
+
userName: ''
|
|
37
|
+
},
|
|
38
|
+
assignToRoles: props.user?.roles ?? [],
|
|
39
|
+
assignToDomainRoles: props.user?.domainRoles.map(a => a.id!.toString()) ?? []
|
|
40
|
+
},
|
|
41
|
+
clearInputErrorOnChange: true,
|
|
42
|
+
validateInputOnChange: true,
|
|
43
|
+
validate: {
|
|
44
|
+
user: {
|
|
45
|
+
firstName: (value) => (!value ? 'Il nome è obbligatorio' : null),
|
|
46
|
+
lastName: (value) => (!value ? 'Il cognome è obbligatorio' : null),
|
|
47
|
+
email: (value) => (!value ? 'L\'email è obbligatoria' : null),
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const create = (value: any) => {
|
|
53
|
+
value.user.userName = value.user.email;
|
|
54
|
+
|
|
55
|
+
const newUser = {
|
|
56
|
+
user: value.user,
|
|
57
|
+
assignToRoles: value.assignToRoles,
|
|
58
|
+
assignToDomainRoles: value.assignToDomainRoles.map((a: string) => parseInt(a))
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
(props.user ? userService.updateUser(props.user.id, newUser) : userService.createUser(newUser))
|
|
63
|
+
.then((res) => {
|
|
64
|
+
if (res.success) {
|
|
65
|
+
showNotification({
|
|
66
|
+
title: 'Operazione completata',
|
|
67
|
+
message: 'Aggiornamento completato',
|
|
68
|
+
color: 'green',
|
|
69
|
+
})
|
|
70
|
+
generalForm.reset();
|
|
71
|
+
generalForm.resetDirty();
|
|
72
|
+
if (props.onCreate)
|
|
73
|
+
props.onCreate();
|
|
74
|
+
} else {
|
|
75
|
+
showNotification({
|
|
76
|
+
title: 'Errore',
|
|
77
|
+
message: `Errore durante l'aggiornamento: ${res.errors.map(x => x.description).join(', ')}`,
|
|
78
|
+
color: 'red',
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
.catch((err) => {
|
|
83
|
+
showNotification({
|
|
84
|
+
title: 'Errore',
|
|
85
|
+
message: `Errore durante l'aggiornamento: ${err.message}`,
|
|
86
|
+
color: 'red',
|
|
87
|
+
});
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<form
|
|
93
|
+
onKeyDown={event => { if (event.which === 13) event.preventDefault() }}
|
|
94
|
+
onSubmit={generalForm.onSubmit(
|
|
95
|
+
(values, event) => {
|
|
96
|
+
event?.preventDefault();
|
|
97
|
+
create(values);
|
|
98
|
+
})}>
|
|
99
|
+
<Stack gap="xs">
|
|
100
|
+
<TextInput label={'Nome'} {...generalForm.getInputProps('user.firstName')} />
|
|
101
|
+
<TextInput label={'Cognome'} {...generalForm.getInputProps('user.lastName')} />
|
|
102
|
+
<TextInput label={'Email'} disabled={!!props.user} {...generalForm.getInputProps('user.email')} />
|
|
103
|
+
<MultiSelect
|
|
104
|
+
data={roles}
|
|
105
|
+
label="Tipo di accesso"
|
|
106
|
+
placeholder="Seleziona uno o più tipi di accesso"
|
|
107
|
+
{...generalForm.getInputProps('assignToRoles')}
|
|
108
|
+
/>
|
|
109
|
+
<MultiSelect
|
|
110
|
+
data={domainRoles.map(x => ({value: x.id!.toString(), label: x.name}))}
|
|
111
|
+
label="Ruolo"
|
|
112
|
+
placeholder="Seleziona uno o più ruoli"
|
|
113
|
+
{...generalForm.getInputProps('assignToDomainRoles')}
|
|
114
|
+
/>
|
|
115
|
+
</Stack >
|
|
116
|
+
<Stack align="flex-end" mt="md">
|
|
117
|
+
<Button type="submit" leftSection={<IconFilePlus />} ml='auto' disabled={!generalForm.isDirty()}>Salva</Button>
|
|
118
|
+
</Stack >
|
|
119
|
+
</form>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export default UserForm;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import React, {useEffect, useState} from "react";
|
|
2
|
+
import {FluxoClientSys, User} from "@fluxo-dev/api-client-base";
|
|
3
|
+
import {showNotification} from "@mantine/notifications";
|
|
4
|
+
import {ActionIcon, Badge, Menu, Modal, Stack, Table} from "@mantine/core";
|
|
5
|
+
import {DataCard} from "@fluxo-dev/ui-components";
|
|
6
|
+
import {IconDotsVertical, IconEdit, IconPlus, IconTrash} from "@tabler/icons-react";
|
|
7
|
+
import UserForm from "./user-form";
|
|
8
|
+
|
|
9
|
+
export function UsersGrid() {
|
|
10
|
+
const [users, setUsers] = useState<User[]>([]);
|
|
11
|
+
|
|
12
|
+
const [currentUser, setCurrentUser] = useState<User>();
|
|
13
|
+
|
|
14
|
+
const [newUserModalOpen, setNewUserModalOpen] = useState<boolean>(false);
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
getAllUsers();
|
|
18
|
+
}, [])
|
|
19
|
+
|
|
20
|
+
const getAllUsers = () => {
|
|
21
|
+
FluxoClientSys.Instance.security.user.getAllUsers().then(res => {
|
|
22
|
+
setUsers(res);
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const deletion = (id: string) => {
|
|
27
|
+
FluxoClientSys.Instance.security.user.deleteUser(id)
|
|
28
|
+
.then((res) => {
|
|
29
|
+
if (res.success) {
|
|
30
|
+
showNotification({
|
|
31
|
+
title: 'Cancellazione completata',
|
|
32
|
+
message: `L'utente è stato cancellato con successo`,
|
|
33
|
+
color: 'green',
|
|
34
|
+
});
|
|
35
|
+
} else {
|
|
36
|
+
showNotification({
|
|
37
|
+
title: 'Errore',
|
|
38
|
+
message: `Errore durante la cancellazione: ${res.errors.map(x => x.description).join(', ')}`,
|
|
39
|
+
color: 'red',
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
getAllUsers();
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<Stack>
|
|
48
|
+
<DataCard
|
|
49
|
+
title={'Utenti'}
|
|
50
|
+
actions={[
|
|
51
|
+
{icon: <IconPlus size={18}/>, label: 'Nuovo utente', onClick: () => setNewUserModalOpen(true)},
|
|
52
|
+
]}>
|
|
53
|
+
|
|
54
|
+
<Table highlightOnHover>
|
|
55
|
+
<Table.Thead>
|
|
56
|
+
<Table.Tr>
|
|
57
|
+
<Table.Th>Nome</Table.Th>
|
|
58
|
+
<Table.Th>Cognome</Table.Th>
|
|
59
|
+
<Table.Th>Email</Table.Th>
|
|
60
|
+
<Table.Th>Tipo di accesso</Table.Th>
|
|
61
|
+
<Table.Th>Ruoli</Table.Th>
|
|
62
|
+
<Table.Th></Table.Th>
|
|
63
|
+
</Table.Tr>
|
|
64
|
+
</Table.Thead>
|
|
65
|
+
<Table.Tbody>
|
|
66
|
+
{
|
|
67
|
+
users.map((element, i) =>
|
|
68
|
+
<Table.Tr key={i}>
|
|
69
|
+
<Table.Td>{element.userData.FirstName}</Table.Td>
|
|
70
|
+
<Table.Td>{element.userData.LastName}</Table.Td>
|
|
71
|
+
<Table.Td>{element.email}</Table.Td>
|
|
72
|
+
<Table.Td>
|
|
73
|
+
<Stack gap={8}>
|
|
74
|
+
{element.roles.map((d) => {
|
|
75
|
+
return (
|
|
76
|
+
<Badge key={d} color={'orange'}>{d}</Badge>
|
|
77
|
+
)
|
|
78
|
+
})}
|
|
79
|
+
</Stack>
|
|
80
|
+
</Table.Td>
|
|
81
|
+
<Table.Td>
|
|
82
|
+
<Stack gap={8}>
|
|
83
|
+
{element.domainRoles.map((d) => {
|
|
84
|
+
return (
|
|
85
|
+
<Badge key={d.id}>{d.name}</Badge>
|
|
86
|
+
)
|
|
87
|
+
})}
|
|
88
|
+
</Stack>
|
|
89
|
+
</Table.Td>
|
|
90
|
+
<Table.Td align="right">
|
|
91
|
+
<Menu shadow="md" width={200}>
|
|
92
|
+
<Menu.Target>
|
|
93
|
+
<ActionIcon><IconDotsVertical size={18} /></ActionIcon>
|
|
94
|
+
</Menu.Target>
|
|
95
|
+
|
|
96
|
+
<Menu.Dropdown>
|
|
97
|
+
<Menu.Item onClick={() => {
|
|
98
|
+
setCurrentUser(element);
|
|
99
|
+
setNewUserModalOpen(true);
|
|
100
|
+
}} leftSection={<IconEdit size={14} />}>Modifica</Menu.Item>
|
|
101
|
+
<Menu.Item color={'red'} onClick={() => deletion(element.id)} leftSection={<IconTrash color={'red'} size={14} />}>Elimina</Menu.Item>
|
|
102
|
+
</Menu.Dropdown>
|
|
103
|
+
</Menu>
|
|
104
|
+
</Table.Td>
|
|
105
|
+
</Table.Tr>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
</Table.Tbody>
|
|
109
|
+
</Table>
|
|
110
|
+
</DataCard>
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
<Modal centered opened={newUserModalOpen} onClose={() => {
|
|
114
|
+
setNewUserModalOpen(false);
|
|
115
|
+
setCurrentUser(undefined);
|
|
116
|
+
}} title={`${currentUser ? 'Modifica utente' : 'Crea utente'}`}>
|
|
117
|
+
<UserForm onCreate={() => {
|
|
118
|
+
setNewUserModalOpen(false);
|
|
119
|
+
getAllUsers();
|
|
120
|
+
setCurrentUser(undefined);
|
|
121
|
+
}} user={currentUser}/>
|
|
122
|
+
</Modal>
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
</Stack>
|
|
126
|
+
);
|
|
127
|
+
}
|