@topconsultnpm/sdkui-react 6.22.0-dev1.9 → 6.22.0-dev2.10

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 (52) hide show
  1. package/lib/components/base/TMButton.d.ts +13 -0
  2. package/lib/components/base/TMButton.js +137 -5
  3. package/lib/components/base/TMDataGridExportForm.js +39 -30
  4. package/lib/components/base/TMModal.js +1 -1
  5. package/lib/components/choosers/TMDynDataListItemChooser.d.ts +2 -0
  6. package/lib/components/choosers/TMDynDataListItemChooser.js +4 -6
  7. package/lib/components/editors/TMDateBox.d.ts +16 -1
  8. package/lib/components/editors/TMDateBox.js +90 -22
  9. package/lib/components/editors/TMMetadataEditor.d.ts +5 -1
  10. package/lib/components/editors/TMMetadataEditor.js +27 -23
  11. package/lib/components/editors/TMTextArea.d.ts +1 -0
  12. package/lib/components/editors/TMTextArea.js +23 -15
  13. package/lib/components/editors/TMTextBox.d.ts +2 -0
  14. package/lib/components/editors/TMTextBox.js +38 -22
  15. package/lib/components/features/documents/TMDcmtForm.d.ts +2 -1
  16. package/lib/components/features/documents/TMDcmtForm.js +107 -8
  17. package/lib/components/features/documents/TMRelationViewer.js +13 -32
  18. package/lib/components/features/search/TMSearch.d.ts +2 -1
  19. package/lib/components/features/search/TMSearch.js +31 -18
  20. package/lib/components/features/search/TMSearchQueryPanel.d.ts +1 -1
  21. package/lib/components/features/search/TMSearchQueryPanel.js +28 -7
  22. package/lib/components/features/search/TMSearchResult.d.ts +2 -1
  23. package/lib/components/features/search/TMSearchResult.js +16 -41
  24. package/lib/components/features/search/TMSignatureInfoContent.d.ts +4 -2
  25. package/lib/components/features/search/TMSignatureInfoContent.js +373 -79
  26. package/lib/components/forms/Login/TMLoginForm.d.ts +2 -0
  27. package/lib/components/forms/Login/TMLoginForm.js +17 -3
  28. package/lib/components/forms/Login/TextBox.d.ts +3 -0
  29. package/lib/components/forms/Login/TextBox.js +2 -2
  30. package/lib/components/pages/TMPage.js +3 -1
  31. package/lib/components/query/TMQueryEditor.js +1 -1
  32. package/lib/components/viewers/TMMidViewer.js +1 -1
  33. package/lib/helper/Globalization.d.ts +1 -1
  34. package/lib/helper/SDKUI_Globals.js +22 -2
  35. package/lib/helper/SDKUI_Localizator.d.ts +11 -0
  36. package/lib/helper/SDKUI_Localizator.js +110 -0
  37. package/lib/helper/TMUtils.d.ts +29 -1
  38. package/lib/helper/TMUtils.js +249 -10
  39. package/lib/helper/grafometricSignaturesCache.d.ts +45 -0
  40. package/lib/helper/grafometricSignaturesCache.js +56 -0
  41. package/lib/helper/helpers.d.ts +11 -0
  42. package/lib/helper/helpers.js +32 -0
  43. package/lib/helper/index.d.ts +1 -0
  44. package/lib/helper/index.js +1 -0
  45. package/lib/hooks/useDocumentOperations.d.ts +2 -1
  46. package/lib/hooks/useDocumentOperations.js +15 -15
  47. package/lib/hooks/usePreventFileDrop.js +14 -3
  48. package/lib/ts/graphometricTypes.d.ts +62 -0
  49. package/lib/ts/graphometricTypes.js +1 -0
  50. package/lib/ts/index.d.ts +1 -0
  51. package/lib/ts/index.js +1 -0
  52. package/package.json +7 -2
@@ -10,21 +10,10 @@ import TMTextBox from './TMTextBox';
10
10
  import { TMMetadataIcon } from '../viewers/TMMidViewer';
11
11
  import TMTextArea from './TMTextArea';
12
12
  import { DateDisplayTypes } from '../../helper/Globalization';
13
+ import { getCurrencySymbol, getDevExtremeDateDisplayFormat } from '../../helper/TMUtils';
13
14
  const renderMetadataIcon = (tid, md, layoutMode, isMetadataSelected, showLabel) => {
14
15
  return (_jsx(TMMetadataIcon, { isMetadataSelected: isMetadataSelected, layoutMode: layoutMode, md: md, tid: tid, elementStyle: showLabel ? { position: 'relative', top: '4px' } : undefined }));
15
16
  };
