@topconsultnpm/sdkui-react-beta 6.16.16 → 6.16.18
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/components/choosers/TMGroupChooser.js +1 -1
- package/lib/components/choosers/TMUserChooser.js +8 -1
- package/lib/components/features/workflow/diagram/RecipientList.d.ts +27 -0
- package/lib/components/features/workflow/diagram/RecipientList.js +172 -0
- package/lib/components/features/workflow/diagram/WorkitemRecipientsEditor.d.ts +0 -14
- package/lib/components/features/workflow/diagram/WorkitemRecipientsEditor.js +84 -268
- package/lib/components/forms/TMChooserForm.js +2 -2
- package/lib/helper/SDKUI_Localizator.d.ts +1 -1
- package/lib/helper/SDKUI_Localizator.js +8 -8
- package/package.json +1 -1
|
@@ -33,5 +33,5 @@ export const TMGroupIdViewer = (props) => {
|
|
|
33
33
|
if (!group) {
|
|
34
34
|
return _jsx("span", { children: SDKUI_Localizator.NoDataToDisplay });
|
|
35
35
|
}
|
|
36
|
-
return _jsxs("span", { children: [props.showIcon && _jsx(IconUserGroup, { color: '#767676',
|
|
36
|
+
return (_jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '4px' }, children: [props.showIcon && _jsx(IconUserGroup, { color: '#767676' }), _jsx("span", { children: group.name })] }));
|
|
37
37
|
};
|
|
@@ -76,7 +76,14 @@ export const TMUserIdViewer = ({ userId, showIcon = false, noneSelectionText = `
|
|
|
76
76
|
return undefined;
|
|
77
77
|
return ud ? getCompleteUserName(ud.domain, ud.name) : userId.toString() ?? noneSelectionText;
|
|
78
78
|
};
|
|
79
|
-
return (_jsxs(
|
|
79
|
+
return (_jsxs("span", { style: { display: 'flex', alignItems: 'center', gap: '4px' }, children: [getIcon(), _jsx("span", { children: getDescription() })] })
|
|
80
|
+
// <StyledDivHorizontal>
|
|
81
|
+
// {getIcon()}
|
|
82
|
+
// <p style={{ textAlign: 'left', marginLeft: showIcon ? '5px' : '', opacity: ud ? 1 : 0.5 }}>
|
|
83
|
+
// {getDescription()}
|
|
84
|
+
// </p>
|
|
85
|
+
// </StyledDivHorizontal>
|
|
86
|
+
);
|
|
80
87
|
};
|
|
81
88
|
export const TMUserIcon = ({ ud }) => {
|
|
82
89
|
if (!ud)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { QueryDescriptor } from '@topconsultnpm/sdk-ts-beta';
|
|
3
|
+
export declare enum WorkItemActorTypes {
|
|
4
|
+
None = 0,
|
|
5
|
+
UID = 1,
|
|
6
|
+
GID = 2,
|
|
7
|
+
MID = 3,
|
|
8
|
+
QID = 4,
|
|
9
|
+
FXID = 5,
|
|
10
|
+
STID = 6
|
|
11
|
+
}
|
|
12
|
+
export interface WorkItemActor {
|
|
13
|
+
ActorType: WorkItemActorTypes;
|
|
14
|
+
ActorID: string;
|
|
15
|
+
Or: number;
|
|
16
|
+
}
|
|
17
|
+
interface RecipientListProps {
|
|
18
|
+
recipients: WorkItemActor[];
|
|
19
|
+
title: string;
|
|
20
|
+
tid?: number;
|
|
21
|
+
qd?: QueryDescriptor;
|
|
22
|
+
onQDChange?: (newQd: QueryDescriptor | undefined) => void;
|
|
23
|
+
onAdd: (recipient: WorkItemActor[]) => void;
|
|
24
|
+
onRemove: (recipient: WorkItemActor) => void;
|
|
25
|
+
}
|
|
26
|
+
declare const RecipientList: React.FC<RecipientListProps>;
|
|
27
|
+
export default RecipientList;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useState } from 'react';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import TMButton from '../../../base/TMButton';
|
|
5
|
+
import { IconAdd, IconDelete, SDKUI_Localizator } from '../../../../helper';
|
|
6
|
+
import { TMUserChooserForm, TMUserIdViewer } from '../../../choosers/TMUserChooser';
|
|
7
|
+
import { TMGroupChooserForm, TMGroupIdViewer } from '../../../choosers/TMGroupChooser';
|
|
8
|
+
import { TMMidViewer } from '../../../viewers/TMMidViewer';
|
|
9
|
+
import { SDK_Globals, SDK_Localizator } from '@topconsultnpm/sdk-ts-beta';
|
|
10
|
+
import { useOutsideClick } from '../../../../hooks/useOutsideClick';
|
|
11
|
+
import { FormModes } from '../../../../ts';
|
|
12
|
+
import { TMMessageBoxManager, ButtonNames } from '../../../base/TMPopUp';
|
|
13
|
+
import TMModal from '../../../base/TMModal';
|
|
14
|
+
import { TMMetadataChooserForm } from '../../../choosers/TMMetadataChooser';
|
|
15
|
+
import TMQueryEditor from '../../../query/TMQueryEditor';
|
|
16
|
+
export var WorkItemActorTypes;
|
|
17
|
+
(function (WorkItemActorTypes) {
|
|
18
|
+
WorkItemActorTypes[WorkItemActorTypes["None"] = 0] = "None";
|
|
19
|
+
WorkItemActorTypes[WorkItemActorTypes["UID"] = 1] = "UID";
|
|
20
|
+
WorkItemActorTypes[WorkItemActorTypes["GID"] = 2] = "GID";
|
|
21
|
+
WorkItemActorTypes[WorkItemActorTypes["MID"] = 3] = "MID";
|
|
22
|
+
WorkItemActorTypes[WorkItemActorTypes["QID"] = 4] = "QID";
|
|
23
|
+
WorkItemActorTypes[WorkItemActorTypes["FXID"] = 5] = "FXID";
|
|
24
|
+
WorkItemActorTypes[WorkItemActorTypes["STID"] = 6] = "STID";
|
|
25
|
+
})(WorkItemActorTypes || (WorkItemActorTypes = {}));
|
|
26
|
+
const RecipientsColumn = styled.div `
|
|
27
|
+
flex: 1;
|
|
28
|
+
border: 1px solid #ccc;
|
|
29
|
+
border-radius: 5px;
|
|
30
|
+
padding: 10px;
|
|
31
|
+
min-width: 300px;
|
|
32
|
+
position: relative;
|
|
33
|
+
`;
|
|
34
|
+
const HeaderContainer = styled.div `
|
|
35
|
+
display: flex;
|
|
36
|
+
justify-content: space-between;
|
|
37
|
+
align-items: center;
|
|
38
|
+
position: relative;
|
|
39
|
+
margin-bottom: 10px;
|
|
40
|
+
`;
|
|
41
|
+
const RecipientItem = styled.div `
|
|
42
|
+
display: flex;
|
|
43
|
+
align-items: center;
|
|
44
|
+
gap: 5px;
|
|
45
|
+
`;
|
|
46
|
+
const FloatingMenu = styled.div `
|
|
47
|
+
position: absolute;
|
|
48
|
+
top: 100%; /* Si apre sotto il bottone */
|
|
49
|
+
right: 0; /* Allinea il bordo destro del menu con quello del genitore */
|
|
50
|
+
background-color: white;
|
|
51
|
+
border: 1px solid #ccc;
|
|
52
|
+
border-radius: 5px;
|
|
53
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
54
|
+
z-index: 10;
|
|
55
|
+
display: flex;
|
|
56
|
+
flex-direction: column; /* Disposizione verticale */
|
|
57
|
+
gap: 5px;
|
|
58
|
+
padding: 5px;
|
|
59
|
+
min-width: 150px;
|
|
60
|
+
transform: translateY(5px);
|
|
61
|
+
align-items: center; /* Centra i pulsanti orizzontalmente */
|
|
62
|
+
`;
|
|
63
|
+
const FloatingMenuButton = styled(TMButton) `
|
|
64
|
+
width: 100%; /* Rende i pulsanti interni larghi quanto il menu */
|
|
65
|
+
`;
|
|
66
|
+
const RecipientList = ({ recipients, title, tid, qd, onAdd, onRemove, onQDChange }) => {
|
|
67
|
+
const [uiState, setUiState] = useState({
|
|
68
|
+
isMenuOpen: false,
|
|
69
|
+
showUserChooser: false,
|
|
70
|
+
showGroupChooser: false,
|
|
71
|
+
showMetadataChooser: false,
|
|
72
|
+
showQdEditor: false,
|
|
73
|
+
});
|
|
74
|
+
const menuRef = useOutsideClick(() => setUiState(prevState => ({ ...prevState, isMenuOpen: false })));
|
|
75
|
+
const handleQdChosen = useCallback((newQd) => {
|
|
76
|
+
if (newQd) {
|
|
77
|
+
const recipientToAdd = {
|
|
78
|
+
ActorType: WorkItemActorTypes.QID,
|
|
79
|
+
ActorID: newQd.id ? newQd.id.toString() : '-1',
|
|
80
|
+
Or: 0,
|
|
81
|
+
};
|
|
82
|
+
onAdd([recipientToAdd]);
|
|
83
|
+
onQDChange?.(newQd);
|
|
84
|
+
}
|
|
85
|
+
setUiState(prevState => ({ ...prevState, showQdEditor: false }));
|
|
86
|
+
}, [onQDChange]);
|
|
87
|
+
const handleUserChosen = useCallback((IDs) => {
|
|
88
|
+
if (IDs && IDs.length > 0) {
|
|
89
|
+
const recipientsToAdd = IDs.map(id => ({
|
|
90
|
+
ActorType: WorkItemActorTypes.UID,
|
|
91
|
+
ActorID: id.toString(),
|
|
92
|
+
Or: 0
|
|
93
|
+
}));
|
|
94
|
+
onAdd(recipientsToAdd);
|
|
95
|
+
}
|
|
96
|
+
setUiState(prevState => ({ ...prevState, showUserChooser: false }));
|
|
97
|
+
}, []);
|
|
98
|
+
const handleGroupChosen = useCallback((IDs) => {
|
|
99
|
+
if (IDs && IDs.length > 0) {
|
|
100
|
+
const recipientsToAdd = IDs.map(id => ({
|
|
101
|
+
ActorType: WorkItemActorTypes.GID,
|
|
102
|
+
ActorID: id.toString(),
|
|
103
|
+
Or: 0
|
|
104
|
+
}));
|
|
105
|
+
onAdd(recipientsToAdd);
|
|
106
|
+
}
|
|
107
|
+
setUiState(prevState => ({ ...prevState, showGroupChooser: false }));
|
|
108
|
+
}, []);
|
|
109
|
+
const handleMetadataChosen = useCallback((IDs) => {
|
|
110
|
+
if (IDs && IDs.length > 0) {
|
|
111
|
+
const recipientsToAdd = IDs.map(item => ({
|
|
112
|
+
ActorType: WorkItemActorTypes.MID,
|
|
113
|
+
ActorID: item.mid ? item.mid.toString() : '0',
|
|
114
|
+
Or: 0
|
|
115
|
+
}));
|
|
116
|
+
onAdd(recipientsToAdd);
|
|
117
|
+
}
|
|
118
|
+
setUiState(prevState => ({ ...prevState, showMetadataChooser: false }));
|
|
119
|
+
}, []);
|
|
120
|
+
const handleAddClick = () => {
|
|
121
|
+
setUiState(prevState => ({ ...prevState, isMenuOpen: !prevState.isMenuOpen }));
|
|
122
|
+
};
|
|
123
|
+
const openChooser = useCallback((chooser) => {
|
|
124
|
+
setUiState(prevState => ({
|
|
125
|
+
...prevState,
|
|
126
|
+
isAndMenuOpen: false,
|
|
127
|
+
isOrMenuOpen: false,
|
|
128
|
+
[chooser]: true,
|
|
129
|
+
}));
|
|
130
|
+
}, []);
|
|
131
|
+
const openQdEditorFromMenu = useCallback(() => {
|
|
132
|
+
const hasExistingQd = recipients.some(r => r.ActorType === WorkItemActorTypes.QID);
|
|
133
|
+
if (hasExistingQd) {
|
|
134
|
+
TMMessageBoxManager.show({
|
|
135
|
+
buttons: [ButtonNames.OK],
|
|
136
|
+
title: SDK_Globals.appModule,
|
|
137
|
+
message: "Definire solo una query per i destinatari"
|
|
138
|
+
});
|
|
139
|
+
setUiState(prevState => ({ ...prevState, isAndMenuOpen: false, isOrMenuOpen: false }));
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
openChooser('showQdEditor');
|
|
143
|
+
}
|
|
144
|
+
}, [recipients, openChooser]);
|
|
145
|
+
const renderActorViewer = (recipient) => {
|
|
146
|
+
const actorId = parseInt(recipient.ActorID, 10);
|
|
147
|
+
switch (recipient.ActorType) {
|
|
148
|
+
case WorkItemActorTypes.UID:
|
|
149
|
+
return _jsx(TMUserIdViewer, { userId: actorId, showIcon: true });
|
|
150
|
+
case WorkItemActorTypes.GID:
|
|
151
|
+
return _jsx(TMGroupIdViewer, { groupID: actorId, showIcon: true });
|
|
152
|
+
case WorkItemActorTypes.MID:
|
|
153
|
+
return _jsx(TMMidViewer, { tid_mid: { tid: tid, mid: actorId }, showIcon: true });
|
|
154
|
+
case WorkItemActorTypes.QID:
|
|
155
|
+
return (_jsx("span", { onDoubleClick: () => openChooser('showQdEditor'), style: { cursor: 'pointer' }, children: SDKUI_Localizator.WorkflowGetRecipientsFromQuery }));
|
|
156
|
+
default:
|
|
157
|
+
return _jsxs("span", { children: [WorkItemActorTypes[recipient.ActorType], ": ", recipient.ActorID] });
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
const renderFloatingMenu = () => {
|
|
161
|
+
const menuItems = [
|
|
162
|
+
{ caption: SDK_Localizator.Users, onClick: () => openChooser('showUserChooser') },
|
|
163
|
+
{ caption: SDK_Localizator.Groups, onClick: () => openChooser('showGroupChooser') },
|
|
164
|
+
{ caption: SDK_Localizator.Metadata, onClick: () => openChooser('showMetadataChooser') },
|
|
165
|
+
{ caption: SDK_Localizator.Query, onClick: openQdEditorFromMenu },
|
|
166
|
+
];
|
|
167
|
+
return (_jsx(FloatingMenu, { ref: menuRef, children: menuItems.map((item, index) => (_jsx(FloatingMenuButton, { btnStyle: 'text', caption: item.caption, onClick: item.onClick }, index))) }));
|
|
168
|
+
};
|
|
169
|
+
return (_jsxs(RecipientsColumn, { children: [_jsxs(HeaderContainer, { children: [_jsx("p", { style: { fontWeight: 600 }, children: title }), _jsx(TMButton, { btnStyle: 'icon', caption: 'Aggiungi destinatario', icon: _jsx(IconAdd, {}), onClick: handleAddClick }), uiState.isMenuOpen && renderFloatingMenu()] }), _jsx("div", { style: { height: '150px', overflowY: 'auto', gap: '5px', display: 'flex', flexDirection: 'column' }, children: recipients.map((recipient, index) => (_jsxs(RecipientItem, { children: [_jsx(IconDelete, { color: '#c00', cursor: 'pointer', onClick: () => onRemove(recipient) }), renderActorViewer(recipient)] }, index))) }), uiState.showUserChooser && _jsx(TMUserChooserForm, { allowMultipleSelection: true, allowSorting: true, onClose: () => setUiState(prevState => ({ ...prevState, showUserChooser: false })), onChoose: (IDs) => handleUserChosen(IDs) }), uiState.showGroupChooser && _jsx(TMGroupChooserForm, { allowMultipleSelection: true, allowSorting: true, onClose: () => setUiState(prevState => ({ ...prevState, showGroupChooser: false })), onChoose: (IDs) => handleGroupChosen(IDs) }), uiState.showMetadataChooser && tid && _jsx(TMMetadataChooserForm, { allowMultipleSelection: true, allowSorting: true, tids: [tid], onClose: () => setUiState(prevState => ({ ...prevState, showMetadataChooser: false })), onChoose: (IDs) => handleMetadataChosen(IDs) }), uiState.showQdEditor &&
|
|
170
|
+
_jsx(TMModal, { title: SDKUI_Localizator.QueryDefine, onClose: () => setUiState(prevState => ({ ...prevState, showQdEditor: false })), children: _jsx(TMQueryEditor, { inputData: qd, formMode: FormModes.Update, onApplied: handleQdChosen, onClose: () => setUiState(prevState => ({ ...prevState, showQdEditor: false })) }) })] }));
|
|
171
|
+
};
|
|
172
|
+
export default RecipientList;
|
|
@@ -1,19 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { QueryDescriptor, WorkItemSetRules } from '@topconsultnpm/sdk-ts-beta';
|
|
3
|
-
export declare enum WorkItemActorTypes {
|
|
4
|
-
None = 0,
|
|
5
|
-
UID = 1,
|
|
6
|
-
GID = 2,
|
|
7
|
-
MID = 3,
|
|
8
|
-
QID = 4,
|
|
9
|
-
FXID = 5,
|
|
10
|
-
STID = 6
|
|
11
|
-
}
|
|
12
|
-
export interface WorkItemActor {
|
|
13
|
-
ActorType: WorkItemActorTypes;
|
|
14
|
-
ActorID: string;
|
|
15
|
-
Or: number;
|
|
16
|
-
}
|
|
17
3
|
interface WorkitemRecipientsEditorProps {
|
|
18
4
|
tos: string;
|
|
19
5
|
setRule: WorkItemSetRules | undefined;
|
|
@@ -1,287 +1,103 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useMemo, useState } from 'react';
|
|
2
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
3
3
|
import styled from 'styled-components';
|
|
4
|
-
import TMButton from '../../../base/TMButton';
|
|
5
|
-
import { IconAdd, IconMetadata, IconSavedQuery, IconUser, IconUserGroup, SDKUI_Localizator } from '../../../../helper'; // Importa anche IconAdd
|
|
6
|
-
import { TMUserChooserForm, TMUserIdViewer } from '../../../choosers/TMUserChooser';
|
|
7
|
-
import { TMGroupChooserForm, TMGroupIdViewer } from '../../../choosers/TMGroupChooser';
|
|
8
|
-
import { SDK_Globals, SDK_Localizator, WorkItemSetRules } from '@topconsultnpm/sdk-ts-beta';
|
|
9
|
-
import { TMMetadataChooserForm } from '../../../choosers/TMMetadataChooser';
|
|
10
|
-
import { FormModes } from '../../../../ts';
|
|
11
4
|
import TMDropDown from '../../../editors/TMDropDown';
|
|
12
|
-
import {
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import { ButtonNames, TMMessageBoxManager } from '../../../base/TMPopUp';
|
|
16
|
-
import { useOutsideClick } from '../../../../hooks/useOutsideClick';
|
|
17
|
-
export var WorkItemActorTypes;
|
|
18
|
-
(function (WorkItemActorTypes) {
|
|
19
|
-
WorkItemActorTypes[WorkItemActorTypes["None"] = 0] = "None";
|
|
20
|
-
WorkItemActorTypes[WorkItemActorTypes["UID"] = 1] = "UID";
|
|
21
|
-
WorkItemActorTypes[WorkItemActorTypes["GID"] = 2] = "GID";
|
|
22
|
-
WorkItemActorTypes[WorkItemActorTypes["MID"] = 3] = "MID";
|
|
23
|
-
WorkItemActorTypes[WorkItemActorTypes["QID"] = 4] = "QID";
|
|
24
|
-
WorkItemActorTypes[WorkItemActorTypes["FXID"] = 5] = "FXID";
|
|
25
|
-
WorkItemActorTypes[WorkItemActorTypes["STID"] = 6] = "STID";
|
|
26
|
-
})(WorkItemActorTypes || (WorkItemActorTypes = {}));
|
|
5
|
+
import { WorkItemSetRules } from '@topconsultnpm/sdk-ts-beta';
|
|
6
|
+
import RecipientList, { WorkItemActorTypes } from './RecipientList';
|
|
7
|
+
import { SDKUI_Localizator } from '../../../../helper';
|
|
27
8
|
const RecipientsContainer = styled.div `
|
|
28
9
|
display: flex;
|
|
29
10
|
gap: 20px;
|
|
30
|
-
/* padding: 10px 0px; */
|
|
31
11
|
flex-wrap: wrap;
|
|
32
12
|
`;
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
padding: 10px;
|
|
38
|
-
min-width: 300px;
|
|
39
|
-
position: relative;
|
|
40
|
-
`;
|
|
41
|
-
const HeaderContainer = styled.div `
|
|
42
|
-
display: flex;
|
|
43
|
-
justify-content: space-between;
|
|
44
|
-
align-items: center;
|
|
45
|
-
position: relative;
|
|
46
|
-
margin-bottom: 10px;
|
|
47
|
-
`;
|
|
48
|
-
const RecipientItem = styled.div `
|
|
49
|
-
display: flex;
|
|
50
|
-
align-items: center;
|
|
51
|
-
margin-bottom: 5px;
|
|
52
|
-
gap: 5px;
|
|
53
|
-
`;
|
|
54
|
-
const RecipientRemoveButton = styled.span `
|
|
55
|
-
cursor: pointer;
|
|
56
|
-
color: #c00;
|
|
57
|
-
font-weight: bold;
|
|
58
|
-
`;
|
|
59
|
-
const FloatingMenu = styled.div `
|
|
60
|
-
position: absolute;
|
|
61
|
-
top: 100%; /* Si apre sotto il bottone */
|
|
62
|
-
right: 0; /* Allinea il bordo destro del menu con quello del genitore */
|
|
63
|
-
background-color: white;
|
|
64
|
-
border: 1px solid #ccc;
|
|
65
|
-
border-radius: 5px;
|
|
66
|
-
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
67
|
-
z-index: 10;
|
|
68
|
-
display: flex;
|
|
69
|
-
flex-direction: column; /* Disposizione verticale */
|
|
70
|
-
gap: 5px;
|
|
71
|
-
padding: 5px;
|
|
72
|
-
min-width: 150px;
|
|
73
|
-
transform: translateY(5px);
|
|
74
|
-
align-items: center; /* Centra i pulsanti orizzontalmente */
|
|
75
|
-
`;
|
|
76
|
-
const FloatingMenuButton = styled(TMButton) `
|
|
77
|
-
width: 100%; /* Rende i pulsanti interni larghi quanto il menu */
|
|
78
|
-
`;
|
|
79
|
-
const WorkitemRecipientsEditor = ({ tos, setRule, qd, mTID, onTosChange, onQDChange, onSetRuleChange }) => {
|
|
80
|
-
const [isAndMenuOpen, setIsAndMenuOpen] = useState(false);
|
|
81
|
-
const [isOrMenuOpen, setIsOrMenuOpen] = useState(false);
|
|
82
|
-
const [showUserChooser, setShowUserChooser] = useState(false);
|
|
83
|
-
const [showGroupChooser, setShowGroupChooser] = useState(false);
|
|
84
|
-
// const [showFxChartChooser, setShowFxChartChooser] = useState(false);
|
|
85
|
-
const [showMetadataChooser, setShowMetadataChooser] = useState(false);
|
|
86
|
-
const [showQdEditor, setShowQdEditor] = useState(false);
|
|
87
|
-
const andMenuRef = useOutsideClick(() => {
|
|
88
|
-
setIsAndMenuOpen(false);
|
|
89
|
-
});
|
|
90
|
-
// Applica il custom hook per il menu OR
|
|
91
|
-
const orMenuRef = useOutsideClick(() => {
|
|
92
|
-
setIsOrMenuOpen(false);
|
|
93
|
-
});
|
|
94
|
-
// useEffect(() => {
|
|
95
|
-
// const handleClickOutside = (event: MouseEvent) => {
|
|
96
|
-
// // Controlla il menu AND
|
|
97
|
-
// if (isAndMenuOpen && andMenuRef.current && !andMenuRef.current.contains(event.target as Node) && andButtonRef.current && !andButtonRef.current.contains(event.target as Node)) {
|
|
98
|
-
// setIsAndMenuOpen(false);
|
|
99
|
-
// }
|
|
100
|
-
// // Controlla il menu OR
|
|
101
|
-
// if (isOrMenuOpen && orMenuRef.current && !orMenuRef.current.contains(event.target as Node) && orButtonRef.current && !orButtonRef.current.contains(event.target as Node)) {
|
|
102
|
-
// setIsOrMenuOpen(false);
|
|
103
|
-
// }
|
|
104
|
-
// };
|
|
105
|
-
// // Aggiungi l'event listener se un menu è aperto
|
|
106
|
-
// if (isAndMenuOpen || isOrMenuOpen) {
|
|
107
|
-
// document.addEventListener('mousedown', handleClickOutside);
|
|
108
|
-
// }
|
|
109
|
-
// // Pulisci l'event listener
|
|
110
|
-
// return () => {
|
|
111
|
-
// document.removeEventListener('mousedown', handleClickOutside);
|
|
112
|
-
// };
|
|
113
|
-
// }, [isAndMenuOpen, isOrMenuOpen]);
|
|
114
|
-
// useEffect(() => {
|
|
115
|
-
// const handleKeyDown = (event: KeyboardEvent) => {
|
|
116
|
-
// if (event.key === 'Escape') {
|
|
117
|
-
// if (isAndMenuOpen) {
|
|
118
|
-
// setIsAndMenuOpen(false);
|
|
119
|
-
// event.stopPropagation(); // Ferma la propagazione per non chiudere anche il modale
|
|
120
|
-
// } else if (isOrMenuOpen) {
|
|
121
|
-
// setIsOrMenuOpen(false);
|
|
122
|
-
// event.stopPropagation(); // Ferma la propagazione per non chiudere anche il modale
|
|
123
|
-
// }
|
|
124
|
-
// }
|
|
125
|
-
// };
|
|
126
|
-
// if (isAndMenuOpen || isOrMenuOpen) {
|
|
127
|
-
// document.addEventListener('keydown', handleKeyDown);
|
|
128
|
-
// }
|
|
129
|
-
// return () => {
|
|
130
|
-
// document.removeEventListener('keydown', handleKeyDown);
|
|
131
|
-
// };
|
|
132
|
-
// }, [isAndMenuOpen, isOrMenuOpen]);
|
|
133
|
-
const parseTos = (tosString) => {
|
|
134
|
-
const andRecipients = [];
|
|
135
|
-
const orRecipients = [];
|
|
136
|
-
if (!tosString)
|
|
137
|
-
return { andRecipients, orRecipients };
|
|
138
|
-
const tokens1 = tosString.split(';');
|
|
139
|
-
for (const t of tokens1) {
|
|
140
|
-
const t1 = t.trim();
|
|
141
|
-
if (!t1)
|
|
142
|
-
continue;
|
|
143
|
-
const tokens2 = t1.split('|');
|
|
144
|
-
if (tokens2.length < 2)
|
|
145
|
-
continue;
|
|
146
|
-
const actorTypeStr = tokens2[0].toUpperCase();
|
|
147
|
-
const actorType = WorkItemActorTypes[actorTypeStr];
|
|
148
|
-
const actorID = tokens2[1];
|
|
149
|
-
const or = tokens2.length === 3 ? parseInt(tokens2[2], 10) : 0;
|
|
150
|
-
if (actorType !== undefined) {
|
|
151
|
-
const actor = {
|
|
152
|
-
ActorType: actorType,
|
|
153
|
-
ActorID: actorID,
|
|
154
|
-
Or: or,
|
|
155
|
-
};
|
|
156
|
-
if (or === 0) {
|
|
157
|
-
andRecipients.push(actor);
|
|
158
|
-
}
|
|
159
|
-
else {
|
|
160
|
-
orRecipients.push(actor);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
13
|
+
const tosToActors = (tosString) => {
|
|
14
|
+
const andRecipients = [];
|
|
15
|
+
const orRecipients = [];
|
|
16
|
+
if (!tosString)
|
|
164
17
|
return { andRecipients, orRecipients };
|
|
165
|
-
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
ActorType: WorkItemActorTypes.UID,
|
|
190
|
-
ActorID: id.toString(),
|
|
191
|
-
Or: orValue
|
|
192
|
-
}));
|
|
193
|
-
handleAddRecipients(recipientsToAdd);
|
|
194
|
-
}
|
|
195
|
-
setShowUserChooser(false);
|
|
196
|
-
};
|
|
197
|
-
const handleGroupChosen = (IDs, orValue) => {
|
|
198
|
-
if (IDs && IDs.length > 0) {
|
|
199
|
-
const recipientsToAdd = IDs.map(id => ({
|
|
200
|
-
ActorType: WorkItemActorTypes.GID,
|
|
201
|
-
ActorID: id.toString(),
|
|
202
|
-
Or: orValue
|
|
203
|
-
}));
|
|
204
|
-
handleAddRecipients(recipientsToAdd);
|
|
205
|
-
}
|
|
206
|
-
setShowGroupChooser(false);
|
|
207
|
-
};
|
|
208
|
-
const handleMetadataChosen = (IDs, orValue) => {
|
|
209
|
-
if (IDs && IDs.length > 0) {
|
|
210
|
-
const recipientsToAdd = IDs.map(id => ({
|
|
211
|
-
ActorType: WorkItemActorTypes.MID,
|
|
212
|
-
ActorID: id.mid ? id.mid.toString() : '0',
|
|
213
|
-
Or: orValue
|
|
214
|
-
}));
|
|
215
|
-
handleAddRecipients(recipientsToAdd);
|
|
18
|
+
const tokens1 = tosString.split(';');
|
|
19
|
+
for (const t of tokens1) {
|
|
20
|
+
const t1 = t.trim();
|
|
21
|
+
if (!t1)
|
|
22
|
+
continue;
|
|
23
|
+
const tokens2 = t1.split('|');
|
|
24
|
+
if (tokens2.length < 2)
|
|
25
|
+
continue;
|
|
26
|
+
const actorTypeStr = tokens2[0].toUpperCase();
|
|
27
|
+
const actorType = WorkItemActorTypes[actorTypeStr];
|
|
28
|
+
const actorID = tokens2[1];
|
|
29
|
+
const or = tokens2.length === 3 ? parseInt(tokens2[2], 10) : 0;
|
|
30
|
+
if (actorType !== undefined) {
|
|
31
|
+
const actor = {
|
|
32
|
+
ActorType: actorType,
|
|
33
|
+
ActorID: actorID,
|
|
34
|
+
Or: or,
|
|
35
|
+
};
|
|
36
|
+
if (or === 0) {
|
|
37
|
+
andRecipients.push(actor);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
orRecipients.push(actor);
|
|
41
|
+
}
|
|
216
42
|
}
|
|
217
|
-
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
43
|
+
}
|
|
44
|
+
return { andRecipients, orRecipients };
|
|
45
|
+
};
|
|
46
|
+
const actorsToTos = (actors) => {
|
|
47
|
+
return actors.map(actor => `${WorkItemActorTypes[actor.ActorType]}|${actor.ActorID}|${actor.Or}`).join(';');
|
|
48
|
+
};
|
|
49
|
+
const WorkitemRecipientsEditor = ({ tos, setRule, qd, mTID, onTosChange, onQDChange, onSetRuleChange }) => {
|
|
50
|
+
const [localTos, setLocalTos] = useState(tos);
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
setLocalTos(tos);
|
|
53
|
+
}, [tos]);
|
|
54
|
+
const handleAddRecipients = useCallback((newRecipients, orValue) => {
|
|
55
|
+
setLocalTos(prevTos => {
|
|
56
|
+
const { andRecipients, orRecipients } = tosToActors(prevTos);
|
|
57
|
+
let allRecipients = [...andRecipients, ...orRecipients];
|
|
58
|
+
// 1. Rimuovi qualsiasi QID esistente se il nuovo destinatario è una query
|
|
59
|
+
if (newRecipients.length > 0 && newRecipients[0].ActorType === WorkItemActorTypes.QID) {
|
|
60
|
+
allRecipients = allRecipients.filter(r => r.ActorType !== WorkItemActorTypes.QID);
|
|
61
|
+
}
|
|
62
|
+
const updatedRecipients = [...allRecipients, ...newRecipients.map(r => ({ ...r, Or: orValue }))];
|
|
63
|
+
const newTos = actorsToTos(updatedRecipients);
|
|
64
|
+
onTosChange(newTos);
|
|
65
|
+
return newTos;
|
|
66
|
+
});
|
|
67
|
+
}, [onTosChange, onQDChange]);
|
|
68
|
+
const handleRemoveRecipient = useCallback((recipientToRemove) => {
|
|
69
|
+
setLocalTos(prevTos => {
|
|
70
|
+
const { andRecipients, orRecipients } = tosToActors(prevTos);
|
|
222
71
|
const allRecipients = [...andRecipients, ...orRecipients];
|
|
223
|
-
const updatedRecipients = allRecipients.filter(r => r.ActorType !==
|
|
224
|
-
// 2. Crea il nuovo destinatario QID
|
|
225
|
-
const recipientToAdd = {
|
|
226
|
-
ActorType: WorkItemActorTypes.QID,
|
|
227
|
-
ActorID: newQd.id ? newQd.id.toString() : '-1',
|
|
228
|
-
Or: orValue
|
|
229
|
-
};
|
|
230
|
-
// 3. Aggiungi il nuovo destinatario alla lista
|
|
231
|
-
updatedRecipients.push(recipientToAdd);
|
|
232
|
-
// 4. Converte la lista aggiornata in una stringa e aggiorna lo stato.
|
|
72
|
+
const updatedRecipients = allRecipients.filter(r => r.ActorType !== recipientToRemove.ActorType || r.ActorID !== recipientToRemove.ActorID || r.Or !== recipientToRemove.Or);
|
|
233
73
|
const newTos = actorsToTos(updatedRecipients);
|
|
234
74
|
onTosChange(newTos);
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
};
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
const filteredRecipients = [...andRecipients, ...orRecipients].filter(r => r.ActorType === WorkItemActorTypes.QID);
|
|
258
|
-
if (filteredRecipients.length > 0) {
|
|
259
|
-
TMMessageBoxManager.show({
|
|
260
|
-
buttons: [ButtonNames.OK],
|
|
261
|
-
title: SDK_Globals.appModule,
|
|
262
|
-
message: "Definire solo una query per i destinatari"
|
|
263
|
-
});
|
|
264
|
-
setIsAndMenuOpen(false);
|
|
265
|
-
setIsOrMenuOpen(false);
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
setShowQdEditor(true);
|
|
269
|
-
};
|
|
270
|
-
const renderRecipientList = (recipients, title, orValue) => (_jsxs(RecipientsColumn, { children: [_jsxs(HeaderContainer, { children: [_jsx("p", { style: { fontWeight: 600 }, children: title }), _jsx(TMButton, { btnStyle: 'icon', caption: 'Aggiungi destinatario', icon: _jsx(IconAdd, {}), onClick: () => {
|
|
271
|
-
if (orValue === 0) {
|
|
272
|
-
setIsAndMenuOpen(prevState => !prevState);
|
|
273
|
-
setIsOrMenuOpen(false);
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
setIsOrMenuOpen(prevState => !prevState);
|
|
277
|
-
setIsAndMenuOpen(false);
|
|
278
|
-
}
|
|
279
|
-
} }), (orValue === 0 && isAndMenuOpen) && (_jsxs(FloatingMenu, { ref: andMenuRef, children: [_jsx(FloatingMenuButton, { btnStyle: 'text', icon: _jsx(IconUser, {}), caption: SDK_Localizator.Users, onClick: () => setShowUserChooser(true) }), _jsx(FloatingMenuButton, { btnStyle: 'text', icon: _jsx(IconUserGroup, {}), caption: SDK_Localizator.Groups, onClick: () => setShowGroupChooser(true) }), _jsx(FloatingMenuButton, { btnStyle: 'text', icon: _jsx(IconMetadata, {}), caption: SDK_Localizator.Metadata, onClick: () => setShowMetadataChooser(true) }), _jsx(FloatingMenuButton, { btnStyle: 'text', icon: _jsx(IconSavedQuery, {}), caption: SDK_Localizator.Query, onClick: openQdEditor })] })), (orValue === 1 && isOrMenuOpen) && (_jsxs(FloatingMenu, { ref: orMenuRef, children: [_jsx(FloatingMenuButton, { btnStyle: 'text', icon: _jsx(IconUser, {}), caption: SDK_Localizator.Users, onClick: () => setShowUserChooser(true) }), _jsx(FloatingMenuButton, { btnStyle: 'text', icon: _jsx(IconUserGroup, {}), caption: SDK_Localizator.Groups, onClick: () => setShowGroupChooser(true) }), _jsx(FloatingMenuButton, { btnStyle: 'text', icon: _jsx(IconMetadata, {}), caption: SDK_Localizator.Metadata, onClick: () => setShowMetadataChooser(true) }), _jsx(FloatingMenuButton, { btnStyle: 'text', icon: _jsx(IconSavedQuery, {}), caption: SDK_Localizator.Query, onClick: openQdEditor })] }))] }), _jsx("div", { style: { height: '150px', overflowY: 'auto' }, children: recipients.map((recipient, index) => (_jsxs(RecipientItem, { children: [_jsx(RecipientRemoveButton, { onClick: () => handleRemoveRecipient(recipient), children: "\u274C" }), renderActorViewer(recipient)] }, index))) })] }));
|
|
75
|
+
if (recipientToRemove.ActorType === WorkItemActorTypes.QID) {
|
|
76
|
+
onQDChange(undefined);
|
|
77
|
+
}
|
|
78
|
+
return newTos;
|
|
79
|
+
});
|
|
80
|
+
}, [onTosChange, onQDChange]);
|
|
81
|
+
const { andRecipients, orRecipients } = useMemo(() => {
|
|
82
|
+
return tosToActors(localTos);
|
|
83
|
+
}, [localTos]);
|
|
84
|
+
const handleQDChosen = useCallback((newQd, orValue) => {
|
|
85
|
+
const allRecipients = [...andRecipients, ...orRecipients];
|
|
86
|
+
const updatedRecipients = allRecipients.filter(r => r.ActorType !== WorkItemActorTypes.QID);
|
|
87
|
+
const recipientToAdd = {
|
|
88
|
+
ActorType: WorkItemActorTypes.QID,
|
|
89
|
+
ActorID: newQd.id ? newQd.id.toString() : '-1',
|
|
90
|
+
Or: orValue,
|
|
91
|
+
};
|
|
92
|
+
updatedRecipients.push(recipientToAdd);
|
|
93
|
+
const newTos = actorsToTos(updatedRecipients);
|
|
94
|
+
onTosChange(newTos);
|
|
95
|
+
onQDChange(newQd);
|
|
96
|
+
}, [andRecipients, orRecipients, onTosChange, onQDChange]);
|
|
280
97
|
const SET_RULE_DATASOURCE = [
|
|
281
98
|
{ value: WorkItemSetRules.Ands_AND_Ors, display: "Ands_AND_Ors" },
|
|
282
99
|
{ value: WorkItemSetRules.Ands_OR_Ors, display: "Ands_OR_Ors" }
|
|
283
100
|
];
|
|
284
|
-
return (_jsxs("div", { children: [_jsxs(RecipientsContainer, { children: [
|
|
285
|
-
_jsx(TMModal, { title: SDKUI_Localizator.QueryDefine, children: _jsx(TMQueryEditor, { inputData: qd, formMode: FormModes.Update, onApplied: (newQd) => handleQdChosen(newQd, isAndMenuOpen ? 0 : 1), onClose: () => { setShowQdEditor(false); } }) })] }));
|
|
101
|
+
return (_jsxs("div", { children: [_jsxs(RecipientsContainer, { children: [_jsx(RecipientList, { recipients: andRecipients, title: "Destinatari in AND", tid: mTID, qd: qd, onQDChange: (newQd) => newQd && handleQDChosen(newQd, 0), onAdd: (newRecipients) => handleAddRecipients(newRecipients, 0), onRemove: handleRemoveRecipient }), _jsx(RecipientList, { recipients: orRecipients, title: "Destinatari in OR", tid: mTID, qd: qd, onQDChange: (newQd) => newQd && handleQDChosen(newQd, 1), onAdd: (newRecipients) => handleAddRecipients(newRecipients, 1), onRemove: handleRemoveRecipient })] }), _jsx("div", { style: { display: 'flex', justifyContent: 'center' }, children: _jsx(TMDropDown, { label: SDKUI_Localizator.WorkflowRecipientSetRule, width: '230px', dataSource: SET_RULE_DATASOURCE, value: setRule, onValueChanged: (e) => { onSetRuleChange?.(e.target.value); } }) })] }));
|
|
286
102
|
};
|
|
287
103
|
export default WorkitemRecipientsEditor;
|
|
@@ -86,8 +86,8 @@ const TMChooserForm = ({ children, title, allowMultipleSelection = false, allowA
|
|
|
86
86
|
...summaryItems ?? {}
|
|
87
87
|
});
|
|
88
88
|
}, [manageUseLocalizedName, summaryItems]);
|
|
89
|
-
return (_jsx(TMModal, { title: renderTitle(), width: width ?? '550px', height: height ?? '600px', toolbar: _jsx(ToolbarButtons, {}), onClose: onClose, children:
|
|
90
|
-
filteredItems.length > 0
|
|
89
|
+
return (_jsx(TMModal, { title: renderTitle(), width: width ?? '550px', height: height ?? '600px', toolbar: _jsx(ToolbarButtons, {}), onClose: onClose, children: children ??
|
|
90
|
+
filteredItems.length > 0
|
|
91
91
|
? _jsx(TMDataGrid, { dataSource: filteredItems, keyExpr: keyName, dataColumns: dataColumns, focusedRowKey: focusedRowKey, selectedRowKeys: selectedRowKeys, searchPanelFocusStarting: true, headerFilter: { visible: true }, selection: { mode: allowMultipleSelection ? 'multiple' : 'single', showCheckBoxesMode: 'always', selectAllMode: 'allPages' }, grouping: allowGrouping ? { autoExpandAll: false, expandMode: 'rowClick' } : undefined, summary: customSummary, onFocusedRowChanged: handleFocusedRowChange, onSelectionChanged: handleSelectionChanged, onRowDblClick: handleRowDoubleClick })
|
|
92
92
|
: _jsx(TMLayoutContainer, { gap: 30, alignItems: 'center', justifyContent: 'center', children: _jsx(TMLayoutItem, { children: _jsx("p", { style: { height: "100%", color: TMColors.primaryColor, fontSize: "1.5rem", display: 'flex', alignItems: 'center', justifyContent: 'center' }, children: SDKUI_Localizator.NoDataToDisplay }) }) }) }));
|
|
93
93
|
};
|
|
@@ -440,7 +440,7 @@ export declare class SDKUI_Localizator {
|
|
|
440
440
|
static get SelectAnOperationBetween(): "Wählen Sie eine Operation zwischen" | "Select an operation between" | "Selecciona una operación entre" | "Sélectionnez une opération entre" | "Selecione uma operação entre" | "Seleziona un'operazione tra";
|
|
441
441
|
static get SelectArchiveToStart(): "Klicken Sie auf Archivieren, um zu beginnen." | "Click on Archive button to start." | "Haz clic en el botón Archivar para comenzar." | "Cliquez sur le bouton Archiver pour commencer." | "Clique no botão Arquivar para iniciar." | "Clicca sul pulsante Archivia per iniziare.";
|
|
442
442
|
static get SelectAttachToStart(): "Sie können Dateien zu Ihrer E-Mail hinzufügen, klicken Sie auf Anhängen, um zu beginnen." | "You can attach files to your email, click on Attach button to start." | "Puedes adjuntar archivos a tu correo electrónico, haz clic en el botón Adjuntar para comenzar." | "Vous pouvez joindre des fichiers à votre e-mail, cliquez sur le bouton Joindre pour commencer." | "Você pode anexar arquivos ao seu e-mail, clique no botão Anexar para iniciar." | "Puoi allegare file alla tua email, clicca sul pulsante Allega per iniziare.";
|
|
443
|
-
static get
|
|
443
|
+
static get SelectFromAttachments(): "Aus Anhängen auswählen" | "Select from attachments" | "Seleccionar de archivos adjuntos" | "Sélectionner parmi les pièces jointes" | "Selecionar dos anexos" | "Seleziona dagli allegati";
|
|
444
444
|
static get SelectSupportAreaMessage(): "Wählen Sie einen Ablagebereich aus" | "Select a support area" | "Seleccione un área de apoyo" | "Sélectionnez une zone de support" | "Selecione uma área de apoio" | "Selezionare un'area di appoggio";
|
|
445
445
|
static get SelectedSingular(): string;
|
|
446
446
|
static get Selected(): "Ausgewählt" | "Selected" | "Sélectionné" | "Selecionado" | "Seleccionados" | "Selezionati";
|
|
@@ -4364,14 +4364,14 @@ export class SDKUI_Localizator {
|
|
|
4364
4364
|
default: return "Puoi allegare file alla tua email, clicca sul pulsante Allega per iniziare.";
|
|
4365
4365
|
}
|
|
4366
4366
|
}
|
|
4367
|
-
static get
|
|
4368
|
-
switch (this._cultureID) {
|
|
4369
|
-
case CultureIDs.De_DE: return "
|
|
4370
|
-
case CultureIDs.En_US: return "
|
|
4371
|
-
case CultureIDs.Es_ES: return "
|
|
4372
|
-
case CultureIDs.Fr_FR: return "
|
|
4373
|
-
case CultureIDs.Pt_PT: return "
|
|
4374
|
-
default: return "
|
|
4367
|
+
static get SelectFromAttachments() {
|
|
4368
|
+
switch (this._cultureID) {
|
|
4369
|
+
case CultureIDs.De_DE: return "Aus Anhängen auswählen";
|
|
4370
|
+
case CultureIDs.En_US: return "Select from attachments";
|
|
4371
|
+
case CultureIDs.Es_ES: return "Seleccionar de archivos adjuntos";
|
|
4372
|
+
case CultureIDs.Fr_FR: return "Sélectionner parmi les pièces jointes";
|
|
4373
|
+
case CultureIDs.Pt_PT: return "Selecionar dos anexos";
|
|
4374
|
+
default: return "Seleziona dagli allegati";
|
|
4375
4375
|
}
|
|
4376
4376
|
}
|
|
4377
4377
|
static get SelectSupportAreaMessage() {
|