@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.
Files changed (66) hide show
  1. package/.babelrc +12 -0
  2. package/.eslintrc.json +18 -0
  3. package/README.md +7 -0
  4. package/jest.config.ts +11 -0
  5. package/package.json +4 -0
  6. package/project.json +43 -0
  7. package/src/index.ts +1 -0
  8. package/src/lib/app.module.css +1 -0
  9. package/src/lib/app.spec.tsx +17 -0
  10. package/src/lib/app.tsx +374 -0
  11. package/src/lib/components/error-page/404.tsx +16 -0
  12. package/src/lib/components/routes/main-routes.tsx +26 -0
  13. package/src/lib/layouts/blank/blank-layout.tsx +10 -0
  14. package/src/lib/layouts/main/app-bar.tsx +192 -0
  15. package/src/lib/layouts/main/app-layout.tsx +52 -0
  16. package/src/lib/layouts/main/content.tsx +10 -0
  17. package/src/lib/layouts/main/footer-bar.tsx +76 -0
  18. package/src/lib/layouts/main/navbar-item.module.css +49 -0
  19. package/src/lib/layouts/main/navbar-item.tsx +129 -0
  20. package/src/lib/layouts/main/navbar.tsx +38 -0
  21. package/src/lib/layouts/main/search-bar.tsx +44 -0
  22. package/src/lib/layouts/main/shell-spotlight.tsx +58 -0
  23. package/src/lib/models/app-jit.ts +6 -0
  24. package/src/lib/pages/general/fluxo-plugin-loader.tsx +22 -0
  25. package/src/lib/pages/login/account-confirmation.tsx +86 -0
  26. package/src/lib/pages/login/change-password.tsx +58 -0
  27. package/src/lib/pages/login/forgot-password.tsx +53 -0
  28. package/src/lib/pages/login/login-page.tsx +70 -0
  29. package/src/lib/pages/login/reset-password.tsx +91 -0
  30. package/src/lib/pages/settings/apps/add-jit-app.tsx +79 -0
  31. package/src/lib/pages/settings/apps/app-item.tsx +157 -0
  32. package/src/lib/pages/settings/apps/app-jit-item.tsx +105 -0
  33. package/src/lib/pages/settings/apps/apps-list.tsx +171 -0
  34. package/src/lib/pages/settings/apps/embedded-module-item.tsx +66 -0
  35. package/src/lib/pages/settings/apps/install-or-upgrade-app.tsx +105 -0
  36. package/src/lib/pages/settings/menu-designer/custom-node.module.css +34 -0
  37. package/src/lib/pages/settings/menu-designer/custom-node.tsx +160 -0
  38. package/src/lib/pages/settings/menu-designer/menu-create-form.tsx +109 -0
  39. package/src/lib/pages/settings/menu-designer/menu-designer.module.css +19 -0
  40. package/src/lib/pages/settings/menu-designer/menu-designer.tsx +463 -0
  41. package/src/lib/pages/settings/menu-designer/menu-item-edit.tsx +115 -0
  42. package/src/lib/pages/settings/menu-designer/placeholder.module.css +8 -0
  43. package/src/lib/pages/settings/menu-designer/placeholder.tsx +13 -0
  44. package/src/lib/pages/settings/security/components/domani-role/domain-role-form.tsx +67 -0
  45. package/src/lib/pages/settings/security/components/domani-role/domain-role-grid.tsx +139 -0
  46. package/src/lib/pages/settings/security/components/permission/create-custom-permission-form.tsx +64 -0
  47. package/src/lib/pages/settings/security/components/permission/create-scope-form.tsx +158 -0
  48. package/src/lib/pages/settings/security/components/permission/permission-grid.tsx +304 -0
  49. package/src/lib/pages/settings/security/components/permission/permission-navigator.tsx +320 -0
  50. package/src/lib/pages/settings/security/components/permission/update-permission.tsx +54 -0
  51. package/src/lib/pages/settings/security/components/route-rule/route-rule-create-form.tsx +59 -0
  52. package/src/lib/pages/settings/security/components/route-rule/route-rule-grid.tsx +229 -0
  53. package/src/lib/pages/settings/security/components/user/user-form.tsx +123 -0
  54. package/src/lib/pages/settings/security/components/user/users-grid.tsx +127 -0
  55. package/src/lib/pages/settings/settings.tsx +298 -0
  56. package/src/lib/pages/settings/token/token-row.tsx +69 -0
  57. package/src/lib/pages/settings/token/tokens.tsx +73 -0
  58. package/src/lib/pages/settings/ui/ui.tsx +149 -0
  59. package/src/lib/services/app-jit-manager.ts +92 -0
  60. package/src/lib/services/app-menu.service.ts +35 -0
  61. package/src/lib/utils/icon-factory.tsx +25 -0
  62. package/src/lib/utils/security/only-not-logged-route.tsx +17 -0
  63. package/src/lib/utils/security/protected-route.tsx +47 -0
  64. package/tsconfig.json +20 -0
  65. package/tsconfig.lib.json +24 -0
  66. package/tsconfig.spec.json +20 -0