16
- const getDateDisplayFormat = (format) => {
17
- format = format ?? MetadataFormats.None;
18
- switch (format) {
19
- case MetadataFormats.LongTime: return "longTime";
20
- case MetadataFormats.ShortTime: return "shortTime";
21
- case MetadataFormats.ShortDateLongTime:
22
- case MetadataFormats.ShortDateShortTime:
23
- case MetadataFormats.LongDateLongTime:
24
- case MetadataFormats.LongDateShortTime: return "shortDateShortTime";
25
- default: return "shortDate";
26
- }
27
- };
28
17
  const getDateDisplayType = (format) => {
29
18
  format = format ?? MetadataFormats.None;
30
19
  switch (format) {
@@ -37,14 +26,26 @@ const getDateDisplayType = (format) => {
37
26
  default: return DateDisplayTypes.Date;
38
27
  }
39
28
  };
40
- const TMMetadataEditor = ({ isSelected = false, customLabel, isReadOnly, isLexProt, layoutMode, queryOperator, isEditable, isModifiedWhen = false, tid, mid, value, queryParamsDynDataList, containerElement, autoFocus, validationItems = [], disabled = false, openChooserBySingleClick = true, onValueChanged, onValueChange, onCascadeRefreshDynDataLists, onCascadeUpdateMIDs, updateIsModalOpen }) => {
41
- const [md, setMd] = useState();
29
+ const getTextTransform = (format) => {
30
+ switch (format) {
31
+ case MetadataFormats.LowerCase: return 'lowercase';
32
+ case MetadataFormats.UpperCase: return 'uppercase';
33
+ default: return undefined;
34
+ }
35
+ };
36
+ const TMMetadataEditor = ({ isSelected = false, customLabel, isReadOnly, isLexProt, layoutMode, queryOperator, isEditable, isModifiedWhen = false, tid, mid, md: mdProp, value, queryParamsDynDataList, containerElement, autoFocus, validationItems = [], disabled = false, openChooserBySingleClick = true, onValueChanged, onValueChange, onCascadeRefreshDynDataLists, onCascadeUpdateMIDs, updateIsModalOpen }) => {
37
+ const [md, setMd] = useState(mdProp);
42
38
  useEffect(() => {
39
+ // Se il descriptor è fornito dall'esterno lo usiamo direttamente (es. metadati di copertina CaseFlow, non legati a un tipo documento).
40
+ if (mdProp) {
41
+ setMd(mdProp);
42
+ return;
43
+ }
43
44
  // Passiamo did = undefined, perché è già in cache
44
45
  DcmtTypeListCacheService.GetWithNotGrantedAsync(tid, undefined).then((dtd) => {
45
46
  setMd(dtd?.metadata?.find(o => o.id == mid));
46
47
  });
47
- }, [tid, mid]);
48
+ }, [tid, mid, mdProp]);
48
49
  const isReadOnlyInternal = () => {
49
50
  if (!md)
50
51
  return false;
@@ -104,23 +105,26 @@ const TMMetadataEditor = ({ isSelected = false, customLabel, isReadOnly, isLexPr
104
105
  else
105
106
  onValueChanged?.(IDs.join(","));
106
107
  }, updateIsModalOpen: updateIsModalOpen });
107
- if (showAsText)
108
- return _jsx(TMTextBox, { placeHolder: layoutMode === LayoutModes.Ark ? md?.defaultValue ?? '' : '', isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, label: (modulesWithLabelTop || showLabelTop) ? (customLabel ?? md?.nameLoc) : undefined, icon: showLabelTop ? icon : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'text', showClearButton: !isReadOnlyResult, maxLength: maxLength, autoFocus: autoFocus, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
109
- if (showAsNumber)
110
- return _jsx(TMTextBox, { placeHolder: layoutMode === LayoutModes.Ark ? md?.defaultValue ?? '' : '', isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, label: (modulesWithLabelTop || showLabelTop) ? (customLabel ?? md?.nameLoc) : undefined, icon: showLabelTop ? icon : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'number', showClearButton: !isReadOnlyResult, precision: md?.length, scale: md?.scale, autoFocus: autoFocus, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
108
+ if (showAsText) {
109
+ return _jsx(TMTextBox, { placeHolder: layoutMode === LayoutModes.Ark ? md?.defaultValue ?? '' : '', isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, label: (modulesWithLabelTop || showLabelTop) ? (customLabel ?? md?.nameLoc) : undefined, icon: showLabelTop ? icon : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'text', showClearButton: !isReadOnlyResult, maxLength: maxLength, autoFocus: autoFocus, value: value ?? '', textTransform: getTextTransform(md?.format?.format), onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
110
+ }
111
+ if (showAsNumber) {
112
+ return _jsx(TMTextBox, { placeHolder: layoutMode === LayoutModes.Ark ? md?.defaultValue ?? '' : '', isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, label: (modulesWithLabelTop || showLabelTop) ? (customLabel ?? md?.nameLoc) : undefined, icon: showLabelTop ? icon : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'number', showClearButton: !isReadOnlyResult, precision: md?.length, scale: md?.scale, autoFocus: autoFocus, value: value ?? '', currencySymbol: getCurrencySymbol(md?.format?.format), onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
113
+ }
111
114
  switch (md?.dataType) {
112
115
  case MetadataDataTypes.DateTime:
113
- return _jsx(TMDateBox, { placeholder: layoutMode === LayoutModes.Ark ? md?.defaultValue ?? '' : '', dateDisplayType: getDateDisplayType(md.format?.format), displayFormat: getDateDisplayFormat(md.format?.format), isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, icon: showLabelTop ? icon : undefined, label: (modulesWithLabelTop || showLabelTop) ? (customLabel ?? md?.nameLoc) : undefined, validationItems: validationItems, disabled: disabled, width: '100%', value: value, showClearButton: !isReadOnlyResult, useDateSerializationFormat: true, containerElement: containerElement, onValueChange: (newValue) => {
116
+ return _jsx(TMDateBox, { placeholder: layoutMode === LayoutModes.Ark ? md?.defaultValue ?? '' : '', dateDisplayType: getDateDisplayType(md.format?.format), displayFormat: getDevExtremeDateDisplayFormat(md.format?.format, md.format?.formatCulture), formatCulture: md.format?.formatCulture, metadataFormat: md.format?.format, isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, icon: showLabelTop ? icon : undefined, label: (modulesWithLabelTop || showLabelTop) ? (customLabel ?? md?.nameLoc) : undefined, validationItems: validationItems, disabled: disabled, width: '100%', value: value, showClearButton: !isReadOnlyResult, useDateSerializationFormat: true, containerElement: containerElement, onValueChange: (newValue) => {
114
117
  onValueChange?.(newValue ? newValue.toString() : undefined);
115
118
  onValueChanged?.(newValue ? newValue.toString() : undefined);
116
119
  } });
117
- case MetadataDataTypes.Number: return _jsx(TMTextBox, { placeHolder: layoutMode === LayoutModes.Ark ? md?.defaultValue ?? '' : '', isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, label: (modulesWithLabelTop || showLabelTop) ? (customLabel ?? md?.nameLoc) : undefined, icon: showLabelTop ? icon : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'number', showClearButton: !isReadOnlyResult, precision: md?.length, scale: md?.scale, autoFocus: autoFocus, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
120
+ case MetadataDataTypes.Number:
121
+ return _jsx(TMTextBox, { placeHolder: layoutMode === LayoutModes.Ark ? md?.defaultValue ?? '' : '', isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, label: (modulesWithLabelTop || showLabelTop) ? (customLabel ?? md?.nameLoc) : undefined, icon: showLabelTop ? icon : undefined, validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, type: 'number', showClearButton: !isReadOnlyResult, precision: md?.length, scale: md?.scale, autoFocus: autoFocus, value: value ?? '', currencySymbol: getCurrencySymbol(md?.format?.format), onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => onValueChanged?.(newValue) });
118
122
  default:
119
123
  if (showByTextarea) {
120
- return _jsx(TMTextArea, { placeHolder: layoutMode === LayoutModes.Ark ? md?.defaultValue ?? '' : '', rows: 1, readOnly: isReadOnlyResult, label: (modulesWithLabelTop || showLabelTop) ? (customLabel ?? md?.nameLoc) : undefined, icon: showLabelTop ? icon : undefined, isModifiedWhen: isModifiedWhenInternal(), validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, showClearButton: !isReadOnlyResult, autoFocus: autoFocus, maxLength: maxLength, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => { onValueChanged?.(newValue); }, resize: false });
124
+ return _jsx(TMTextArea, { placeHolder: layoutMode === LayoutModes.Ark ? md?.defaultValue ?? '' : '', rows: 1, readOnly: isReadOnlyResult, label: (modulesWithLabelTop || showLabelTop) ? (customLabel ?? md?.nameLoc) : undefined, icon: showLabelTop ? icon : undefined, isModifiedWhen: isModifiedWhenInternal(), validationItems: validationItems, disabled: disabled, elementStyle: { width: '100%' }, showClearButton: !isReadOnlyResult, autoFocus: autoFocus, maxLength: maxLength, value: value ?? '', textTransform: getTextTransform(md?.format?.format), onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => { onValueChanged?.(newValue); }, resize: false });
121
125
  }
122
126
  else {
123
- return _jsx(TMTextBox, { placeHolder: layoutMode === LayoutModes.Ark ? md?.defaultValue ?? '' : '', isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, label: (modulesWithLabelTop || showLabelTop) ? (customLabel ?? md?.nameLoc) : undefined, icon: showLabelTop ? icon : undefined, disabled: disabled, validationItems: validationItems, type: 'text', elementStyle: { width: '100%' }, showClearButton: !isReadOnlyResult, autoFocus: autoFocus, maxLength: maxLength, value: value ?? '', onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => { onValueChanged?.(newValue); } });
127
+ return _jsx(TMTextBox, { placeHolder: layoutMode === LayoutModes.Ark ? md?.defaultValue ?? '' : '', isModifiedWhen: isModifiedWhenInternal(), readOnly: isReadOnlyResult, label: (modulesWithLabelTop || showLabelTop) ? (customLabel ?? md?.nameLoc) : undefined, icon: showLabelTop ? icon : undefined, disabled: disabled, validationItems: validationItems, type: 'text', elementStyle: { width: '100%' }, showClearButton: !isReadOnlyResult, autoFocus: autoFocus, maxLength: maxLength, value: value ?? '', textTransform: getTextTransform(md?.format?.format), onValueChanged: (e) => onValueChange?.(e.target.value), onBlur: (newValue) => { onValueChanged?.(newValue); } });
124
128
  }
125
129
  }
126
130
  };
@@ -16,6 +16,7 @@ interface ITMTextArea extends ITMEditorBase {
16
16
  fillHeight?: boolean;
17
17
  name?: string;
18
18
  id?: string;
19
+ textTransform?: 'lowercase' | 'uppercase';
19
20
  }
20
21
  declare const TMTextArea: React.FunctionComponent<ITMTextArea>;
21
22
  export default TMTextArea;
@@ -28,7 +28,7 @@ const StyledTextAreaEditorButton = styled.div `
28
28
  // Define the TMTextArea component
29
29
  const TMTextArea = (props) => {
30
30
  // Extract properties from the props object
31
- const { label = '', value = '', width = '100%', height = 'auto', autoFocus = false, showClearButton, validationItems = [], disabled = false, isModifiedWhen = false, fontSize = FontSize.defaultFontSize, elementStyle = {}, icon = null, labelPosition = 'left', readOnly = false, onValueChanged, onBlur, placeHolder, formulaItems = [], buttons = [], maxHeight = 'auto', rows, maxLength, resize = true, autoCalculateRows = true, fillHeight = false, name, id } = props;
31
+ const { label = '', value = '', width = '100%', height = 'auto', autoFocus = false, showClearButton, validationItems = [], disabled = false, isModifiedWhen = false, fontSize = FontSize.defaultFontSize, elementStyle = {}, icon = null, labelPosition = 'left', readOnly = false, onValueChanged, onBlur, placeHolder, formulaItems = [], buttons = [], maxHeight = 'auto', rows, maxLength, resize = true, autoCalculateRows = true, fillHeight = false, name, id, textTransform } = props;
32
32
  // Generate a unique id if not provided
33
33
  const autoId = useId();
34
34
  const effectiveId = id ?? autoId;
@@ -151,20 +151,28 @@ const TMTextArea = (props) => {
151
151
  };
152
152
  // Renders the textarea
153
153
  const renderTextArea = () => {
154
- const textareaElement = _jsxs(_Fragment, { children: [_jsx(StyledTextareaEditor, { ref: inputRef, id: effectiveId, ...(name && { name }), autoFocus: autoFocus, readOnly: readOnly, disabled: disabled, value: currentValue, placeholder: placeHolder, rows: fillHeight ? undefined : calculatedRows, maxLength: maxLength, spellCheck: false, onFocus: () => setIsFocused(true), onBlur: (e) => { setIsFocused(false); if (currentValue != value)
155
- onBlur?.(currentValue); }, onChange: (e) => { setCurrentValue(e.target.value); onValueChanged?.(e); }, "$isMobile": deviceType === DeviceType.MOBILE, "$maxHeight": maxHeight, "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, "$fontSize": fontSize, "$width": width, "$resize": resize, style: fillHeight ? { flex: 1, height: 0 } : undefined }), _jsxs("div", { style: { display: 'flex', flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', position: 'absolute', right: '6px', top: calculatedRows === 1 ? (label.length > 0 ? '20px' : '7px') : (label.length > 0 ? '22px' : '7px'), pointerEvents: disabled ? 'none' : 'auto', opacity: disabled ? 0.4 : 1 }, children: [formulaItems.length > 0 &&
156
- _jsx(StyledTextAreaEditorButton, { onClick: () => {
157
- setShowFormulaItemsChooser(true);
158
- }, children: _jsx(IconDataList, {}) }), showClearButton && currentValue &&
159
- _jsx(StyledTextAreaEditorButton, { onClick: () => {
160
- onValueChanged?.({ target: { value: undefined } });
161
- setCurrentValue('');
162
- if (autoCalculateRows)
163
- setCalculatedRows(1);
164
- onBlur?.(undefined);
165
- }, children: _jsx(IconClearButton, {}) }), buttons.map((buttonItem, index) => {
166
- return (_jsx(StyledTextAreaEditorButton, { onClick: buttonItem.onClick, children: _jsx(TMTooltip, { content: buttonItem.text, children: buttonItem.icon }) }, buttonItem.text));
167
- })] }), openFormulaItemsChooser(), _jsx(TMVilViewer, { vil: validationItems })] });
154
+ const textareaElement = _jsxs(_Fragment, { children: [_jsxs("div", { style: { position: 'relative', ...(fillHeight ? { flex: 1, display: 'flex', flexDirection: 'column' } : {}) }, children: [_jsx(StyledTextareaEditor, { ref: inputRef, id: effectiveId, ...(name && { name }), autoFocus: autoFocus, readOnly: readOnly, disabled: disabled, value: currentValue, placeholder: placeHolder, rows: fillHeight ? undefined : calculatedRows, maxLength: maxLength, spellCheck: false, onFocus: () => setIsFocused(true), onBlur: (e) => { setIsFocused(false); if (currentValue != value)
155
+ onBlur?.(currentValue); }, onChange: (e) => {
156
+ let newValue = e.target.value;
157
+ if (textTransform === 'lowercase')
158
+ newValue = newValue.toLowerCase();
159
+ else if (textTransform === 'uppercase')
160
+ newValue = newValue.toUpperCase();
161
+ setCurrentValue(newValue);
162
+ onValueChanged?.({ ...e, target: { ...e.target, value: newValue } });
163
+ }, "$isMobile": deviceType === DeviceType.MOBILE, "$maxHeight": maxHeight, "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, "$fontSize": fontSize, "$width": width, "$resize": resize, style: fillHeight ? { flex: 1, height: 0 } : undefined }), _jsxs("div", { style: { display: 'flex', flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', position: 'absolute', right: '6px', top: '50%', transform: 'translateY(-50%)', pointerEvents: disabled ? 'none' : 'auto', opacity: disabled ? 0.4 : 1 }, children: [formulaItems.length > 0 &&
164
+ _jsx(StyledTextAreaEditorButton, { onClick: () => {
165
+ setShowFormulaItemsChooser(true);
166
+ }, children: _jsx(IconDataList, {}) }), showClearButton && currentValue &&
167
+ _jsx(StyledTextAreaEditorButton, { onClick: () => {
168
+ onValueChanged?.({ target: { value: undefined } });
169
+ setCurrentValue('');
170
+ if (autoCalculateRows)
171
+ setCalculatedRows(1);
172
+ onBlur?.(undefined);
173
+ }, children: _jsx(IconClearButton, {}) }), buttons.map((buttonItem, index) => {
174
+ return (_jsx(StyledTextAreaEditorButton, { onClick: buttonItem.onClick, children: _jsx(TMTooltip, { content: buttonItem.text, children: buttonItem.icon }) }, buttonItem.text));
175
+ })] })] }), openFormulaItemsChooser(), _jsx(TMVilViewer, { vil: validationItems })] });
168
176
  // Wrap with context menu if formula items exist
169
177
  if (formulaItems.length > 0) {
170
178
  return (_jsx(TMContextMenu, { items: getFormulaMenuItems(), trigger: "right", children: textareaElement }));
@@ -14,6 +14,8 @@ export interface ITMTextBox extends ITMEditorBase {
14
14
  value?: string | number;
15
15
  fromModal?: boolean;
16
16
  allowedPattern?: RegExp;
17
+ textTransform?: 'lowercase' | 'uppercase';
18
+ currencySymbol?: string;
17
19
  onClick?: () => void;
18
20
  onValueChanged?: (e: React.ChangeEvent<HTMLInputElement>) => void;
19
21
  onBlur?: (value: string | undefined) => void;
@@ -34,7 +34,7 @@ const StyledTextBoxEditorButton = styled.div `
34
34
  border-bottom-color: ${TMColors.primary};
35
35
  }
36
36
  `;
37
- const TMTextBox = ({ autoComplete = 'off', autoFocus, maxLength, labelColor, precision, fromModal = false, scale, showClearButton, validationItems = [], label = '', readOnly = false, formulaItems = [], buttons = [], isModifiedWhen, placeHolder, elementStyle, width = '100%', maxValue, minValue, fontSize = FontSize.defaultFontSize, icon, labelPosition = 'left', value, disabled = false, type = 'text', onClick, onValueChanged, onBlur, onKeyDown, borderRadius, allowedPattern }) => {
37
+ const TMTextBox = ({ autoComplete = 'off', autoFocus, maxLength, labelColor, precision, fromModal = false, scale, showClearButton, validationItems = [], label = '', readOnly = false, formulaItems = [], buttons = [], isModifiedWhen, placeHolder, elementStyle, width = '100%', maxValue, minValue, fontSize = FontSize.defaultFontSize, icon, labelPosition = 'left', value, disabled = false, type = 'text', onClick, onValueChanged, onBlur, onKeyDown, borderRadius, allowedPattern, textTransform, currencySymbol }) => {
38
38
  const [initialType, setInitialType] = useState(type);
39
39
  const [currentType, setCurrentType] = useState(type);
40
40
  const [currentValue, setCurrentValue] = useState(value);
@@ -151,6 +151,13 @@ const TMTextBox = ({ autoComplete = 'off', autoFocus, maxLength, labelColor, pre
151
151
  };
152
152
  const handleInputChange = (e) => {
153
153
  let inputValue = e.target.value;
154
+ // Applica textTransform direttamente durante la digitazione (non per i numeri)
155
+ if (currentType !== 'number') {
156
+ if (textTransform === 'lowercase')
157
+ inputValue = inputValue.toLowerCase();
158
+ else if (textTransform === 'uppercase')
159
+ inputValue = inputValue.toUpperCase();
160
+ }
154
161
  // Validazione generica con RegEx
155
162
  if (allowedPattern) {
156
163
  // Soluzione 1: Confronto diretto (preferibile per un singolo carattere)
@@ -257,14 +264,20 @@ const TMTextBox = ({ autoComplete = 'off', autoFocus, maxLength, labelColor, pre
257
264
  : currentValue ?? '';
258
265
  // Calcola il padding-right necessario per evitare sovrapposizione con i bottoni
259
266
  const calculateRightPadding = () => {
260
- if (initialType === 'password')
261
- return 10; // Solo l'icona show/hide password
262
267
  let buttonCount = 0;
263
268
  if (formulaItems.length > 0)
264
269
  buttonCount++; // IconDataList
265
270
  if (showClearButton && currentValue)
266
271
  buttonCount++; // IconClearButton
267
272
  buttonCount += buttons.length; // Custom buttons
273
+ const buttonWidth = 28;
274
+ if (initialType === 'password') {
275
+ // Solo l'occhiolino se il chiamante non passa bottoni custom (comportamento invariato)
276
+ if (buttonCount === 0)
277
+ return 10;
278
+ // Occhiolino a destra + bottoni custom alla sua sinistra
279
+ return 34 + (buttonCount * buttonWidth) + 8;
280
+ }
268
281
  if (currentType === 'number') {
269
282
  // Per i number, non aggiungiamo padding-right perché le freccette native
270
283
  // occupano già spazio. Se ci sono bottoni custom a sinistra delle freccette,
@@ -273,28 +286,31 @@ const TMTextBox = ({ autoComplete = 'off', autoFocus, maxLength, labelColor, pre
273
286
  }
274
287
  else {
275
288
  // Per gli altri tipi, calcolo normale
276
- const buttonWidth = 28;
277
289
  return 6 + (buttonCount * buttonWidth) + 8;
278
290
  }
279
291
  };
280
- return (_jsxs("div", { style: { width: '100%', height: 'fit-content', cursor: onClick ? 'pointer' : undefined }, id: `text-${id}`, onClick: onClick, children: [_jsx(StyledEditor, { ref: inputRef, onContextMenu: (e) => e.stopPropagation(), id: `text-${label}-${id}`, name: label, autoFocus: autoFocus, readOnly: readOnly, type: currentType, disabled: disabled, value: displayedValue, width: width || '100%', placeholder: placeHolder, maxLength: maxLength, autoComplete: autoComplete, spellCheck: false, onFocus: () => setIsFocused(true), onBlur: (e) => { setIsFocused(false); if (currentValue != value)
281
- onBlur?.(currentValue); }, onChange: handleInputChange, onKeyDown: (e) => {
282
- if (currentType === 'number') {
283
- if (!scale && (e.key == "." || e.key == ","))
284
- e.preventDefault();
285
- }
286
- onKeyDown?.(e);
287
- }, "$isMobile": deviceType === DeviceType.MOBILE, "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, "$fontSize": fontSize, "$maxValue": maxValue, "$width": width, "$type": currentType, "$borderRadius": borderRadius, style: { paddingRight: `${calculateRightPadding()}px`, cursor: onClick ? 'pointer' : undefined } }), (initialType === 'password' || initialType === 'secureText') && _jsx(StyledShowPasswordIcon, { onClick: toggleShowPassword, "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, children: showPasswordIcon() }), initialType !== 'password' &&
288
- _jsxs("div", { style: { display: 'flex', flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', position: 'absolute', right: type === 'number' ? '25px' : '6px', top: label.length > 0 ? '20px' : '3px', pointerEvents: disabled ? 'none' : 'auto', opacity: disabled ? 0.4 : 1 }, children: [formulaItems.length > 0 &&
289
- _jsx(StyledTextBoxEditorButton, { onClick: () => {
290
- setShowFormulaItemsChooser(true);
291
- }, children: _jsx(IconDataList, {}) }), showClearButton && currentValue &&
292
- _jsx(StyledTextBoxEditorButton, { onClick: () => {
293
- onValueChanged?.({ target: { value: undefined } });
294
- onBlur?.(undefined);
295
- }, children: _jsx(IconClearButton, {}) }), buttons.map((buttonItem, index) => {
296
- return (_jsx(StyledTextBoxEditorButton, { onClick: buttonItem.onClick, children: _jsx(TMTooltip, { content: buttonItem.text, children: buttonItem.icon }) }, buttonItem.text));
297
- })] }), openFormulaItemsChooser(), formulaItems.length > 0 && (_jsx(TMContextMenu, { items: formulaMenuItems, target: `#text-${id}` })), _jsx(TMVilViewer, { vil: validationItems })] }));
292
+ // Calcola il padding-left per il simbolo della valuta
293
+ const calculateLeftPadding = () => {
294
+ if (!currencySymbol)
295
+ return 6; // Padding di default
296
+ // Stima la larghezza del simbolo (circa 10px per carattere + margine)
297
+ return 6 + (currencySymbol.length * 10) + 4;
298
+ };
299
+ return (_jsx("div", { style: { width: '100%', height: 'fit-content', cursor: onClick ? 'pointer' : undefined, display: 'flex', alignItems: 'center' }, id: `text-${id}`, onClick: onClick, children: _jsxs("div", { style: { flex: 1 }, children: [_jsxs("div", { style: { position: 'relative' }, children: [currencySymbol && initialType !== 'password' && initialType !== 'secureText' && _jsx("span", { style: { position: 'absolute', left: '6px', top: '50%', transform: 'translateY(-50%)', color: disabled ? TMColors.disabled : TMColors.text_normal, fontSize: fontSize, pointerEvents: 'none', zIndex: 1 }, children: currencySymbol }), _jsx(StyledEditor, { ref: inputRef, onContextMenu: (e) => e.stopPropagation(), id: `text-${label}-${id}`, name: label, autoFocus: autoFocus, readOnly: readOnly, type: currentType, disabled: disabled, value: displayedValue, width: width || '100%', placeholder: placeHolder, maxLength: maxLength, autoComplete: autoComplete, spellCheck: false, onFocus: () => setIsFocused(true), onBlur: (e) => { setIsFocused(false); if (currentValue != value)
300
+ onBlur?.(currentValue); }, onChange: handleInputChange, onKeyDown: (e) => {
301
+ if (currentType === 'number') {
302
+ if (!scale && (e.key == "." || e.key == ","))
303
+ e.preventDefault();
304
+ }
305
+ onKeyDown?.(e);
306
+ }, "$isMobile": deviceType === DeviceType.MOBILE, "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, "$fontSize": fontSize, "$maxValue": maxValue, "$width": width, "$type": currentType, "$borderRadius": borderRadius, style: { paddingLeft: `${calculateLeftPadding()}px`, paddingRight: `${calculateRightPadding()}px`, cursor: onClick ? 'pointer' : undefined } }), (initialType === 'password' || initialType === 'secureText') && _jsx(StyledShowPasswordIcon, { onClick: toggleShowPassword, "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, children: showPasswordIcon() }), (formulaItems.length > 0 || (showClearButton && currentValue) || buttons.length > 0) &&
307
+ _jsxs("div", { style: { display: 'flex', flexDirection: 'row', justifyContent: 'flex-start', alignItems: 'center', position: 'absolute', right: type === 'number' ? '25px' : (initialType === 'password' ? '34px' : '6px'), top: '50%', transform: 'translateY(-50%)', pointerEvents: disabled ? 'none' : 'auto', opacity: disabled ? 0.4 : 1 }, children: [formulaItems.length > 0 &&
308
+ _jsx(StyledTextBoxEditorButton, { onClick: () => {
309
+ setShowFormulaItemsChooser(true);
310
+ }, children: _jsx(IconDataList, {}) }), (showClearButton && currentValue) &&
311
+ _jsx(StyledTextBoxEditorButton, { onClick: () => { onValueChanged?.({ target: { value: undefined } }); onBlur?.(undefined); }, children: _jsx(IconClearButton, {}) }), buttons.map((buttonItem, index) => {
312
+ return (_jsx(StyledTextBoxEditorButton, { onClick: buttonItem.onClick, children: _jsx(TMTooltip, { content: buttonItem.text, children: buttonItem.icon }) }, buttonItem.text));
313
+ })] }), openFormulaItemsChooser(), formulaItems.length > 0 && (_jsx(TMContextMenu, { items: formulaMenuItems, target: `#text-${id}` }))] }), _jsx(TMVilViewer, { vil: validationItems })] }) }));
298
314
  };
299
315
  const renderedLeftLabelTextBox = () => {
300
316
  return (_jsxs(TMLayoutContainer, { direction: 'horizontal', children: [icon && _jsx(TMLayoutItem, { width: '20px', children: _jsx(StyledEditorIcon, { "$disabled": disabled, "$vil": validationItems, "$isModified": isModifiedWhen, children: icon }) }), _jsx(TMLayoutItem, { children: _jsxs(StyledEditorContainer, { "$width": width, children: [label && _jsx(StyledEditorLabel, { "$color": labelColor, "$isFocused": isFocused, "$labelPosition": labelPosition, "$disabled": disabled, children: label }), renderInputField()] }) })] }));
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { DcmtTypeDescriptor, HomeBlogPost, LayoutModes, ObjectRef, SearchResultDescriptor, TaskDescriptor, ValidationItem } from '@topconsultnpm/sdk-ts';
3
- import { DcmtInfo, FormModes, MetadataValueDescriptorEx, TaskContext } from '../../../ts';
3
+ import { DcmtInfo, FormModes, MetadataValueDescriptorEx, TaskContext, IGraphometricManagerProp } from '../../../ts';
4
4
  import { IntesiCertificateData } from '../../../helper';
5
5
  /**
6
6
  * Definisce il contesto da cui è stato invocato il TMDcmtForm.
@@ -85,6 +85,7 @@ interface ITMDcmtFormProps {
85
85
  onRefreshBlogDatagrid?: () => Promise<void>;
86
86
  onRefreshPreviewDatagrid?: () => Promise<void>;
87
87
  };
88
+ graphometricManager?: IGraphometricManagerProp;
88
89
  }
89
90
  declare const TMDcmtForm: React.FC<ITMDcmtFormProps>;
90
91
  export default TMDcmtForm;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
3
  import TMDcmtPreview from './TMDcmtPreview';
4
- import { AccessLevelsEx, AppModules, ArchiveConstraints, ArchiveEngineByID, DcmtTypeListCacheService, DossierCacheService, LayoutCacheService, LayoutModes, MetadataDataDomains, MetadataDataTypes, ObjectClasses, ResultTypes, SDK_Globals, SDK_Localizator, SystemMIDsAsNumber, SystemTIDs, Task_States, TID_DID, UpdateEngineByID, UserListCacheService, ValidationItem, WorkflowCacheService, WorkingGroupCacheService, WorkItemMetadataNames } from '@topconsultnpm/sdk-ts';
4
+ import { AccessLevelsEx, AppModules, ArchiveConstraints, ArchiveEngineByID, DcmtTypeListCacheService, DossierCacheService, LayoutCacheService, LayoutModes, MetadataDataDomains, MetadataDataTypes, MetadataFormats, ObjectClasses, ResultTypes, SDK_Globals, SDK_Localizator, SystemMIDsAsNumber, SystemTIDs, Task_States, TID_DID, UpdateEngineByID, UserListCacheService, ValidationItem, WorkflowCacheService, WorkingGroupCacheService, WorkItemMetadataNames } from '@topconsultnpm/sdk-ts';
5
5
  import { FormModes, SearchResultContext } from '../../../ts';
6
6
  import { DeviceType, useDeviceType } from '../../base/TMDeviceProvider';
7
7
  import { getWorkItemSetIDAsync, handleArchiveVisibility, searchResultToMetadataValues } from '../../../helper/queryHelper';
@@ -57,7 +57,7 @@ export var InvocationContext;
57
57
  let abortControllerLocal = new AbortController();
58
58
  ;
59
59
  //#endregion
60
- const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMode = FormModes.Update, invocationContext = InvocationContext.Default, showHeader = true, showBackButton = true, showDcmtFormSidebar = true, isClosable = false, showTodoDcmtForm = false, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, isModal = false, titleModal, widthModal = "100%", heightModal = "100%", allowNavigation = true, canNext, canPrev, count, itemIndex, onNext, onPrev, inputFile = null, inputMids = [], connectorFileSave = undefined, isSharedDcmt = false, sharedSourceTID, sharedSourceDID, allowRelations = true, allowButtonsRefs = false, openS4TViewer = false, enableDragDropOverlay = false, editPdfForm = false, onClose, onSavedAsyncCallback, onSaveRecents, onWFOperationCompleted, allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, onTaskCompleted, onTaskCreateRequest, moreInfoTasks, taskFormDialogComponent, handleNavigateToWGs, handleNavigateToDossiers, onReferenceClick, onOpenS4TViewerRequest, onOpenPdfEditorRequest, openFileUploaderPdfEditor, s4TViewerDialogComponent, onScanRequest, passToSearch, fetchRemoteCertificates, datagridUtility }) => {
60
+ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMode = FormModes.Update, invocationContext = InvocationContext.Default, showHeader = true, showBackButton = true, showDcmtFormSidebar = true, isClosable = false, showTodoDcmtForm = false, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, isModal = false, titleModal, widthModal = "100%", heightModal = "100%", allowNavigation = true, canNext, canPrev, count, itemIndex, onNext, onPrev, inputFile = null, inputMids = [], connectorFileSave = undefined, isSharedDcmt = false, sharedSourceTID, sharedSourceDID, allowRelations = true, allowButtonsRefs = false, openS4TViewer = false, enableDragDropOverlay = false, editPdfForm = false, onClose, onSavedAsyncCallback, onSaveRecents, onWFOperationCompleted, allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTaskCallback, editTaskCallback, onTaskCompleted, onTaskCreateRequest, moreInfoTasks, taskFormDialogComponent, handleNavigateToWGs, handleNavigateToDossiers, onReferenceClick, onOpenS4TViewerRequest, onOpenPdfEditorRequest, openFileUploaderPdfEditor, s4TViewerDialogComponent, onScanRequest, passToSearch, fetchRemoteCertificates, datagridUtility, graphometricManager }) => {
61
61
  const { onRefreshSearchAsyncDatagrid, onRefreshBlogDatagrid, onRefreshPreviewDatagrid } = datagridUtility || {};
62
62
  const floatingBarContainerRef = useRef(null);
63
63
  const [id, setID] = useState('');
@@ -423,6 +423,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
423
423
  enablePinIcons: false,
424
424
  allowRelations,
425
425
  inputDcmtFormLayoutMode: layoutMode,
426
+ graphometricManager
426
427
  },
427
428
  tasks: {
428
429
  allTasks: allTasks,
@@ -1425,7 +1426,49 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1425
1426
  return undefined;
1426
1427
  const settings = getCurrentDcmtFormSetting()?.setting;
1427
1428
  // Return the appropriate layout based on context
1428
- return invocationContext === InvocationContext.Todo ? settings?.layoutToDo : settings?.layout;
1429
+ const persistedState = invocationContext === InvocationContext.Todo ? settings?.layoutToDo : settings?.layout;
1430
+ // tmWF must always start hidden - PanelDisabledStateHandler will restore it
1431
+ // when workflow data becomes available and isWFDisabled becomes false
1432
+ if (persistedState && persistedState['tmWF']?.visible) {
1433
+ // Get tmWF width to redistribute
1434
+ const tmWFWidth = parseFloat(persistedState['tmWF'].width) || 0;
1435
+ // Find other visible panels to redistribute width
1436
+ const otherVisiblePanels = Object.keys(persistedState).filter(key => key !== 'tmWF' && persistedState[key]?.visible);
1437
+ // Calculate extra width per visible panel
1438
+ const extraWidthPerPanel = otherVisiblePanels.length > 0
1439
+ ? tmWFWidth / otherVisiblePanels.length
1440
+ : 0;
1441
+ // Build new state with redistributed widths
1442
+ const newState = {};
1443
+ for (const key of Object.keys(persistedState)) {
1444
+ if (key === 'tmWF') {
1445
+ // Hide tmWF
1446
+ newState[key] = { ...persistedState[key], visible: false };
1447
+ }
1448
+ else if (otherVisiblePanels.includes(key)) {
1449
+ // Add extra width to visible panels
1450
+ const currentWidth = parseFloat(persistedState[key].width) || 0;
1451
+ newState[key] = {
1452
+ ...persistedState[key],
1453
+ width: `${currentWidth + extraWidthPerPanel}%`
1454
+ };
1455
+ }
1456
+ else {
1457
+ // Keep other panels as-is
1458
+ newState[key] = persistedState[key];
1459
+ }
1460
+ }
1461
+ return newState;
1462
+ }
1463
+ return persistedState;
1464
+ };
1465
+ // Returns whether tmWF was visible in persisted state (for restoring after WF data loads)
1466
+ const getPersistedWFVisible = () => {
1467
+ if (isMobile)
1468
+ return false;
1469
+ const settings = getCurrentDcmtFormSetting()?.setting;
1470
+ const persistedState = invocationContext === InvocationContext.Todo ? settings?.layoutToDo : settings?.layout;
1471
+ return persistedState?.['tmWF']?.visible ?? false;
1429
1472
  };
1430
1473
  const onBlogCommentFormCustomSave = useCallback(async (blogPost) => {
1431
1474
  try {
@@ -1514,7 +1557,7 @@ const TMDcmtForm = ({ TID, DID, groupId, layoutMode = LayoutModes.Update, formMo
1514
1557
  overflow: 'hidden'
1515
1558
  }, children: [_jsxs("div", { style: { width: '100%', height: '100%', display: isOpenDetails || isOpenMaster ? 'none' : 'flex' }, children: [isNavigating && _jsx(Spinner, { description: SDKUI_Localizator.Loading, flat: false }), (fromDTD) && _jsx(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: useWaitPanelLocalState ? showWaitPanelLocal : showWaitPanel, showWaitPanelPrimary: useWaitPanelLocalState ? showPrimaryLocal : showPrimary, showWaitPanelSecondary: useWaitPanelLocalState ? showSecondaryLocal : showSecondary, waitPanelTitle: useWaitPanelLocalState ? waitPanelTitleLocal : waitPanelTitle, waitPanelTextPrimary: useWaitPanelLocalState ? waitPanelTextPrimaryLocal : waitPanelTextPrimary, waitPanelValuePrimary: useWaitPanelLocalState ? waitPanelValuePrimaryLocal : waitPanelValuePrimary, waitPanelMaxValuePrimary: useWaitPanelLocalState ? waitPanelMaxValuePrimaryLocal : waitPanelMaxValuePrimary, waitPanelTextSecondary: useWaitPanelLocalState ? waitPanelTextSecondaryLocal : waitPanelTextSecondary, waitPanelValueSecondary: useWaitPanelLocalState ? waitPanelValueSecondaryLocal : waitPanelValueSecondary, waitPanelMaxValueSecondary: useWaitPanelLocalState ? waitPanelMaxValueSecondaryLocal : waitPanelMaxValueSecondary, isCancelable: useWaitPanelLocalState ? dcmtFile ? dcmtFile.size >= 1000000 : false : true, abortController: useWaitPanelLocalState ? abortControllerLocal : abortController, children: _jsxs(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: showCicoWaitPanel, showWaitPanelPrimary: showCicoPrimaryProgress, waitPanelTitle: cicoWaitPanelTitle, waitPanelTextPrimary: cicoPrimaryProgressText, waitPanelValuePrimary: cicoPrimaryProgressValue, waitPanelMaxValuePrimary: cicoPrimaryProgressMax, isCancelable: true, abortController: abortControllerLocal, children: [(groupId && groupId.length > 0)
1516
1559
  ? _jsxs(_Fragment, { children: [_jsx(PanelDisabledStateHandler, { isWFDisabled: isWFDisabled, isSysMetadataDisabled: isSysMetadataDisabled, isBoardDisabled: isBoardDisabled, isDcmtTasksDisabled: isDcmtTasksDisabled, isPreviewDisabled: isPreviewDisabled }), _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", parentId: groupId, showToolbar: showDcmtFormSidebar })] })
1517
- : _jsxs(TMPanelManagerWithPersistenceProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: defaultPanelDimensions, initialDimensions: defaultPanelDimensions, initialMobilePanelId: 'tmDcmtForm', isPersistenceEnabled: !isMobile && layoutMode !== LayoutModes.Ark ? hasSavedLayout() : false, persistPanelStates: !isMobile && layoutMode !== LayoutModes.Ark ? (state) => persistPanelStates(state) : undefined, persistedPanelStates: layoutMode !== LayoutModes.Ark ? getPersistedPanelStates() : undefined, children: [_jsx(PanelDisabledStateHandler, { isWFDisabled: isWFDisabled, isSysMetadataDisabled: isSysMetadataDisabled, isBoardDisabled: isBoardDisabled, isDcmtTasksDisabled: isDcmtTasksDisabled, isPreviewDisabled: isPreviewDisabled }), _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", parentId: groupId, showToolbar: showDcmtFormSidebar })] }), isOpenDistinctValues &&
1560
+ : _jsxs(TMPanelManagerWithPersistenceProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: defaultPanelDimensions, initialDimensions: defaultPanelDimensions, initialMobilePanelId: 'tmDcmtForm', isPersistenceEnabled: !isMobile && layoutMode !== LayoutModes.Ark ? hasSavedLayout() : false, persistPanelStates: !isMobile && layoutMode !== LayoutModes.Ark ? (state) => persistPanelStates(state) : undefined, persistedPanelStates: layoutMode !== LayoutModes.Ark ? getPersistedPanelStates() : undefined, children: [_jsx(PanelDisabledStateHandler, { isWFDisabled: isWFDisabled, isSysMetadataDisabled: isSysMetadataDisabled, isBoardDisabled: isBoardDisabled, isDcmtTasksDisabled: isDcmtTasksDisabled, isPreviewDisabled: isPreviewDisabled, persistedWFVisible: getPersistedWFVisible() }), _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", parentId: groupId, showToolbar: showDcmtFormSidebar })] }), isOpenDistinctValues &&
1518
1561
  _jsx(TMDistinctValues, { tid: TID, mid: focusedMetadataValue?.mid, isModal: true, showHeader: false, layoutMode: layoutMode, onClosePanelCallback: () => setIsOpenDistinctValues(false), onSelectionChanged: (e) => {
1519
1562
  if (!e)
1520
1563
  return;
@@ -1576,6 +1619,8 @@ export const validateMetadataList = (mvdList = []) => {
1576
1619
  if (isValidForValidation(mvd)) {
1577
1620
  validateRequiredField(mvd, value, validationItems);
1578
1621
  validateMaxLength(mvd, value, validationItems);
1622
+ validateCustomRegEx(mvd, value, validationItems);
1623
+ validateFormatRegEx(mvd, value, validationItems);
1579
1624
  }
1580
1625
  return validationItems;
1581
1626
  }, []);
@@ -1598,13 +1643,63 @@ const validateMaxLength = (mvd, value, validationItems) => {
1598
1643
  const isTextOrNumber = mvd.md?.dataType === MetadataDataTypes.Varchar || mvd.md?.dataType === MetadataDataTypes.Number;
1599
1644
  const isFormula = FormulaHelper.isFormula(value);
1600
1645
  if (isTextOrNumber && !isFormula && mvd.md?.length && value.replace(regex, '').length > maxLength) {
1601
- const message = `"${mvd.md.nameLoc ?? "no-name"}" ha superata massimo lunghezza di ${maxLength} caratteri.`;
1602
- validationItems.push(new ValidationItem(ResultTypes.ERROR, mvd.md.nameLoc ?? "", message));
1646
+ const fieldName = mvd.md?.nameLoc ?? mvd.md?.name ?? SDKUI_Localizator.Field;
1647
+ const message = SDKUI_Localizator.MaxLengthExceeded.replaceParams(fieldName, maxLength);
1648
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, fieldName, message));
1649
+ }
1650
+ };
1651
+ const validateCustomRegEx = (mvd, value, validationItems) => {
1652
+ const pattern = mvd.md?.format?.formatCustom;
1653
+ if (mvd.md?.format?.format !== MetadataFormats.CustomRegEx || !pattern)
1654
+ return;
1655
+ // Valore vuoto: ci pensa validateRequiredField; formule: non validabili con regex
1656
+ if (!value.trim() || FormulaHelper.isFormula(value))
1657
+ return;
1658
+ try {
1659
+ const regex = new RegExp(`^(?:${pattern})$`);
1660
+ if (!regex.test(value)) {
1661
+ const fieldName = mvd.md?.nameLoc ?? mvd.md?.name ?? SDKUI_Localizator.Field;
1662
+ const message = SDKUI_Localizator.FormatNotRespected.replaceParams(fieldName, pattern);
1663
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, fieldName, message));
1664
+ }
1665
+ }
1666
+ catch {
1667
+ // Pattern regex non valido: nessuna validazione, accetta qualsiasi valore
1668
+ }
1669
+ };
1670
+ // Regex predefinite per i formati standard (EMail, Partita IVA, Codice Fiscale)
1671
+ const FORMAT_REGEX_RULES = [
1672
+ {
1673
+ format: MetadataFormats.EMail,
1674
+ regex: /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/,
1675
+ message: (name) => SDKUI_Localizator.InvalidEmailAddress.replaceParams(name)
1676
+ },
1677
+ {
1678
+ format: MetadataFormats.PartitaIva,
1679
+ regex: /^[0-9]{11}$/,
1680
+ message: (name) => SDKUI_Localizator.InvalidVatNumber.replaceParams(name)
1681
+ },
1682
+ {
1683
+ // Persone fisiche (16 caratteri, incluse le lettere di omocodia) o soggetti giuridici (11 cifre)
1684
+ format: MetadataFormats.CodiceFiscale,
1685
+ regex: /^(?:[A-Z]{6}[0-9LMNPQRSTUV]{2}[ABCDEHLMPRST][0-9LMNPQRSTUV]{2}[A-Z][0-9LMNPQRSTUV]{3}[A-Z]|[0-9]{11})$/i,
1686
+ message: (name) => SDKUI_Localizator.InvalidTaxCode.replaceParams(name)
1687
+ }
1688
+ ];
1689
+ const validateFormatRegEx = (mvd, value, validationItems) => {
1690
+ const rule = FORMAT_REGEX_RULES.find(r => r.format === mvd.md?.format?.format);
1691
+ if (!rule)
1692
+ return;
1693
+ // Valore vuoto: ci pensa validateRequiredField; formule: non validabili con regex
1694
+ if (!value.trim() || FormulaHelper.isFormula(value))
1695
+ return;
1696
+ if (!rule.regex.test(value)) {
1697
+ validationItems.push(new ValidationItem(ResultTypes.ERROR, mvd.md?.nameLoc ?? "", rule.message(mvd.md?.nameLoc ?? SDKUI_Localizator.Field)));
1603
1698
  }
1604
1699
  };
1605
1700
  //#endregion Validation
1606
1701
  // Synchronizes panel visibility and toolbar button disabled states when panels become disabled
1607
- const PanelDisabledStateHandler = ({ isWFDisabled, isSysMetadataDisabled, isBoardDisabled, isDcmtTasksDisabled, isPreviewDisabled }) => {
1702
+ const PanelDisabledStateHandler = ({ isWFDisabled, isSysMetadataDisabled, isBoardDisabled, isDcmtTasksDisabled, isPreviewDisabled, persistedWFVisible = false }) => {
1608
1703
  const { setPanelVisibilityById, setToolbarButtonDisabled } = useTMPanelManagerContext();
1609
1704
  useEffect(() => {
1610
1705
  if (isSysMetadataDisabled) {
@@ -1631,8 +1726,12 @@ const PanelDisabledStateHandler = ({ isWFDisabled, isSysMetadataDisabled, isBoar
1631
1726
  }
1632
1727
  else {
1633
1728
  setToolbarButtonDisabled('tmWF', false);
1729
+ // Restore persisted visibility when WF becomes enabled
1730
+ if (persistedWFVisible) {
1731
+ setPanelVisibilityById('tmWF', true);
1732
+ }
1634
1733
  }
1635
- }, [isWFDisabled]);
1734
+ }, [isWFDisabled, persistedWFVisible]);
1636
1735
  useEffect(() => {
1637
1736
  if (isDcmtTasksDisabled) {
1638
1737
  setToolbarButtonDisabled('tmDcmtTasks', true);
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
3
- import { DcmtTypeListCacheService, SDK_Globals, DataColumnTypes, MetadataFormats, MetadataDataDomains, RelationCacheService, RelationTypes, UserListCacheService, LayoutModes } from "@topconsultnpm/sdk-ts";
4
- import { genUniqueId, IconFolder, IconBackhandIndexPointingRight, IconCircleInfo, getDcmtCicoStatus, IconChevronDown, IconChevronRight, SDKUI_Localizator, buildDcmtDisplayName, SDKUI_Globals, searchResultToMetadataValues } from '../../../helper';
3
+ import { DcmtTypeListCacheService, SDK_Globals, DataColumnTypes, MetadataDataDomains, RelationCacheService, RelationTypes, UserListCacheService, LayoutModes } from "@topconsultnpm/sdk-ts";
4
+ import { genUniqueId, IconFolder, IconBackhandIndexPointingRight, IconCircleInfo, getDcmtCicoStatus, IconChevronDown, IconChevronRight, SDKUI_Localizator, buildDcmtDisplayName, SDKUI_Globals, searchResultToMetadataValues, getColumnFormatInfo, formatDateTimeByMetadataFormat, formatNumberByMetadataFormat } from '../../../helper';
5
5
  import ShowAlert from '../../base/TMAlert';
6
6
  import TMToppyMessage from '../../../helper/TMToppyMessage';
7
7
  import { TMColors } from '../../../utils/theme';
@@ -55,35 +55,14 @@ export const getDisplayValueByColumn = (col, value) => {
55
55
  return value;
56
56
  if (col.dataType === DataColumnTypes.Text)
57
57
  return value;
58
- const format = MetadataFormats[(col.extendedProperties?.["Format"] ?? "None")];
59
- const formatCulture = col.extendedProperties?.["FormatCulture"] ?? window.navigator.language;
60
- if (col.dataType === DataColumnTypes.DateTime) {
61
- const date = new Date(value);
62
- switch (format) {
63
- case MetadataFormats.ShortDate: return date.toLocaleString(formatCulture, formatCulture == "it-IT" ? { year: "numeric", month: "2-digit", day: "2-digit" } : { dateStyle: 'short' });
64
- case MetadataFormats.ShortTime: return date.toLocaleString(formatCulture, { timeStyle: 'short' });
65
- case MetadataFormats.ShortDateLongTime: return date.toLocaleString(formatCulture, formatCulture == "it-IT" ? { year: "numeric", month: "2-digit", day: "2-digit", hour: '2-digit', minute: '2-digit', second: '2-digit' } : { dateStyle: 'short', timeStyle: 'medium' }).replace(',', '');
66
- case MetadataFormats.ShortDateShortTime: return date.toLocaleString(formatCulture, formatCulture == "it-IT" ? { year: "numeric", month: "2-digit", day: "2-digit", hour: '2-digit', minute: '2-digit' } : { dateStyle: 'short', timeStyle: 'short' }).replace(',', '');
67
- case MetadataFormats.LongDate: return date.toLocaleString(formatCulture, { weekday: "long", year: "numeric", month: "long", day: "numeric" });
68
- case MetadataFormats.LongTime: return date.toLocaleString(formatCulture, { timeStyle: 'medium' });
69
- case MetadataFormats.LongDateLongTime: return date.toLocaleString(formatCulture, { weekday: "long", year: "numeric", month: "long", day: "numeric", hour: '2-digit', minute: '2-digit', second: '2-digit' });
70
- case MetadataFormats.LongDateShortTime: return date.toLocaleString(formatCulture, { weekday: "long", year: "numeric", month: "long", day: "numeric", hour: '2-digit', minute: '2-digit' });
71
- default: return date.toLocaleString(formatCulture, { dateStyle: 'short' });
72
- }
73
- }
74
- if (col.dataType === DataColumnTypes.Number) {
75
- return value.toLocaleString(formatCulture, { useGrouping: format == MetadataFormats.NumberWithThousandsSeparator });
76
- }
77
- if (format == MetadataFormats.None)
78
- return value;
79
- if (format == MetadataFormats.CurrencyEuro)
80
- return value.toLocaleString(formatCulture, { style: 'currency', currency: "EUR" });
81
- if (format == MetadataFormats.CurrencyDollar)
82
- return value.toLocaleString(formatCulture, { style: 'currency', currency: "USD" });
83
- if (format == MetadataFormats.CurrencyPound)
84
- return value.toLocaleString(formatCulture, { style: 'currency', currency: "GBP" });
85
- if (format == MetadataFormats.CurrencyYen)
86
- return value.toLocaleString(formatCulture, { style: 'currency', currency: "JPY" });
58
+ // Formato e cultura di visualizzazione definiti sulle proprietà estese della colonna
59
+ const { format, formatCulture } = getColumnFormatInfo(col);
60
+ // Date: il valore arriva come stringa e va prima convertito in Date
61
+ if (col.dataType === DataColumnTypes.DateTime)
62
+ return formatDateTimeByMetadataFormat(new Date(value), format, formatCulture);
63
+ // Numeri (incluse valute): stessa formattazione usata da TMSearchResult
64
+ if (col.dataType === DataColumnTypes.Number)
65
+ return formatNumberByMetadataFormat(value, format, formatCulture);
87
66
  return value;
88
67
  };
89
68
  /**
@@ -123,9 +102,11 @@ export const searchResultToDataSource = async (searchResult, hideSysMetadata) =>
123
102
  ? (mvd.md?.name ?? '').toUpperCase()
124
103
  : (mvd.md?.name ?? '');
125
104
  if (key) {
105
+ // Find the corresponding column by MID to format the value
106
+ const column = dtdResult?.columns?.find(c => Number(c.extendedProperties?.["MID"] ?? "0") === mvd.mid);
126
107
  item[key] = {
127
108
  md: mvd.md,
128
- value: mvd.value
109
+ value: getDisplayValueByColumn(column, mvd.value)
129
110
  };
130
111
  }
131
112
  }
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import { SavedQueryDescriptor, DcmtTypeDescriptor, TaskDescriptor, ObjectRef, HomeBlogPost } from '@topconsultnpm/sdk-ts';
3
3
  import { IntesiCertificateData } from '../../../helper';
4
- import { DcmtInfo, TaskContext } from '../../../ts';
4
+ import { DcmtInfo, IGraphometricManagerProp, TaskContext } from '../../../ts';
5
5
  import { TMSearchResultFloatingActionConfig } from './TMSearchResultFloatingActionButton';
6
6
  interface ITMSearchProps {
7
7
  allTasks?: Array<TaskDescriptor>;
@@ -44,6 +44,7 @@ interface ITMSearchProps {
44
44
  inputDID?: number;
45
45
  formAutoOpen?: boolean;
46
46
  fetchRemoteCertificates?: (email: string) => Promise<IntesiCertificateData[]>;
47
+ graphometricManager?: IGraphometricManagerProp;
47
48
  }
48
49
  declare const TMSearch: React.FunctionComponent<ITMSearchProps>;
49
50
  export default TMSearch;