@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,86 @@
1
+ import { Button, Grid, Stack, Text } from '@mantine/core';
2
+ import { useEffect, useState } from 'react';
3
+ import { Link, useSearchParams } from 'react-router-dom';
4
+ import {UserService} from "@fluxo-dev/api-client-base";
5
+
6
+ export function AccountConfirmation() {
7
+
8
+ const [email, setEmail] = useState<string>();
9
+ const [token, setToken] = useState<string>();
10
+ const [linkIsValid, setLinkIsValid] = useState<boolean>(true);
11
+
12
+ const [recoveryResult, setRecoveryResult] = useState<{ success: boolean, errors: { code: string, description: string }[] } | undefined>();
13
+
14
+ const userService = new UserService();
15
+ let [searchParams] = useSearchParams();
16
+
17
+ useEffect(() => {
18
+
19
+ const currentEmail = searchParams.get('email');
20
+ const currentToken = searchParams.get('token');
21
+
22
+ if (!currentEmail || !currentToken) {
23
+ setLinkIsValid(false)
24
+ } else {
25
+ setEmail(currentEmail)
26
+ setToken(currentToken)
27
+ }
28
+
29
+
30
+ }, [searchParams]);
31
+
32
+ const onFormSubmitClickHandler = () => {
33
+ if (email && token) {
34
+ userService.confirmEmail({ email: email, token: token })
35
+ .then(async (res) => {
36
+ setRecoveryResult(res);
37
+ })
38
+ .catch(_err => setRecoveryResult({ success: false, errors: [{ code: 'unkown', description: 'Errore sconosciuto' }] }));
39
+ }
40
+ }
41
+
42
+ return (
43
+ <Grid justify="center">
44
+ <Grid.Col span={3}>
45
+
46
+ {linkIsValid &&
47
+ <Stack gap={16}>
48
+ {(!recoveryResult) &&
49
+ <Stack gap={16}>
50
+ <h2 style={{ textAlign: 'center' }}>Conferma attivazione account</h2>
51
+ <Text style={{ marginTop: 0, marginBottom: 32, textAlign: 'center' }}>{email}</Text>
52
+
53
+ <Button onClick={onFormSubmitClickHandler}>Clicca qui per attivare il tuo account</Button>
54
+ </Stack>
55
+ }
56
+
57
+ {recoveryResult?.success ?
58
+ <div style={{ marginTop: 32 }}>
59
+ <Stack gap={16} style={{ textAlign: 'center' }}>
60
+ <Text>Account attivato con successo</Text>
61
+ <Link to={'/identity/login'}>Effettua il login</Link>
62
+ </Stack>
63
+ </div> :
64
+ <div style={{ textAlign: 'center', marginTop: 32 }}>
65
+ {recoveryResult?.errors.map((err, index) => {
66
+ return <Text key={err.code + index} >{err.description}</Text>
67
+ })}
68
+ </div>
69
+ }
70
+
71
+ </Stack>
72
+ }
73
+
74
+ {!linkIsValid &&
75
+ <Stack gap={16}>
76
+ <Text>Link non valido</Text>
77
+ <Link to={'/identity/login'} style={{ textAlign: 'center' }}>Effettua il login</Link>
78
+ </Stack>
79
+ }
80
+
81
+ </Grid.Col>
82
+ </Grid>
83
+ )
84
+ }
85
+
86
+ export default AccountConfirmation;
@@ -0,0 +1,58 @@
1
+ import { Button, Grid, Stack, TextInput, Text } from '@mantine/core';
2
+ import { useState } from 'react';
3
+ import {UserService} from "@fluxo-dev/api-client-base";
4
+
5
+ export function ChangePassword() {
6
+
7
+ const [currentPassword, setCurrentPassword] = useState<string>();
8
+ const [newPassword, setNewPassword] = useState<string>();
9
+ const [confirmNewPassword, setConfirmNewPassword] = useState<string>();
10
+
11
+ const userService = new UserService();
12
+
13
+ const [recoveryResult, setRecoveryResult] = useState<{ success: boolean, errors: { code: string, description: string }[] } | undefined>();
14
+
15
+ const onFormSubmitClickHandler = () => {
16
+ if (currentPassword && newPassword && confirmNewPassword) {
17
+ userService.changePassword({ currentPassword: currentPassword, newPassword: newPassword })
18
+ .then(async (_res) => {
19
+ setRecoveryResult(_res);
20
+ })
21
+ .catch(_err => {
22
+ setRecoveryResult({ success: false, errors: [{ code: 'unkown', description: 'Errore sconosciuto' }] })
23
+ });
24
+ }
25
+ }
26
+
27
+ return (
28
+ <Grid justify="center">
29
+ <Grid.Col span={3}>
30
+
31
+ <Stack gap={16}>
32
+ {(!recoveryResult || !recoveryResult.success) &&
33
+ <Stack gap={16}>
34
+ <h2>Cambio password</h2>
35
+ <TextInput type={'password'} label={'Password attuale'} onChange={(e) => setCurrentPassword(e.target.value)} />
36
+ <TextInput type={'password'} label={'Nuova password'} onChange={(e) => setNewPassword(e.target.value)} />
37
+ <TextInput type={'password'} label={'Conferma nuova password'} onChange={(e) => setConfirmNewPassword(e.target.value)} />
38
+
39
+ {recoveryResult?.errors.map((err) => {
40
+ return <Text>{err.description}</Text>
41
+ })}
42
+
43
+ <Button onClick={onFormSubmitClickHandler} disabled={!(newPassword && (newPassword === confirmNewPassword)) || (currentPassword === newPassword)}>Cambia password</Button>
44
+ </Stack>
45
+ }
46
+
47
+ {recoveryResult && recoveryResult.success &&
48
+ <h2>Password modificata con successo</h2>
49
+ }
50
+
51
+ </Stack>
52
+
53
+ </Grid.Col>
54
+ </Grid>
55
+ )
56
+ }
57
+
58
+ export default ChangePassword;
@@ -0,0 +1,53 @@
1
+ import { Button, Grid, Stack, Text, TextInput } from '@mantine/core';
2
+ import { useState } from 'react';
3
+ import { Link, useNavigate } from 'react-router-dom';
4
+ import {UserService} from "@fluxo-dev/api-client-base";
5
+
6
+ export function ForgotPassword() {
7
+
8
+ const [email, setEmail] = useState<string>();
9
+ const [errorMessage, setErrorMessage] = useState<string | undefined>();
10
+ const [successMessage, setSuccessMessage] = useState<string | undefined>();
11
+
12
+ const navigateTo = useNavigate();
13
+ const userService = new UserService();
14
+
15
+ const onFormSubmitClickHandler = () => {
16
+ if (email) {
17
+ userService.forgotPassword(email)
18
+ .then((_res) => setSuccessMessage("Richiesta inviata correttamente. Apri la tua casella e-mail."))
19
+ .catch(_err => setErrorMessage("Errore durante il login"));
20
+ }
21
+ }
22
+
23
+ return (
24
+ <Grid justify="center">
25
+ <Grid.Col span={3}>
26
+ {!successMessage &&
27
+ <div>
28
+ <h2>Hai dimenticato la password?</h2>
29
+ <Stack gap={16}>
30
+ <TextInput onChange={(e) => setEmail(e.target.value)} placeholder={'Il tuo indirizzo e-mail'} label={'Inserisci il tuo indirizzo e-mail per recuperarla.'} />
31
+ <Button onClick={onFormSubmitClickHandler} disabled={!email}>Recupera</Button>
32
+ <Link to={'/auth/login'} style={{ textAlign: 'center' }}>Effettua il login</Link>
33
+
34
+ {errorMessage &&
35
+ <Text>{errorMessage}</Text>
36
+ }
37
+
38
+ </Stack>
39
+ </div>
40
+ }
41
+
42
+ {successMessage &&
43
+ <Stack gap={16}>
44
+ <Text style={{ textAlign: 'center', width: '100%', display: 'block' }}>{successMessage}</Text>
45
+ <Link to={'/auth/login'} style={{ textAlign: 'center' }}>Effettua il login</Link>
46
+ </Stack>
47
+ }
48
+ </Grid.Col>
49
+ </Grid>
50
+ )
51
+ }
52
+
53
+ export default ForgotPassword;
@@ -0,0 +1,70 @@
1
+ import React from 'react';
2
+ import { useSelector } from 'react-redux'
3
+ import { FluxoClientSys } from "@fluxo-dev/api-client-base";
4
+ import { useForm } from '@mantine/form';
5
+ import { TextInput, Button, PasswordInput, Grid, Stack } from "@mantine/core";
6
+ import { useNavigate } from 'react-router-dom';
7
+
8
+ function LoginPage() {
9
+
10
+ const { loading, error } = useSelector((state: any) => state.user)
11
+ const navigateTo = useNavigate();
12
+
13
+ const form = useForm({
14
+ initialValues: {
15
+ username: '',
16
+ password: '',
17
+ },
18
+
19
+ validate: {
20
+ username: (value) => (value?.length < 1 ? 'Username obbligatorio' : null),
21
+ password: (value) => (value?.length < 1 ? 'Password obbligatoria' : null),
22
+ },
23
+ });
24
+
25
+ const loginHandler = (values: any) => {
26
+ FluxoClientSys.Instance.auth.login(values.username, values.password);
27
+ }
28
+
29
+ return (
30
+ <Grid justify="center">
31
+ <Grid.Col span={3}>
32
+ <h1>Login Page</h1>
33
+ <form onSubmit={form.onSubmit(
34
+ (values, event) => {
35
+ loginHandler(values);
36
+ }
37
+ )}>
38
+ <TextInput
39
+ withAsterisk
40
+ label="Nome utente"
41
+ placeholder="utente@azienda.com"
42
+ {...form.getInputProps('username')}
43
+ />
44
+ <PasswordInput
45
+ withAsterisk
46
+ label="Password"
47
+ placeholder="Inserisci la password..."
48
+ {...form.getInputProps('password')}
49
+ />
50
+
51
+ <Stack gap={5} mt="md">
52
+ <Stack align="flex-end">
53
+ <Button size="compact-XXX" variant="subtle" onClick={() => navigateTo('/auth/forgot-password')}>
54
+ Password Dimenticata?
55
+ </Button>
56
+ </Stack>
57
+ <Button loading={loading} type="submit">Accedi</Button>
58
+ </Stack>
59
+
60
+ </form>
61
+ {error &&
62
+ <p>Errore</p>
63
+ }
64
+
65
+ </Grid.Col>
66
+ </Grid>
67
+ )
68
+ }
69
+
70
+ export default LoginPage;
@@ -0,0 +1,91 @@
1
+ import { Button, Grid, Stack, Text, TextInput } from '@mantine/core';
2
+ import { useEffect, useState } from 'react';
3
+ import { Link, useSearchParams } from 'react-router-dom';
4
+ import {UserService} from "@fluxo-dev/api-client-base";
5
+
6
+ export function ResetPassword() {
7
+
8
+ const [email, setEmail] = useState<string>();
9
+ const [token, setToken] = useState<string>();
10
+ const [linkIsValid, setLinkIsValid] = useState<boolean>(true);
11
+
12
+ const [newPassword, setNewPassword] = useState<string>();
13
+ const [confirmNewPassword, setConfirmNewPassword] = useState<string>();
14
+
15
+ const [recoveryResult, setRecoveryResult] = useState<{ success: boolean, errors: { code: string, description: string }[] } | undefined>();
16
+
17
+ const userService = new UserService();
18
+ let [searchParams] = useSearchParams();
19
+
20
+ useEffect(() => {
21
+ if (searchParams) {
22
+ const currentEmail = searchParams.get('email');
23
+ const currentToken = searchParams.get('token');
24
+
25
+ if (!currentEmail || !currentToken) {
26
+ setLinkIsValid(false)
27
+ } else {
28
+ setEmail(currentEmail)
29
+ setToken(currentToken)
30
+ }
31
+ } else {
32
+ setLinkIsValid(false)
33
+ }
34
+ }, [searchParams])
35
+
36
+ const onFormSubmitClickHandler = () => {
37
+ if (email && token && newPassword) {
38
+ userService.forgotPasswordConfirm({ email: email, token: token, password: newPassword })
39
+ .then((res) => {
40
+ setRecoveryResult(res);
41
+ })
42
+ .catch(_err => setRecoveryResult({ success: false, errors: [{ code: 'unkown', description: 'Errore sconosciuto' }] }));
43
+ }
44
+ }
45
+
46
+ return (
47
+ <Grid justify="center">
48
+ <Grid.Col span={3}>
49
+ {linkIsValid &&
50
+ <Stack gap={16}>
51
+ {(!recoveryResult || !recoveryResult.success) &&
52
+ <Stack gap={16}>
53
+ <h2>Reset password</h2>
54
+ <Text>{email}</Text>
55
+ <TextInput type={'password'} label={'Nuova password'} onChange={(e) => setNewPassword(e.target.value)} />
56
+ <TextInput type={'password'} label={'Conferma nuova password'} onChange={(e) => setConfirmNewPassword(e.target.value)} />
57
+
58
+ {recoveryResult?.errors.map((err) => {
59
+ return <Text>{err.description}</Text>
60
+ })}
61
+
62
+ <Button onClick={onFormSubmitClickHandler} disabled={!(newPassword && (newPassword === confirmNewPassword))}>Effettua il reset</Button>
63
+ <Link to={'/auth/login'} style={{ textAlign: 'center' }}>Non vuoi effettuare il reset? Effettua il login</Link>
64
+ </Stack>
65
+ }
66
+
67
+ {recoveryResult?.success &&
68
+ <div style={{ marginTop: 32 }}>
69
+ <Stack gap={16}>
70
+ <Text style={{ textAlign: 'center', width: '100%', display: 'block' }}>{'Reset effettuato con successo'}</Text>
71
+ <Link to={'/auth/login'} style={{ textAlign: 'center' }}>Effettua il login</Link>
72
+ </Stack>
73
+ </div>
74
+ }
75
+
76
+ </Stack>
77
+ }
78
+
79
+ {!linkIsValid &&
80
+ <Stack gap={16}>
81
+ <Text>Link non valido</Text>
82
+ <Link to={'/auth/login'} style={{ textAlign: 'center' }}>Effettua il login</Link>
83
+ </Stack>
84
+ }
85
+
86
+ </Grid.Col>
87
+ </Grid>
88
+ )
89
+ }
90
+
91
+ export default ResetPassword;
@@ -0,0 +1,79 @@
1
+ import {Button, Group, Stack, TextInput} from "@mantine/core";
2
+ import React from "react";
3
+ import {AppJitManager} from "../../../services/app-jit-manager";
4
+ import {FluxoFrontendAppConfiguration} from "@fluxo-dev/api-client-base";
5
+
6
+ export interface AddJitAppProps {
7
+ onCanceled: () => void;
8
+ onAdded: () => void;
9
+ }
10
+ export function AddJitApp(props: AddJitAppProps) {
11
+
12
+ const [url, setUrl] = React.useState<string>('');
13
+ const [rootRoute, setRootRoute] = React.useState<string>('');
14
+
15
+ const [fluxoAppConfiguration, setFluxoAppConfiguration] = React.useState<FluxoFrontendAppConfiguration | undefined>(undefined);
16
+
17
+ const [verifyStatus, setVerifyStatus] = React.useState<'idle' | 'verified' | 'error'>('idle');
18
+
19
+ const verifyUrl = () => {
20
+
21
+ setVerifyStatus('idle');
22
+
23
+ fetch(`${url}/fluxo-fe-app-configuration.json`)
24
+ .then((response) => {
25
+ response.json()
26
+ .then((json) => {
27
+ setFluxoAppConfiguration(json);
28
+ setVerifyStatus('verified');
29
+ });
30
+ })
31
+ .catch((error) => {
32
+ setVerifyStatus('error');
33
+ });
34
+ }
35
+
36
+ const addApp = () => {
37
+ const manager = new AppJitManager();
38
+
39
+ if(!fluxoAppConfiguration) {
40
+ return;
41
+ }
42
+
43
+ manager.addAppConfiguration(fluxoAppConfiguration, url, rootRoute);
44
+ props.onAdded();
45
+ }
46
+
47
+ return (
48
+ <Stack>
49
+ <form>
50
+ <Stack>
51
+ <TextInput
52
+ label={'Root route'}
53
+ placeholder={'root-route'}
54
+ value={rootRoute}
55
+ onChange={(e) => setRootRoute(e.currentTarget.value)}
56
+ />
57
+ <TextInput
58
+ label={'Url'}
59
+ placeholder={'http://localhost:1234'}
60
+ value={url}
61
+ onChange={(e) => setUrl(e.currentTarget.value)}
62
+ />
63
+ {fluxoAppConfiguration &&
64
+ <>
65
+ <p>{fluxoAppConfiguration.name}</p>
66
+ </>
67
+ }
68
+ </Stack>
69
+ </form>
70
+ <Group align={'end'} justify={'right'}>
71
+ <Button variant={'subtle'} onClick={props.onCanceled}>Annulla</Button>
72
+ {verifyStatus === 'idle' || verifyStatus === 'error' ?
73
+ <Button disabled={!rootRoute || !url} onClick={verifyUrl} type={'submit'}>Verifica</Button> :
74
+ <Button onClick={addApp} type={'submit'}>Aggiungi</Button>
75
+ }
76
+ </Group>
77
+ </Stack>
78
+ )
79
+ }
@@ -0,0 +1,157 @@
1
+ import {AppState, AppType, FluxoApp, FluxoClientSys} from "@fluxo-dev/api-client-base";
2
+ import {ActionIcon, Badge, Button, Group, Image, Menu, Modal, Stack, Text} from "@mantine/core";
3
+ import React from "react";
4
+ import {IconArrowUp, IconCircleOff, IconDotsVertical, IconTrash} from '@tabler/icons-react';
5
+ import moment from "moment";
6
+ import {ConfirmModal} from "@fluxo-dev/ui-components";
7
+ import {showNotification} from "@mantine/notifications";
8
+ import {InstallOrUpgradeApp} from "./install-or-upgrade-app";
9
+
10
+ export interface AppItemProps {
11
+ app: FluxoApp;
12
+ onUninstall?: (app: FluxoApp) => void;
13
+ onDeactivate?: (app: FluxoApp) => void;
14
+ onActivate?: (app: FluxoApp) => void;
15
+ onUpgrade?: (app: FluxoApp) => void;
16
+ pluginEndpoint: string;
17
+ }
18
+ export function AppItem(props: AppItemProps) {
19
+
20
+ const [showDeleteModal, setShowDeleteModal] = React.useState(false);
21
+ const [showDeactivateModal, setShowDeactivateModale] = React.useState(false);
22
+ const [showActivateModal, setShowActivateModal] = React.useState(false);
23
+ const [showUpgradeAppModal, setShowUpgradeAppModal] = React.useState(false);
24
+
25
+ const disable = () => {
26
+ FluxoClientSys.Instance.apps.deactivateApp(props.app.id).then(() => {
27
+ showNotification({
28
+ title: 'Operazione completata',
29
+ message: `L'applicazione (${props.app.name} - ${props.app.version}) è stata disattivata con successo`,
30
+ color: 'green',
31
+ })
32
+ props.onDeactivate?.(props.app);
33
+ }).catch((err) => {
34
+ showNotification({
35
+ title: 'Operazione fallita',
36
+ message: `L'applicazione (${props.app.name} - ${props.app.version}) non è stata disattivata: ${err.message}`,
37
+ color: 'red',
38
+ })
39
+ })
40
+ }
41
+
42
+ const enable = () => {
43
+ FluxoClientSys.Instance.apps.activateApp(props.app.id).then(() => {
44
+ showNotification({
45
+ title: 'Operazione completata',
46
+ message: `L'applicazione (${props.app.name} - ${props.app.version}) è stata attivata con successo`,
47
+ color: 'green',
48
+ })
49
+ props.onActivate?.(props.app);
50
+ }).catch((err) => {
51
+ showNotification({
52
+ title: 'Operazione fallita',
53
+ message: `L'applicazione (${props.app.name} - ${props.app.version}) non è stata attivata: ${err.message}`,
54
+ color: 'red',
55
+ })
56
+ })
57
+ }
58
+
59
+ const uninstall = () => {
60
+ FluxoClientSys.Instance.apps.uninstallApp(props.app.id).then(() => {
61
+ showNotification({
62
+ title: 'Operazione completata',
63
+ message: `L'applicazione (${props.app.name} - ${props.app.version}) è stata disinstallata con successo`,
64
+ color: 'green',
65
+ })
66
+ props.onUninstall?.(props.app);
67
+ }).catch((err) => {
68
+ showNotification({
69
+ title: 'Operazione fallita',
70
+ message: `L'applicazione (${props.app.name} - ${props.app.version}) non è stata disinstallata: ${err.message}`,
71
+ color: 'red',
72
+ })
73
+ })
74
+ }
75
+
76
+ return (
77
+ <Group justify='space-between' style={{ border: '1px solid #dedede', padding: 15 }}>
78
+ <Group>
79
+ <Image src={`${props.pluginEndpoint}/${props.app.scope}/${props.app.name}/favicon.ico`} width={48} height={48} />
80
+ <Stack gap={0}>
81
+ <span>{props.app.description} <small>({props.app.version})</small></span>
82
+ <small>{props.app.name} - <b>{props.app.author}</b></small>
83
+ </Stack>
84
+ </Group>
85
+ <Group>
86
+
87
+ {props.app.state === AppState.Active ? <Badge color="green">Attivo</Badge> : <Badge color="red">Disattivo</Badge>}
88
+ <Badge color={props.app.type === AppType.Frontend ? 'orange' : 'violet'}>{props.app.type === AppType.Frontend ? 'Frontend' : 'Backend'}</Badge>
89
+ <Badge color={'gray'}>{moment(props.app.installationDate).format("DD/MM/yyyy")}</Badge>
90
+
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 leftSection={<IconCircleOff size={14} />} onClick={props.app.state == AppState.Active ? disable : enable}>
98
+ {props.app.state == AppState.Active ? 'Disattiva' : 'Attiva'}
99
+ </Menu.Item>
100
+ <Menu.Item onClick={() => setShowUpgradeAppModal(true)} leftSection={<IconArrowUp color={'green'} size={14} />}>Aggiorna</Menu.Item>
101
+ <Menu.Divider />
102
+ <Menu.Item color={'red'} onClick={() => setShowDeleteModal(true)} leftSection={<IconTrash color={'red'} size={14} />}>Disinstalla</Menu.Item>
103
+ </Menu.Dropdown>
104
+ </Menu>
105
+ </Group>
106
+
107
+ <ConfirmModal
108
+ title={'Disinstalla app'}
109
+ open={showDeleteModal}
110
+ onButtonCancelClick={() => setShowDeleteModal(false)}
111
+ onButtonConfirmClick={() => {
112
+ setShowDeleteModal(false);
113
+ uninstall();
114
+ }}
115
+ messageText={'Sei sicuro di voler disinstallare l\'applicazione?'}
116
+ />
117
+
118
+ <ConfirmModal
119
+ title={'Attiva app'}
120
+ open={showActivateModal}
121
+ onButtonCancelClick={() => setShowActivateModal(false)}
122
+ onButtonConfirmClick={() => {
123
+ setShowActivateModal(false);
124
+ enable();
125
+ }}
126
+ messageText={'Sei sicuro di voler attivare l\'applicazione?'}
127
+ />
128
+
129
+ <ConfirmModal
130
+ title={'Attiva app'}
131
+ open={showDeactivateModal}
132
+ onButtonCancelClick={() => setShowDeactivateModale(false)}
133
+ onButtonConfirmClick={() => {
134
+ setShowDeactivateModale(false);
135
+ disable();
136
+ }}
137
+ messageText={'Sei sicuro di voler attivare l\'applicazione?'}
138
+ />
139
+
140
+ {
141
+ <Modal centered title={'Aggiornamento app'} opened={showUpgradeAppModal} onClose={() => setShowUpgradeAppModal(false)}>
142
+ <Stack>
143
+ <Text>Procedura di aggiornamento dell'app {props.app.name}</Text>
144
+ <InstallOrUpgradeApp mode={'upgrade'} appIdToUpgrade={props.app.id} onInstall={() => {
145
+ setShowUpgradeAppModal(false);
146
+ props.onUpgrade?.(props.app);
147
+ }} />
148
+ <Group justify={'right'}>
149
+ <Button onClick={() => setShowUpgradeAppModal(false)}>Annulla</Button>
150
+ </Group>
151
+ </Stack>
152
+ </Modal>
153
+ }
154
+
155
+ </Group>
156
+ )
157
+ }