@@ -0,0 +1,8 @@
1
+ .root {
2
+ background-color: #1967d2;
3
+ height: 2px;
4
+ position: absolute;
5
+ right: 0;
6
+ transform: translateY(-50%);
7
+ top: 0;
8
+ }
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ import { NodeModel } from "@minoru/react-dnd-treeview";
3
+ import styles from "./placeholder.module.css";
4
+
5
+ type Props = {
6
+ node: NodeModel;
7
+ depth: number;
8
+ };
9
+
10
+ export const Placeholder: React.FC<Props> = (props) => {
11
+ const left = props.depth * 24;
12
+ return <div className={styles["root"]} style={{ left }}></div>;
13
+ };
@@ -0,0 +1,67 @@
1
+ import {DomainRole, DomainRoleService} from "@fluxo-dev/api-client-base";
2
+ import {useForm} from "@mantine/form";
3
+ import {Button, Stack, TextInput} from "@mantine/core";
4
+ import {IconFilePlus} from '@tabler/icons-react';
5
+ import {showNotification} from "@mantine/notifications";
6
+
7
+ export interface DomainRoleFormProps {
8
+ domainRole: DomainRole | undefined;
9
+ onCreate: () => void;
10
+ }
11
+
12
+ export function DomainRoleForm (props: DomainRoleFormProps) {
13
+
14
+ const domainRoleService = new DomainRoleService();
15
+
16
+ const form = useForm<DomainRole>({
17
+ initialValues: {
18
+ name: props.domainRole?.name ?? '',
19
+ description: props.domainRole?.description ?? '',
20
+ identifier: props.domainRole?.identifier ?? '',
21
+ }
22
+ });
23
+
24
+ const save = (value: DomainRole) => {
25
+
26
+ (props.domainRole ? domainRoleService.update(props.domainRole.id!.toString(), value) : domainRoleService.create(value))
27
+ .then((res) => {
28
+
29
+ showNotification({
30
+ title: 'Operazione completata',
31
+ message: 'Ruolo salvato correttamente',
32
+ color: 'green',
33
+ })
34
+ form.reset();
35
+ form.resetDirty();
36
+ if (props.onCreate)
37
+ props.onCreate();
38
+
39
+ })
40
+ .catch((err) => {
41
+ showNotification({
42
+ title: 'Errore',
43
+ message: 'Si è verificato un errore: ' + err.message,
44
+ color: 'red',
45
+ })
46
+ })
47
+ }
48
+
49
+ return (
50
+ <form onKeyDown={event => { if (event.which === 13) event.preventDefault() }}
51
+ onSubmit={form.onSubmit(
52
+ (values, event) => {
53
+ event?.preventDefault();
54
+ save(values);
55
+ })}>
56
+ <Stack>
57
+ <TextInput label={"Identificatore"} placeholder={'Es: administrator'} required {...form.getInputProps('identifier')} />
58
+ <TextInput label={"Nome"} placeholder={'Es: Amministratore'} required {...form.getInputProps('name')} />
59
+ <TextInput label={"Descrizione"} placeholder={'Es: Ruolo amministratore'} required {...form.getInputProps('description')} />
60
+
61
+ <Stack align="flex-end" mt="md">
62
+ <Button type="submit" leftSection={<IconFilePlus />} ml='auto' disabled={!form.isDirty()}>Salva</Button>
63
+ </Stack >
64
+ </Stack>
65
+ </form>
66
+ )
67
+ }
@@ -0,0 +1,139 @@
1
+ import {IconDotsVertical, IconEdit, IconLock, IconPlus, IconTrash} from "@tabler/icons-react";
2
+ import {ActionIcon, Menu, Modal, Table} from "@mantine/core";
3
+ import {DataCard} from "@fluxo-dev/ui-components";
4
+ import React, {useEffect, useState} from "react";
5
+ import {DomainRole, FluxoClientSys} from "@fluxo-dev/api-client-base";
6
+ import {showNotification} from "@mantine/notifications";
7
+ import {DomainRoleForm} from "./domain-role-form";
8
+ import {PermissionNavigator} from "../permission/permission-navigator";
9
+
10
+ export function DomainRoleGrid() {
11
+
12
+ const [domainRoles, setDomainRoles] = useState<DomainRole[]>([]);
13
+ const [currentDomainRole, setCurrentDomainRole] = useState<DomainRole>();
14
+ const [domainRoleModalOpen, setDomainRoleModalOpen] = useState<boolean>(false);
15
+ const [updateDomainRolePermissionsModal, setUpdateDomainRolePermissionsModal] = useState<boolean>(false);
16
+
17
+ useEffect(() => {
18
+ getAllDomainRoles();
19
+ }, [])
20
+
21
+ const getAllDomainRoles = () => {
22
+ FluxoClientSys.Instance.security.domainRole.find(9999,0, undefined, "DomainRolePermissions,DomainRolePermissions.Permission")
23
+ .then((res) => {
24
+ setDomainRoles(res.results);
25
+ });
26
+ }
27
+
28
+ const deleteDomainRole = (id: number | undefined) => {
29
+
30
+ if(!id)
31
+ return;
32
+
33
+ FluxoClientSys.Instance.security.domainRole.delete(id.toString())
34
+ .then((res) => {
35
+
36
+ showNotification({
37
+ title: 'Cancellazione completata',
38
+ message: `Il ruolo è stato cancellato con successo`,
39
+ color: 'green',
40
+ });
41
+
42
+ getAllDomainRoles();
43
+
44
+ })
45
+ .catch((err) => {
46
+ showNotification({
47
+ title: 'Errore',
48
+ message: `Errore durante la cancellazione`,
49
+ color: 'red',
50
+ });
51
+ });
52
+ }
53
+
54
+ return (
55
+ <DataCard title={'Ruoli utente'}
56
+ actions={[{icon: <IconPlus size={18}/>, label: 'Nuovo ruolo', onClick: () => {
57
+ setCurrentDomainRole(undefined);
58
+ setDomainRoleModalOpen(true);
59
+ }}]}>
60
+ <Table highlightOnHover>
61
+ <Table.Thead>
62
+ <Table.Tr>
63
+ <Table.Th>Id</Table.Th>
64
+ <Table.Th>Identificatore</Table.Th>
65
+ <Table.Th>Nome</Table.Th>
66
+ <Table.Th>Descrizione</Table.Th>
67
+ <Table.Th>Permessi</Table.Th>
68
+ <Table.Th></Table.Th>
69
+ </Table.Tr>
70
+ </Table.Thead>
71
+ <tbody>
72
+ {
73
+ domainRoles.map((element, i) =>
74
+ <Table.Tr key={i}>
75
+ <td>{element.id}</td>
76
+ <td>{element.identifier}</td>
77
+ <td>{element.name}</td>
78
+ <td>{element.description}</td>
79
+ <td>{element.permissionCount}</td>
80
+ <Table.Td align="right">
81
+ <Menu shadow="md" width={200}>
82
+ <Menu.Target>
83
+ <ActionIcon><IconDotsVertical size={18} /></ActionIcon>
84
+ </Menu.Target>
85
+
86
+ <Menu.Dropdown>
87
+ <Menu.Item leftSection={<IconLock size={14} />} onClick={() => {
88
+ setCurrentDomainRole(element);
89
+ setUpdateDomainRolePermissionsModal(true)
90
+ }}>
91
+ Permessi
92
+ </Menu.Item>
93
+ <Menu.Item onClick={() => {
94
+ setCurrentDomainRole(element);
95
+ setDomainRoleModalOpen(true);
96
+ }} leftSection={<IconEdit size={14} />}>Modifica</Menu.Item>
97
+ <Menu.Divider />
98
+ <Menu.Item color={'red'} onClick={() => deleteDomainRole(element.id)} leftSection={<IconTrash color={'red'} size={14} />}>Elimina</Menu.Item>
99
+ </Menu.Dropdown>
100
+ </Menu>
101
+ </Table.Td>
102
+ </Table.Tr>
103
+ )
104
+ }
105
+ </tbody>
106
+ </Table>
107
+
108
+ <Modal centered opened={domainRoleModalOpen} onClose={() => {
109
+ setDomainRoleModalOpen(false);
110
+ setCurrentDomainRole(undefined);
111
+ }} title={`${currentDomainRole ? 'Modifica ruolo' : 'Crea ruolo'}`}>
112
+ <DomainRoleForm onCreate={() => {
113
+ setDomainRoleModalOpen(false);
114
+ getAllDomainRoles();
115
+ setCurrentDomainRole(undefined);
116
+ }} domainRole={currentDomainRole}/>
117
+ </Modal>
118
+
119
+ {currentDomainRole &&
120
+ <Modal
121
+ size={'60%'}
122
+ centered
123
+ opened={updateDomainRolePermissionsModal}
124
+ onClose={() => {
125
+ setUpdateDomainRolePermissionsModal(false);
126
+ setCurrentDomainRole(undefined);
127
+ getAllDomainRoles();
128
+ }}
129
+ title={`Gestione permessi ${currentDomainRole.name}`}>
130
+ <PermissionNavigator
131
+ context={{type: 'domainRole', id: currentDomainRole.id!.toString()}}
132
+ onUpdate={() => {}}
133
+ />
134
+ </Modal>
135
+ }
136
+
137
+ </DataCard>
138
+ )
139
+ }
@@ -0,0 +1,64 @@
1
+ import {Alert, Button, Divider, Group, Stack, TextInput} from "@mantine/core";
2
+ import {CreateCustomPermissionCommand, FluxoClientSys, PermissionScope} from "@fluxo-dev/api-client-base";
3
+ import React, {useState} from "react";
4
+ import {showNotification} from "@mantine/notifications";
5
+ import {IconInfoCircle} from "@tabler/icons-react";
6
+
7
+ export interface CreateCustomPermissionFormProps {
8
+ permissionScope: PermissionScope;
9
+ onCanceled: () => void;
10
+ onCreated: () => void;
11
+ }
12
+ export function CreateCustomPermissionForm(props: CreateCustomPermissionFormProps) {
13
+
14
+ const [identifier, setIdentifier] = useState<string>('');
15
+ const [description, setDescription] = useState<string>('');
16
+
17
+ const createCustomPermission = () => {
18
+ if(!identifier || !description) return;
19
+
20
+ const command: CreateCustomPermissionCommand = {
21
+ scope: props.permissionScope.scope,
22
+ packageName: props.permissionScope.packageName,
23
+ namespace: props.permissionScope.namespace,
24
+ identifier: identifier,
25
+ description: description
26
+ }
27
+ FluxoClientSys.Instance.security.permission.createCustomPermission(command)
28
+ .then(() => {
29
+ showNotification({
30
+ title: 'Permesso creato',
31
+ message: `Il permesso ${props.permissionScope.scope}.${props.permissionScope.packageName}.${props.permissionScope.namespace}.${identifier} è stato creato con successo.`,
32
+ color: 'green'
33
+ })
34
+ props.onCreated();
35
+ })
36
+ .catch(() => {
37
+ showNotification({
38
+ title: 'Errore',
39
+ message: `Si è verificato un errore durante la creazione del permesso ${props.permissionScope.scope}.${props.permissionScope.packageName}.${props.permissionScope.namespace}.${identifier}.`,
40
+ color: 'red'
41
+ })
42
+ });
43
+ }
44
+
45
+ return (
46
+ <Stack>
47
+ <Alert color={'yellow'} icon={<IconInfoCircle />}>
48
+ <b>Informazioni: </b> crea nuovi permessi personalizzati da utilizzare nei servizi dinamici, nei menu e nelle pagine DynamicUI.
49
+ </Alert>
50
+ <TextInput label={"Identificatore"} placeholder={'Es: create'} required onChange={(v) => setIdentifier(v.target.value)} />
51
+ <TextInput label={"Descrizione"} placeholder={'Es: Crea'} required onChange={(v) => setDescription(v.target.value)} />
52
+
53
+ <Divider />
54
+ <Group justify={'right'}>
55
+ <Button variant={'subtle'} onClick={props.onCanceled}>Annulla</Button>
56
+ <Button
57
+ disabled={!identifier || !description}
58
+ onClick={createCustomPermission}>
59
+ Salva
60
+ </Button>
61
+ </Group>
62
+ </Stack>
63
+ )
64
+ }
@@ -0,0 +1,158 @@
1
+ import React, {useState} from "react";
2
+ import {Button, Divider, Group, Select, Stack, TextInput} from "@mantine/core";
3
+ import {CreatePermissionScopeCommand, FluxoClientSys, PermissionScope} from "@fluxo-dev/api-client-base";
4
+ import {showNotification} from "@mantine/notifications";
5
+
6
+ export interface CreateScopeFormProps {
7
+ permissionScopes: PermissionScope[],
8
+ onCreated: () => void;
9
+ onCanceled: () => void;
10
+ }
11
+
12
+ export function CreateScopeForm(props: CreateScopeFormProps) {
13
+
14
+ const [permissionScopes] = useState<PermissionScope[]>(props.permissionScopes);
15
+ const [createdScopes, setCreatedScopes] = useState<string[]>([]);
16
+ const [createdPackageNames, setCreatedPackageNames] = useState<string[]>([]);
17
+ const [createdNamespaces, setCreatedNamespaces] = useState<string[]>([]);
18
+
19
+ const [currentScope, setCurrentScope] = useState<string | null>(null);
20
+ const [currentPackageName, setCurrentPackageName] = useState<string | null>(null);
21
+ const [currentNamespace, setCurrentNamespace] = useState<string | undefined>(undefined);
22
+ const [namespaceDescription, setNamespaceDescription] = useState<string>('');
23
+ const [namespaceIdentifierError, setNamespaceIdentifierError] = useState<string | null>(null);
24
+ const createPermissionScope = () => {
25
+ if(!currentScope || !currentPackageName || !currentNamespace) {
26
+ return;
27
+ }
28
+
29
+ const command: CreatePermissionScopeCommand = {
30
+ scope: currentScope,
31
+ packageName: currentPackageName,
32
+ namespace: currentNamespace,
33
+ namespaceDescription: namespaceDescription
34
+ }
35
+
36
+ FluxoClientSys.Instance.security.permission.createPermissionScope(command)
37
+ .then((res) => {
38
+ showNotification({
39
+ title: 'Scope creato',
40
+ message: `Lo scope ${currentScope}.${currentPackageName}.${currentNamespace} è stato creato con successo.`,
41
+ color: 'green'
42
+ });
43
+ props.onCreated();
44
+ })
45
+ .catch(() => {
46
+ showNotification({
47
+ title: 'Errore',
48
+ message: `Si è verificato un errore durante la creazione dello scope ${currentScope}.${currentPackageName}.${currentNamespace}.`,
49
+ color: 'red'
50
+ });
51
+ })
52
+ }
53
+
54
+ const getScopes = () => {
55
+ if(permissionScopes === undefined) return [];
56
+ return [...new Set(permissionScopes.map(a => a.scope))];
57
+ }
58
+
59
+ const getPackageNames = (scope: string | null) => {
60
+ if(permissionScopes === undefined || !scope) return [];
61
+ return [...new Set(permissionScopes.filter(a => a.scope === scope).map(a => a.packageName))];
62
+ }
63
+
64
+ const getNamespaces = (scope: string | null, packageName: string | null) => {
65
+ if(permissionScopes === undefined || !scope || !packageName) return [];
66
+ return [...new Set(permissionScopes.filter(a => a.scope === scope && a.packageName === packageName).map(a => a.namespace))];
67
+ }
68
+
69
+ return (
70
+ <Stack>
71
+ {/*<Select
72
+ label="Scope"
73
+ description={'Seleziona uno scope esistente oppure crea un nuovo scope.'}
74
+ data={[...getScopes(), ...createdScopes]}
75
+ nothingFoundMessage="Nessuno scope trovato"
76
+ searchable
77
+ onChange={(v) => setCurrentScope(v)}
78
+ creatable
79
+ getCreateLabel={(query) => `+ Crea ${query}`}
80
+ onCreate={(query) => {
81
+ setCreatedScopes([query]);
82
+ return query;
83
+ }}
84
+ />
85
+
86
+ <Select
87
+ label="Package Name"
88
+ description={'Seleziona un package name esistente oppure crea un nuovo package name.'}
89
+ data={[...getPackageNames(currentScope), ...createdPackageNames]}
90
+ disabled={!currentScope}
91
+ nothingFoundMessage="Nessuno package name trovato"
92
+ searchable
93
+ creatable
94
+ onChange={(v) => setCurrentPackageName(v)}
95
+ getCreateLabel={(query) => `+ Crea ${query}`}
96
+ onCreate={(query) => {
97
+ setCreatedPackageNames([query]);
98
+ return query;
99
+ }}
100
+ />*/}
101
+
102
+ <Select
103
+ label="Scope"
104
+ description={'Seleziona uno scope esistente oppure crea un nuovo scope.'}
105
+ data={[...getScopes(), ...createdScopes]}
106
+ nothingFoundMessage="Nessuno scope trovato"
107
+ searchable
108
+ onChange={(v) => setCurrentScope(v)}
109
+ />
110
+
111
+ <Select
112
+ label="Package Name"
113
+ description={'Seleziona un package name esistente oppure crea un nuovo package name.'}
114
+ data={[...getPackageNames(currentScope), ...createdPackageNames]}
115
+ disabled={!currentScope}
116
+ nothingFoundMessage="Nessuno package name trovato"
117
+ searchable
118
+ />
119
+
120
+ <TextInput
121
+ disabled={!currentPackageName}
122
+ description={'Identificatore del nuovo namespace. Non è possibile selezionare un namespace già esistente.'}
123
+ label={'Identificatore del namespace'}
124
+ value={currentNamespace}
125
+ error={namespaceIdentifierError}
126
+ onChange={(e) => {
127
+ if(getNamespaces(currentScope, currentPackageName).includes(e.currentTarget.value)) {
128
+ setNamespaceIdentifierError(`Il namespace inserito è già presente nel percorso ${currentScope}.${currentPackageName}.`);
129
+ } else {
130
+ setNamespaceIdentifierError(null);
131
+ }
132
+
133
+ setCurrentNamespace(e.currentTarget.value)
134
+ }}
135
+ />
136
+
137
+ <TextInput
138
+ disabled={!currentNamespace}
139
+ label={'Descrizione del namespace'}
140
+ placeholder={'Descrizione del namespace'}
141
+ value={namespaceDescription}
142
+ onChange={(e) => {
143
+ setNamespaceDescription(e.currentTarget.value)
144
+ }}
145
+ />
146
+
147
+ <Divider />
148
+ <Group justify={'right'}>
149
+ <Button variant={'subtle'} onClick={props.onCanceled}>Annulla</Button>
150
+ <Button
151
+ disabled={!currentScope || !currentPackageName || !currentNamespace || !namespaceDescription || namespaceIdentifierError !== null}
152
+ onClick={createPermissionScope}>
153
+ Salva
154
+ </Button>
155
+ </Group>
156
+ </Stack>
157
+ )
158
+ }