@topconsultnpm/sdkui-react 6.21.0-t1 → 6.21.0-t2

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 (91) hide show
  1. package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +4 -4
  2. package/lib/components/base/TMAccordionNew.d.ts +1 -0
  3. package/lib/components/base/TMAccordionNew.js +6 -5
  4. package/lib/components/base/TMAreaManager.js +19 -3
  5. package/lib/components/base/TMDataGrid.js +2 -2
  6. package/lib/components/base/TMModal.d.ts +1 -0
  7. package/lib/components/base/TMModal.js +2 -2
  8. package/lib/components/base/TMPanel.d.ts +7 -4
  9. package/lib/components/base/TMPanel.js +58 -26
  10. package/lib/components/base/TMTreeView.js +12 -2
  11. package/lib/components/base/TMWaitPanel.js +7 -4
  12. package/lib/components/choosers/TMDistinctValues.js +35 -21
  13. package/lib/components/choosers/TMUserChooser.d.ts +4 -0
  14. package/lib/components/choosers/TMUserChooser.js +7 -5
  15. package/lib/components/editors/TMDateBox.js +4 -2
  16. package/lib/components/editors/TMFormulaEditor.d.ts +2 -0
  17. package/lib/components/editors/TMFormulaEditor.js +75 -21
  18. package/lib/components/editors/TMMetadataValues.js +2 -1
  19. package/lib/components/editors/TMRadioButton.js +7 -5
  20. package/lib/components/editors/TMTextArea.d.ts +2 -0
  21. package/lib/components/editors/TMTextArea.js +6 -3
  22. package/lib/components/editors/TMTextBox.d.ts +2 -0
  23. package/lib/components/editors/TMTextBox.js +3 -3
  24. package/lib/components/features/archive/TMArchive.js +1 -1
  25. package/lib/components/features/documents/TMCopyToFolderForm.d.ts +24 -0
  26. package/lib/components/features/documents/TMCopyToFolderForm.js +379 -0
  27. package/lib/components/features/documents/TMDcmtForm.d.ts +1 -0
  28. package/lib/components/features/documents/TMDcmtForm.js +147 -45
  29. package/lib/components/features/documents/TMDcmtFormActionButtons.js +259 -60
  30. package/lib/components/features/documents/TMDcmtPreview.d.ts +1 -0
  31. package/lib/components/features/documents/TMDcmtPreview.js +2 -2
  32. package/lib/components/features/documents/TMDcmtTasks.d.ts +1 -0
  33. package/lib/components/features/documents/TMDcmtTasks.js +2 -2
  34. package/lib/components/features/documents/TMDownloadRelationViewerSection.d.ts +23 -0
  35. package/lib/components/features/documents/TMDownloadRelationViewerSection.js +173 -0
  36. package/lib/components/features/documents/TMFileUploader.js +1 -1
  37. package/lib/components/features/documents/TMMasterDetailDcmts.d.ts +4 -0
  38. package/lib/components/features/documents/TMMasterDetailDcmts.js +29 -9
  39. package/lib/components/features/documents/TMMergeToPdfForm.d.ts +26 -0
  40. package/lib/components/features/documents/TMMergeToPdfForm.js +293 -0
  41. package/lib/components/features/documents/TMRelationViewer.d.ts +13 -0
  42. package/lib/components/features/documents/TMRelationViewer.js +75 -6
  43. package/lib/components/features/documents/copyAndMergeDcmtsShared.d.ts +71 -0
  44. package/lib/components/features/documents/copyAndMergeDcmtsShared.js +304 -0
  45. package/lib/components/features/search/SignatureParamsManager.d.ts +70 -0
  46. package/lib/components/features/search/SignatureParamsManager.js +145 -0
  47. package/lib/components/features/search/TMSavedQuerySelector.d.ts +2 -2
  48. package/lib/components/features/search/TMSavedQuerySelector.js +3 -2
  49. package/lib/components/features/search/TMSearch.d.ts +6 -1
  50. package/lib/components/features/search/TMSearch.js +16 -10
  51. package/lib/components/features/search/TMSearchQueryPanel.js +1 -1
  52. package/lib/components/features/search/TMSearchResult.d.ts +4 -0
  53. package/lib/components/features/search/TMSearchResult.js +118 -22
  54. package/lib/components/features/search/TMViewHistoryDcmt.js +1 -2
  55. package/lib/components/features/workflow/TMWorkflowPopup.js +3 -0
  56. package/lib/components/features/workflow/diagram/queryDescriptorParser.js +3 -6
  57. package/lib/components/forms/Login/TMLoginForm.d.ts +9 -0
  58. package/lib/components/forms/Login/TMLoginForm.js +61 -0
  59. package/lib/components/forms/TMResultDialog.d.ts +1 -1
  60. package/lib/components/forms/TMResultDialog.js +4 -2
  61. package/lib/components/grids/TMBlogAttachments.d.ts +1 -0
  62. package/lib/components/grids/TMBlogAttachments.js +38 -12
  63. package/lib/components/grids/TMBlogsPost.js +7 -1
  64. package/lib/components/grids/TMBlogsPostUtils.js +11 -17
  65. package/lib/components/index.d.ts +1 -0
  66. package/lib/components/index.js +1 -0
  67. package/lib/components/pages/TMPage.js +3 -1
  68. package/lib/components/query/TMQueryEditor.js +2 -2
  69. package/lib/components/viewers/TMTidViewer.js +1 -1
  70. package/lib/helper/GlobalStyles.js +6 -0
  71. package/lib/helper/SDKUI_Globals.d.ts +15 -0
  72. package/lib/helper/SDKUI_Globals.js +15 -1
  73. package/lib/helper/SDKUI_Localizator.d.ts +106 -2
  74. package/lib/helper/SDKUI_Localizator.js +1060 -12
  75. package/lib/helper/TMPdfViewer.js +25 -24
  76. package/lib/helper/TMUtils.d.ts +20 -0
  77. package/lib/helper/TMUtils.js +17 -0
  78. package/lib/helper/ZipManager.d.ts +56 -0
  79. package/lib/helper/ZipManager.js +127 -0
  80. package/lib/helper/index.d.ts +1 -0
  81. package/lib/helper/index.js +1 -0
  82. package/lib/hooks/useDataUserIdItem.js +6 -4
  83. package/lib/hooks/useDcmtOperations.d.ts +9 -2
  84. package/lib/hooks/useDcmtOperations.js +78 -35
  85. package/lib/hooks/useDocumentOperations.d.ts +5 -0
  86. package/lib/hooks/useDocumentOperations.js +238 -27
  87. package/lib/hooks/useForm.js +5 -2
  88. package/lib/hooks/useResizeObserver.d.ts +1 -1
  89. package/lib/hooks/useResizeObserver.js +16 -15
  90. package/lib/ts/types.d.ts +1 -0
  91. package/package.json +3 -2
@@ -73,20 +73,20 @@ export declare const MenuButton: import("styled-components/dist/types").IStyledC
73
73
  export declare const ConfigButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never> & Partial<Pick<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>>> & string;
74
74
  export declare const ApplyButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never> & Partial<Pick<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>>> & string;
75
75
  export declare const CloseButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never> & Partial<Pick<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>>> & string;
76
- export declare const ContextMenuButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<Omit<import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "$isActive"> & {
76
+ export declare const ContextMenuButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<Omit<import("styled-components").FastOmit<import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "$isActive"> & {
77
77
  $isActive?: boolean;
78
78
  }, never> & Partial<Pick<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "$isActive"> & {
79
79
  $isActive?: boolean;
80
- }, never>> & {
80
+ }, never>>, "as" | "forwardedAs"> & {
81
81
  as?: import("styled-components").WebTarget | undefined;
82
82
  forwardedAs?: import("styled-components").WebTarget | undefined;
83
83
  }, "ref"> & {
84
84
  ref?: ((instance: HTMLButtonElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLButtonElement> | null | undefined;
85
- }, never> & Partial<Pick<Omit<import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "$isActive"> & {
85
+ }, never> & Partial<Pick<Omit<import("styled-components").FastOmit<import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "$isActive"> & {
86
86
  $isActive?: boolean;
87
87
  }, never> & Partial<Pick<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "$isActive"> & {
88
88
  $isActive?: boolean;
89
- }, never>> & {
89
+ }, never>>, "as" | "forwardedAs"> & {
90
90
  as?: import("styled-components").WebTarget | undefined;
91
91
  forwardedAs?: import("styled-components").WebTarget | undefined;
92
92
  }, "ref"> & {
@@ -23,6 +23,7 @@ export interface TMAccordionProps {
23
23
  localStorageKey?: string;
24
24
  selectedItem?: any;
25
25
  onSelectedItemChange?: (item: any) => void;
26
+ itemMarginBottom?: number;
26
27
  }
27
28
  declare const TMAccordion: React.FC<TMAccordionProps>;
28
29
  export default TMAccordion;
@@ -41,7 +41,7 @@ const Container = styled.div `
41
41
  }
42
42
  `;
43
43
  const AccordionItem = styled.div `
44
- margin-bottom: 16px;
44
+ margin-bottom: ${props => props.$marginBottom}px;
45
45
  border-radius: 5px;
46
46
  background: white;
47
47
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
@@ -152,7 +152,7 @@ const LoadingContainer = styled.div `
152
152
  min-height: 200px;
153
153
  `;
154
154
  const DEFAULT_COLORS = ['#339af0', '#fa5252', '#40c057', '#f59f00', '#e64980', '#7950f2'];
155
- const TMAccordion = ({ groups, localStorageKey, selectedItem, onSelectedItemChange }) => {
155
+ const TMAccordion = ({ groups, localStorageKey, selectedItem, onSelectedItemChange, itemMarginBottom = 16 }) => {
156
156
  const [openAccordions, setOpenAccordions] = useState({});
157
157
  const [isInitialized, setIsInitialized] = useState(false);
158
158
  const [focusedItem, setFocusedItem] = useState(undefined);
@@ -252,6 +252,7 @@ const TMAccordion = ({ groups, localStorageKey, selectedItem, onSelectedItemChan
252
252
  disabled: mi.disabled,
253
253
  onClick: mi.onClick,
254
254
  submenu: mi.items || mi.submenu,
255
+ beginGroup: mi.beginGroup ?? false
255
256
  }));
256
257
  setItemContextMenuPosition({ x: event.clientX, y: event.clientY });
257
258
  setItemContextMenuItems(convertedItems);
@@ -308,16 +309,16 @@ const TMAccordion = ({ groups, localStorageKey, selectedItem, onSelectedItemChan
308
309
  const color = getGroupColor(group, index);
309
310
  const isOpen = openAccordions[group.id] ?? true;
310
311
  if (group.customComponent) {
311
- return (_jsxs(AccordionItem, { children: [_jsxs(AccordionHeader, { id: `accordion-header-${group.id}`, "$color": color, "$isOpen": isOpen, onClick: (e) => handleHeaderClick(e, group.id), onContextMenu: (e) => handleHeaderContextMenu(e, group.id), children: [_jsxs(AccordionTitle, { children: [group.icon, _jsx(TitleText, { children: group.title })] }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '10px' }, children: [renderBadges(group, color), _jsx(ToggleIcon, { "$isOpen": isOpen, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: _jsx("path", { d: "M4 6L8 10L12 6", stroke: "#495057", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })] }), isOpen && (_jsx(CustomComponentContainer, { children: group.customComponent }))] }, group.id));
312
+ return (_jsxs(AccordionItem, { "$marginBottom": itemMarginBottom, children: [_jsxs(AccordionHeader, { id: `accordion-header-${group.id}`, "$color": color, "$isOpen": isOpen, onClick: (e) => handleHeaderClick(e, group.id), onContextMenu: (e) => handleHeaderContextMenu(e, group.id), children: [_jsxs(AccordionTitle, { children: [group.icon, _jsx(TitleText, { children: group.title })] }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '10px' }, children: [renderBadges(group, color), _jsx(ToggleIcon, { "$isOpen": isOpen, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: _jsx("path", { d: "M4 6L8 10L12 6", stroke: "#495057", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })] }), isOpen && (_jsx(CustomComponentContainer, { children: group.customComponent }))] }, group.id));
312
313
  }
313
314
  if (!group.dataSource || group.dataSource.length === 0)
314
315
  return null;
315
316
  if (!group.renderItem) {
316
- return (_jsxs(AccordionItem, { children: [_jsxs(AccordionHeader, { id: `accordion-header-${group.id}`, "$color": color, "$isOpen": isOpen, onClick: (e) => handleHeaderClick(e, group.id), onContextMenu: (e) => handleHeaderContextMenu(e, group.id), children: [_jsxs(AccordionTitle, { children: [group.icon, _jsx(TitleText, { children: group.title })] }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '10px' }, children: [renderBadges(group, color), _jsx(ToggleIcon, { "$isOpen": isOpen, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: _jsx("path", { d: "M4 6L8 10L12 6", stroke: "#495057", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })] }), _jsx(AccordionContent, { "$isOpen": isOpen, "$maxHeight": 100, children: _jsxs(ErrorMessage, { children: ["\u26A0\uFE0F renderItem function is required for \"", group.title, "\" group"] }) })] }, group.id));
317
+ return (_jsxs(AccordionItem, { "$marginBottom": itemMarginBottom, children: [_jsxs(AccordionHeader, { id: `accordion-header-${group.id}`, "$color": color, "$isOpen": isOpen, onClick: (e) => handleHeaderClick(e, group.id), onContextMenu: (e) => handleHeaderContextMenu(e, group.id), children: [_jsxs(AccordionTitle, { children: [group.icon, _jsx(TitleText, { children: group.title })] }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '10px' }, children: [renderBadges(group, color), _jsx(ToggleIcon, { "$isOpen": isOpen, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: _jsx("path", { d: "M4 6L8 10L12 6", stroke: "#495057", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })] }), _jsx(AccordionContent, { "$isOpen": isOpen, "$maxHeight": 100, children: _jsxs(ErrorMessage, { children: ["\u26A0\uFE0F renderItem function is required for \"", group.title, "\" group"] }) })] }, group.id));
317
318
  }
318
319
  const itemHeight = group.itemHeight || 80;
319
320
  const maxHeight = group.dataSource.length * itemHeight + 20;
320
- return (_jsxs(AccordionItem, { children: [_jsxs(AccordionHeader, { id: `accordion-header-${group.id}`, "$color": color, "$isOpen": isOpen, onClick: (e) => handleHeaderClick(e, group.id), onContextMenu: (e) => handleHeaderContextMenu(e, group.id), children: [_jsxs(AccordionTitle, { children: [group.icon, _jsx(TitleText, { children: group.title })] }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '10px' }, children: [renderBadges(group, color), _jsx(ToggleIcon, { "$isOpen": isOpen, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: _jsx("path", { d: "M4 6L8 10L12 6", stroke: "#495057", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })] }), _jsx(AccordionContent, { "$isOpen": isOpen, "$maxHeight": maxHeight, children: _jsx(ItemsList, { children: group.dataSource.map((item, itemIndex) => {
321
+ return (_jsxs(AccordionItem, { "$marginBottom": itemMarginBottom, children: [_jsxs(AccordionHeader, { id: `accordion-header-${group.id}`, "$color": color, "$isOpen": isOpen, onClick: (e) => handleHeaderClick(e, group.id), onContextMenu: (e) => handleHeaderContextMenu(e, group.id), children: [_jsxs(AccordionTitle, { children: [group.icon, _jsx(TitleText, { children: group.title })] }), _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '10px' }, children: [renderBadges(group, color), _jsx(ToggleIcon, { "$isOpen": isOpen, children: _jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: _jsx("path", { d: "M4 6L8 10L12 6", stroke: "#495057", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })] }), _jsx(AccordionContent, { "$isOpen": isOpen, "$maxHeight": maxHeight, children: _jsx(ItemsList, { children: group.dataSource.map((item, itemIndex) => {
321
322
  const isSelected = selectedItem === item;
322
323
  const isFocused = focusedItem === item;
323
324
  return (_jsx(ListItem, { id: `accordion-item-${group.id}-${itemIndex}`, className: "tm-accordion-list-item", "$isSelected": isSelected, "$color": color, onClick: () => handleItemClick(item, group), onDoubleClick: () => handleItemDoubleClick(item, group), onMouseEnter: () => setFocusedItem(item), onMouseLeave: () => setFocusedItem(undefined), onContextMenu: (e) => handleContextMenu(e, item, group), children: group.renderItem(item, isSelected, isFocused, color) }, itemIndex * 2));
@@ -5,7 +5,7 @@ import { FileDescriptor, FileFormats, FileTransferModes, SDK_Localizator, SDK_Gl
5
5
  import CustomFileSystemProvider from 'devextreme/file_management/custom_provider';
6
6
  import FileSystemError from "devextreme/file_management/error";
7
7
  import Button from "devextreme/ui/button";
8
- import { alert, confirm } from "devextreme/ui/dialog";
8
+ import { alert, custom } from "devextreme/ui/dialog";
9
9
  import { loadMessages } from 'devextreme/localization';
10
10
  import { getFileManagerFolderColor, Globalization, IconAll, IconCloud, IconFolder, IconFolderForCSS, IconSelected, SDKUI_Localizator, svgToString } from '../../helper';
11
11
  import { TMExceptionBoxManager } from './TMPopUp';
@@ -253,8 +253,24 @@ const TMAreaManager = (props = { selectionMode: 'multiple', isPathChooser: false
253
253
  else {
254
254
  msg = SDKUI_Localizator.FileManager_QuestionAlreadyExistsFiles.replaceParams(resolvesForExistingFiles.length.toString());
255
255
  }
256
- const result = confirm(msg, SDKUI_Localizator.Attention);
257
- result.then((dialogResult) => {
256
+ const confirmDialog = custom({
257
+ title: SDKUI_Localizator.Attention,
258
+ messageHtml: `<div style="padding: 15px; font-size: 1rem; max-width: 500px; word-wrap: break-word; overflow-wrap: break-word;">${msg}</div>`,
259
+ buttons: [
260
+ {
261
+ text: SDKUI_Localizator.Yes ?? "Yes",
262
+ onClick: () => true,
263
+ type: "default",
264
+ stylingMode: "contained"
265
+ },
266
+ {
267
+ text: SDKUI_Localizator.No ?? "No",
268
+ onClick: () => false,
269
+ stylingMode: "outlined"
270
+ }
271
+ ]
272
+ });
273
+ confirmDialog.show().then((dialogResult) => {
258
274
  resolvesForNonExistingFiles.forEach((res) => {
259
275
  res({
260
276
  cancel: false,
@@ -22,7 +22,7 @@ const TMDataGrid = React.forwardRef((props, ref) => {
22
22
  // events and callbacks
23
23
  onSelectionChanged, onFocusedRowChanged, onRowDblClick, onRowClick, onCellClick, onCellDblClick, onOptionChanged, onContentReady, onContextMenuPreparing, onInitialized, onEditorPreparing, onCellPrepared, onRowPrepared, onRowUpdating, onRowExpanded, onRowCollapsed, onRowUpdated, onSaved, onEditCanceled, onEditingStart, onEditingChange, customizeColumns, onKeyDown, scrolling = { mode: 'standard', useNative: SDKUI_Globals.userSettings?.themeSettings.gridSettings.useNativeScrollbar === 1 }, paging = { enabled: true, pageSize: pageSize }, pager = { visible: true, showInfo: true, showNavigationButtons: true }, selection = { mode: 'multiple', showCheckBoxesMode: "always", selectAllMode: "allPages" }, sorting, summary, stateStoring, grouping, groupPanel, filterRow, headerFilter, editing, rowDragging, masterDetail,
24
24
  // other properties
25
- disabled = false, autoNavigateToFocusedRow = true, columnResizingMode = 'widget', columnHidingEnabled = true, columnAutoWidth = true, allowColumnResizing = true, allowColumnReordering = true, showBorders = true, showRowLines = SDKUI_Globals.userSettings?.themeSettings.gridSettings.showRowLines === 1, showColumnLines = SDKUI_Globals.userSettings?.themeSettings.gridSettings.showColumnLines === 1, showColumnHeaders = true, rowAlternationEnabled = false, wordWrapEnabled = false, noDataText,
25
+ disabled = false, autoNavigateToFocusedRow = true, columnResizingMode = 'widget', columnHidingEnabled = true, columnAutoWidth = true, allowColumnResizing = true, allowColumnReordering = true, showBorders = true, showRowLines = SDKUI_Globals.userSettings?.themeSettings.gridSettings.showRowLines === 1, showColumnLines = SDKUI_Globals.userSettings?.themeSettings.gridSettings.showColumnLines === 1, showColumnHeaders = true, rowAlternationEnabled = false, wordWrapEnabled = false, noDataText, columnMinWidth,
26
26
  // styles
27
27
  id, width = '100%', height = '100%', } = props;
28
28
  const internalRef = React.useRef(null);
@@ -354,7 +354,7 @@ const TMDataGrid = React.forwardRef((props, ref) => {
354
354
  // events and callbacks
355
355
  onSelectionChanged: onSelectionChangedCallback, onRowDblClick: onRowDblClickCallback, onRowPrepared: onRowPrepared, onContextMenuPreparing: onContextMenuPreparingCallback, onToolbarPreparing: onToolbarPreparingCallback, onFocusedRowChanged: onFocusedRowChanged, onRowClick: onRowClick, onCellClick: onCellClick, onCellDblClick: onCellDblClick, onOptionChanged: onOptionChangedCallback, onContentReady: onContentReadyCallback, onInitialized: onInitialized, customizeColumns: customizeColumns, onEditorPreparing: onEditorPreparing, onCellPrepared: onCellPrepared, onRowUpdating: onRowUpdating, onRowExpanded: onRowExpanded, onRowCollapsed: onRowCollapsed, onRowUpdated: onRowUpdated, onSaved: onSaved, onEditCanceled: onEditCanceled, onEditingStart: onEditingStart, onEditingChange: onEditingChange, onKeyDown: onKeyDown,
356
356
  // other properties
357
- disabled: disabled, autoNavigateToFocusedRow: autoNavigateToFocusedRow, focusedRowKey: focusedRowKey, columnHidingEnabled: columnHidingEnabled, columnResizingMode: columnResizingMode, columnAutoWidth: columnAutoWidth, allowColumnResizing: allowColumnResizing, allowColumnReordering: allowColumnReordering, showBorders: showBorders, showRowLines: showRowLines, showColumnLines: showColumnLines, showColumnHeaders: showColumnHeaders, rowAlternationEnabled: rowAlternationEnabled, wordWrapEnabled: wordWrapEnabled, noDataText: noDataText,
357
+ disabled: disabled, autoNavigateToFocusedRow: autoNavigateToFocusedRow, focusedRowKey: focusedRowKey, columnHidingEnabled: columnHidingEnabled, columnResizingMode: columnResizingMode, columnAutoWidth: columnAutoWidth, allowColumnResizing: allowColumnResizing, allowColumnReordering: allowColumnReordering, showBorders: showBorders, showRowLines: showRowLines, showColumnLines: showColumnLines, showColumnHeaders: showColumnHeaders, rowAlternationEnabled: rowAlternationEnabled, wordWrapEnabled: wordWrapEnabled, columnMinWidth: columnMinWidth, noDataText: noDataText,
358
358
  // styles
359
359
  width: width, height: height, style: {
360
360
  userSelect: 'none',
@@ -13,6 +13,7 @@ interface ITMModal {
13
13
  hidePopup?: boolean;
14
14
  askClosingConfirm?: boolean;
15
15
  showCloseButton?: boolean;
16
+ showHeader?: boolean;
16
17
  }
17
18
  declare const TMModal: React.FC<ITMModal>;
18
19
  export default TMModal;
@@ -39,7 +39,7 @@ const StyledModalContext = styled.div `
39
39
  overflow: auto;
40
40
  height: 100%;
41
41
  `;
42
- const TMModal = ({ resizable = true, expandable = false, isModal = true, title = '', toolbar, onClose, children, width = '100%', height = '100%', fontSize = FontSize.defaultFontSize, hidePopup = true, askClosingConfirm = false, showCloseButton = true }) => {
42
+ const TMModal = ({ resizable = true, expandable = false, isModal = true, title = '', toolbar, onClose, children, width = '100%', height = '100%', fontSize = FontSize.defaultFontSize, hidePopup = true, askClosingConfirm = false, showCloseButton = true, showHeader = true }) => {
43
43
  const popupRef = useRef(null);
44
44
  const [initialWidth, setInitialWidth] = useState(width);
45
45
  const [initialHeight, setInitialHeight] = useState(height);
@@ -101,7 +101,7 @@ const TMModal = ({ resizable = true, expandable = false, isModal = true, title =
101
101
  setShowPopup(false);
102
102
  onClose && onClose();
103
103
  };
104
- return (_jsx(_Fragment, { children: isModal ? (_jsx(Popup, { ref: popupRef, showCloseButton: showCloseButton, animation: undefined, minWidth: minWidth, minHeight: minHeight, maxHeight: '95%', maxWidth: '95%', dragEnabled: !isResizing, resizeEnabled: resizable, width: expandable && isFullScreen ? '95%' : initialWidth, height: expandable && isFullScreen ? '95%' : initialHeight, title: title, visible: showPopup, onShown: handleShown, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd, onHiding: onHiding, toolbarItems: expandable ? [
104
+ return (_jsx(_Fragment, { children: isModal ? (_jsx(Popup, { ref: popupRef, showCloseButton: showHeader ? showCloseButton : false, showTitle: showHeader, animation: undefined, minWidth: minWidth, minHeight: minHeight, maxHeight: '95%', maxWidth: '95%', dragEnabled: !isResizing, resizeEnabled: resizable, width: expandable && isFullScreen ? '95%' : initialWidth, height: expandable && isFullScreen ? '95%' : initialHeight, title: title, visible: showPopup, onShown: handleShown, onResizeStart: handleResizeStart, onResizeEnd: handleResizeEnd, onHiding: onHiding, toolbarItems: showHeader && expandable ? [
105
105
  {
106
106
  widget: 'dxButton',
107
107
  location: 'after',
@@ -1,7 +1,3 @@
1
- /** Gestione TMPanel "attivo / non attivo" secondo una pattern ibrido (Controlled/Uncontrolled Component):
2
- 1) Modalità Non Controllata (Uncontrolled): Se non gli viene passata la prop "isActive", il pannello gestisce lo stato "attivo" internamente. Per l'uso singolo ("plug-and-play").
3
- 2) Modalità Controllata (Controlled): Se il genitore passa la prop "isActive", il pannello cede il controllo e si affida completamente al genitore. Ideale per layout con più pannelli che necessitano di coordinamento.
4
- */
5
1
  import React from 'react';
6
2
  export interface ITMPanelRef {
7
3
  focusPanel: () => void;
@@ -28,5 +24,12 @@ export interface ITMPanelProps {
28
24
  onHeaderDoubleClick?: () => void;
29
25
  onMaximize?: (isMaximized: boolean) => void;
30
26
  }
27
+ /**
28
+ * TMPanel - Pannello con supporto Controlled/Uncontrolled
29
+ *
30
+ * @prop isActive (opzionale)
31
+ * - Se NON passata → Uncontrolled: gestione interna dello stato attivo (plug-and-play)
32
+ * - Se passata → Controlled: il parent gestisce lo stato tramite onActivate
33
+ */
31
34
  declare const TMPanel: React.ForwardRefExoticComponent<ITMPanelProps & React.RefAttributes<ITMPanelRef>>;
32
35
  export default TMPanel;
@@ -1,14 +1,35 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- /** Gestione TMPanel "attivo / non attivo" secondo una pattern ibrido (Controlled/Uncontrolled Component):
3
- 1) Modalità Non Controllata (Uncontrolled): Se non gli viene passata la prop "isActive", il pannello gestisce lo stato "attivo" internamente. Per l'uso singolo ("plug-and-play").
4
- 2) Modalità Controllata (Controlled): Se il genitore passa la prop "isActive", il pannello cede il controllo e si affida completamente al genitore. Ideale per layout con più pannelli che necessitano di coordinamento.
5
- */
6
2
  import { useCallback, useRef, useState, forwardRef, useImperativeHandle } from 'react';
7
3
  import styled from 'styled-components';
8
4
  import { getAppModuleGradient, IconArrowLeft, IconClearButton, IconWindowMaximize, IconWindowMinimize, isPositiveNumber, SDKUI_Localizator } from '../../helper';
9
5
  import TMButton from './TMButton';
10
6
  import { Gutters } from '../../utils/theme';
7
+ const StyledBackButton = styled.button `
8
+ display: flex;
9
+ align-items: center;
10
+ justify-content: center;
11
+ gap: 4px;
12
+ padding: 4px 10px;
13
+ border: 1px solid ${({ $isActive }) => $isActive ? 'rgba(37, 89, 165, 0.3)' : 'rgba(255, 255, 255, 0.4)'};
14
+ border-radius: 6px;
15
+ cursor: pointer;
16
+ font-weight: 500;
17
+ font-size: 0.85rem;
18
+ flex-shrink: 0;
19
+ transition: all 0.15s ease;
20
+ background-color: ${({ $isActive }) => $isActive ? '#FFFFFF' : '#2559A5'};
21
+ box-shadow: none;
22
+
23
+ &&, && * {
24
+ color: ${({ $isActive }) => $isActive ? '#2559A5' : '#FFFFFF'} !important;
25
+ }
26
+
27
+ svg {
28
+ font-size: 14px;
29
+ }
30
+ `;
11
31
  import { AppModules, SDK_Globals } from '@topconsultnpm/sdk-ts';
32
+ import { DeviceType, useDeviceType } from './TMDeviceProvider';
12
33
  const StyledPanelContainer = styled.div `
13
34
  width: 100%;
14
35
  height: 100%;
@@ -75,9 +96,19 @@ const StyledPanelContent = styled.div `
75
96
  outline: none;
76
97
  }
77
98
  `;
99
+ /**
100
+ * TMPanel - Pannello con supporto Controlled/Uncontrolled
101
+ *
102
+ * @prop isActive (opzionale)
103
+ * - Se NON passata → Uncontrolled: gestione interna dello stato attivo (plug-and-play)
104
+ * - Se passata → Controlled: il parent gestisce lo stato tramite onActivate
105
+ */
78
106
  const TMPanel = forwardRef(({ allowMaximize = true, color, backgroundColor, backgroundColorContainer, children, showHeader = true, title, totalItems, displayedItemsCount, toolbar, padding = '5px', isVisible = true, panelID = 'tmpanel', isActive, // Questa prop determinerà la modalità
79
107
  onActivate, onBack, onClose, onHeaderDoubleClick, onMaximize, onActiveChanged }, ref) => {
80
108
  const [isMaximized, setIsMaximized] = useState(false);
109
+ // Detect device type (e.g., mobile or desktop)
110
+ const deviceType = useDeviceType();
111
+ const isMobile = deviceType === DeviceType.MOBILE;
81
112
  // INTERNAL STATUS for UNCONTROLLED mode
82
113
  const [internalIsActive, setInternalIsActive] = useState(false);
83
114
  const panelRef = useRef(null);
@@ -149,36 +180,37 @@ onActivate, onBack, onClose, onHeaderDoubleClick, onMaximize, onActiveChanged },
149
180
  flexDirection: 'row',
150
181
  alignItems: 'center',
151
182
  width: '100%',
152
- minWidth: 0
153
- }, children: [_jsxs("div", { style: {
183
+ minWidth: 0,
184
+ flexWrap: 'nowrap',
185
+ overflow: 'hidden'
186
+ }, children: [onBack && _jsx("div", { style: {
154
187
  display: 'flex',
155
188
  flexDirection: 'row',
156
189
  alignItems: 'center',
157
- gap: '8px',
190
+ flexShrink: 0
191
+ }, children: _jsxs(StyledBackButton, { "$isActive": currentIsActive, onClick: () => onBack ? onBack() : null, title: SDKUI_Localizator.Back, children: [_jsx(IconArrowLeft, {}), !isMobile && _jsx("span", { children: SDKUI_Localizator.Back })] }) }), _jsx("div", { style: {
158
192
  flex: 1,
159
- minWidth: 0
160
- }, children: [onBack &&
161
- _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconArrowLeft, {}), caption: SDKUI_Localizator.Back, onClick: onBack }), _jsx("div", { style: {
162
- display: 'flex',
163
- flexDirection: 'row',
164
- alignItems: 'center',
165
- overflow: 'hidden',
166
- }, children: _jsxs("div", { style: {
167
- whiteSpace: 'nowrap',
168
- overflow: 'hidden',
169
- textOverflow: 'ellipsis',
170
- margin: 0
171
- }, children: [title, isPositiveNumber(displayedItemsCount) && isPositiveNumber(totalItems)
172
- ? ` (${displayedItemsCount} / ${totalItems})`
173
- : isPositiveNumber(totalItems)
174
- ? ` (${totalItems})`
175
- : ''] }) })] }), _jsxs("div", { style: {
193
+ display: 'flex',
194
+ alignItems: 'center',
195
+ justifyContent: 'flex-start',
196
+ minWidth: 0,
197
+ overflow: 'hidden',
198
+ padding: '0 8px'
199
+ }, children: _jsxs("div", { style: {
200
+ whiteSpace: 'nowrap',
201
+ overflow: 'hidden',
202
+ textOverflow: 'ellipsis',
203
+ margin: 0
204
+ }, children: [title, isPositiveNumber(displayedItemsCount) && isPositiveNumber(totalItems)
205
+ ? ` (${displayedItemsCount} / ${totalItems})`
206
+ : isPositiveNumber(totalItems)
207
+ ? ` (${totalItems})`
208
+ : ''] }) }), _jsxs("div", { style: {
176
209
  display: 'flex',
177
210
  flexDirection: 'row',
178
211
  alignItems: 'center',
179
212
  gap: '5px',
180
- flexShrink: 0,
181
- marginLeft: 10
213
+ flexShrink: 0
182
214
  }, children: [toolbar, allowMaximize && _jsx(TMButton, { color: 'primaryOutline', caption: isMaximized ? SDKUI_Localizator.Minimize : SDKUI_Localizator.Maximize, icon: isMaximized
183
215
  ? _jsx(IconWindowMinimize, { fontSize: 16 })
184
216
  : _jsx(IconWindowMaximize, { fontSize: 16 }), btnStyle: 'icon', onClick: handleMaximize }), onClose && _jsx(TMButton, { color: 'primaryOutline', caption: SDKUI_Localizator.Close, icon: _jsx(IconClearButton, {}), btnStyle: 'icon', onClick: () => { setIsMaximized(false); onClose?.(); } })] })] }) }), _jsx(StyledPanelContent, { "$height": showHeader ? "calc(100% - 40px)" : "100%", "$padding": padding, "$backgroundColor": backgroundColorContainer ?? `#FFFFFF`, children: children })] }));
@@ -9,23 +9,28 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
9
9
  if (!focusedItem)
10
10
  return;
11
11
  let newFocusedItem = null;
12
+ let handled = false;
12
13
  switch (event.key) {
13
14
  case 'ArrowDown':
14
15
  newFocusedItem = findNextItem(dataSource, focusedItem);
16
+ handled = true;
15
17
  break;
16
18
  case 'ArrowUp':
17
19
  newFocusedItem = findPreviousItem(dataSource, focusedItem);
20
+ handled = true;
18
21
  break;
19
22
  case '+':
20
23
  if (!focusedItem.expanded) {
21
24
  handleNodeToggle(focusedItem.key, false);
22
25
  newFocusedItem = { ...focusedItem, expanded: true };
26
+ handled = true;
23
27
  }
24
28
  break;
25
29
  case '-':
26
30
  if (focusedItem.expanded) {
27
31
  handleNodeToggle(focusedItem.key, false);
28
32
  newFocusedItem = { ...focusedItem, expanded: false };
33
+ handled = true;
29
34
  }
30
35
  break;
31
36
  // case ' ':
@@ -40,12 +45,17 @@ const TMTreeView = ({ dataSource = [], focusedItem, selectedItems = [], allowMul
40
45
  default:
41
46
  break;
42
47
  }
48
+ if (handled) {
49
+ event.preventDefault();
50
+ event.stopPropagation();
51
+ }
43
52
  if (newFocusedItem)
44
53
  onFocusedItemChanged?.(newFocusedItem);
45
54
  };
46
- window.addEventListener('keydown', handleKeyDown);
55
+ // Usa capture: true per intercettare l'evento PRIMA che DevExtreme Popup lo gestisca
56
+ window.addEventListener('keydown', handleKeyDown, true);
47
57
  return () => {
48
- window.removeEventListener('keydown', handleKeyDown);
58
+ window.removeEventListener('keydown', handleKeyDown, true);
49
59
  };
50
60
  }, [focusedItem, dataSource, onFocusedItemChanged]);
51
61
  const findNextItem = (nodes, currentItem) => {
@@ -18,13 +18,16 @@ const StyledWaitPanel = styled.div `
18
18
  top: 50%;
19
19
  left: 50%;
20
20
  transform: translate(-50%, -50%);
21
- width: 300px;
22
- height: ${(props) => props.$height};
21
+ width: 300px;
22
+ max-width: calc(100% - 20px);
23
+ height: auto;
24
+ max-height: calc(100% - 20px);
23
25
  background: white;
24
26
  border-radius: 8px;
25
27
  padding: 10px;
26
28
  text-align: center;
27
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
29
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
30
+ overflow: auto;
28
31
  `;
29
32
  const StyledTitle = styled.h2 ` margin: 0; font-size: 1.5em; color: #333; `;
30
33
  const StyledProgressBarContainer = styled.div ` width: 100%; height: 20px; background: #e0e0e0; border-radius: 10px; overflow: hidden; margin: 20px 0; `;
@@ -42,7 +45,7 @@ export const TMWaitPanel = (props) => {
42
45
  };
43
46
  let progressValue1 = calculateProgress(valuePrimary, maxValuePrimary);
44
47
  let progressValue2 = calculateProgress(valueSecondary, maxValueSecondary);
45
- return (_jsx(StyledWaitPanelOverlay, { children: _jsxs(StyledWaitPanel, { "$height": (showPrimary && showSecondary) ? '350px' : '250px', children: [_jsx(StyledTitle, { children: title }), showPrimary &&
48
+ return (_jsx(StyledWaitPanelOverlay, { children: _jsxs(StyledWaitPanel, { children: [_jsx(StyledTitle, { children: title }), showPrimary &&
46
49
  _jsxs("div", { style: { width: '100%', height: '100px' }, children: [_jsx(StyledProgressBarContainer, { children: _jsx(StyledProgressBar, { style: { width: `${progressValue1.toFixed(2)}%` } }) }), _jsxs(StyledProgressText, { children: [progressValue1.toFixed(2), "%"] }), _jsx(StyledMessage, { children: textPrimary })] }), showSecondary &&
47
50
  _jsxs("div", { style: { width: '100%', height: '100px' }, children: [_jsx(StyledProgressBarContainer, { children: _jsx(StyledProgressBar, { style: { width: `${progressValue2.toFixed(2)}%` } }) }), _jsxs(StyledProgressText, { children: [progressValue2.toFixed(2), "%"] }), _jsx(StyledMessage, { children: textSecondary })] }), isCancelable && _jsx(StyledAbortButton, { onClick: () => onAbortClick?.(abortController), children: SDKUI_Localizator.Abort })] }) }));
48
51
  };
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useMemo, useState } from 'react';
3
- import { LayoutModes, MetadataDataDomains, AccessLevels, MetadataDataTypes, SDK_Globals, DcmtTypeListCacheService, DataColumnTypes } from '@topconsultnpm/sdk-ts';
3
+ import { LayoutModes, MetadataDataDomains, AccessLevels, MetadataDataTypes, SDK_Globals, DcmtTypeListCacheService, DataColumnTypes, DataListViewModes } from '@topconsultnpm/sdk-ts';
4
4
  import styled from 'styled-components';
5
5
  import { SDKUI_Localizator, stringIsNullOrEmpty } from '../../helper';
6
6
  import TMDataGrid, { TMDataGridPageSize } from '../base/TMDataGrid';
@@ -9,14 +9,17 @@ import TMSpinner from '../base/TMSpinner';
9
9
  import TMCheckBox from '../editors/TMCheckBox';
10
10
  import TMPanel from '../base/TMPanel';
11
11
  import TMModal from '../base/TMModal';
12
+ import { useDataListItem } from '../../hooks/useDataListItem';
13
+ import { useDataUserIdItem } from '../../hooks/useDataUserIdItem';
12
14
  const StyledDistinctValues = styled.div `display: flex; flex-direction: column; height: 100%; overflow: hidden; gap: 10px;`;
13
- const StyledPanelContainer = styled.div ` width: 100%; height: 100%; padding: 20px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 20px; `;
14
15
  const TMDistinctValues = ({ tid, mid, layoutMode = LayoutModes.None, allowAppendMode = true, showHeader = true, isModal, separator = " ", onSelectionChanged, onClosePanelCallback }) => {
15
16
  const [focusedItem, setFocusedItem] = useState();
16
17
  const [dataSource, setDataSource] = useState([]);
17
18
  const [isAppendMode, setIsAppendMode] = useState(false);
18
19
  const [md, setMd] = useState();
19
20
  const [currentValue, setCurrentValue] = useState('');
21
+ const { loadDataListsAsync, renderDataListCell, dataListsCache } = useDataListItem();
22
+ const { loadUsersAsync, renderUserIdViewer, usersCache } = useDataUserIdItem();
20
23
  useEffect(() => {
21
24
  getDistictValuesAsync();
22
25
  }, [mid]);
@@ -57,8 +60,23 @@ const TMDistinctValues = ({ tid, mid, layoutMode = LayoutModes.None, allowAppend
57
60
  try {
58
61
  TMSpinner.show({ description: 'Caricamento dei valori distinti...' });
59
62
  let dtd = await DcmtTypeListCacheService.GetAsync(tid, true);
60
- setMd(dtd?.metadata?.find(o => o.id === mid));
63
+ const currentMd = dtd?.metadata?.find(o => o.id === mid);
64
+ setMd(currentMd);
61
65
  let result = await SDK_Globals.tmSession?.NewSearchEngine().GetDistinctValuesAsync(tid, mid, 10000);
66
+ // Load DataList or UserID cache based on metadata domain
67
+ if (currentMd?.dataDomain === MetadataDataDomains.DataList && currentMd.dataListID) {
68
+ await loadDataListsAsync(new Set([currentMd.dataListID]));
69
+ }
70
+ if (currentMd?.dataDomain === MetadataDataDomains.UserID && result?.dtdResult?.rows) {
71
+ const userIDs = new Set();
72
+ result.dtdResult.rows.forEach((row) => {
73
+ const userId = Number(row[0]);
74
+ if (userId && userId > 0) {
75
+ userIDs.add(userId);
76
+ }
77
+ });
78
+ await loadUsersAsync(userIDs);
79
+ }
62
80
  setDataSource(convertDataTableToObject(result?.dtdResult));
63
81
  }
64
82
  catch (e) {
@@ -69,31 +87,27 @@ const TMDistinctValues = ({ tid, mid, layoutMode = LayoutModes.None, allowAppend
69
87
  TMSpinner.hide();
70
88
  }
71
89
  };
72
- const getDcmtTypeAsync = async () => {
73
- if (!tid)
74
- return;
75
- try {
76
- TMSpinner.show({ description: 'Caricamento dei valori distinti...' });
77
- let dtd = await DcmtTypeListCacheService.GetAsync(tid, true);
78
- setMd(dtd?.metadata?.find(o => o.id === mid));
79
- }
80
- catch (e) {
81
- let err = e;
82
- TMExceptionBoxManager.show({ exception: err });
83
- }
84
- finally {
85
- TMSpinner.hide();
86
- }
87
- };
88
90
  const onFocusedRowChanged = useCallback((e) => {
89
91
  setFocusedItem(e.row?.data);
90
92
  }, []);
93
+ const valueCellRender = useCallback((cellData) => {
94
+ if (!cellData || cellData.value === undefined)
95
+ return null;
96
+ if (md?.dataDomain === MetadataDataDomains.DataList && md.dataListID) {
97
+ return renderDataListCell(cellData.value, md.dataListID, md.dataListViewMode ?? DataListViewModes.None);
98
+ }
99
+ if (md?.dataDomain === MetadataDataDomains.UserID) {
100
+ return renderUserIdViewer(Number(cellData.value), true);
101
+ }
102
+ return _jsx("div", { children: cellData.text });
103
+ }, [md, renderDataListCell, renderUserIdViewer]);
91
104
  const customColumns = useMemo(() => {
105
+ const needsCellRender = md?.dataDomain === MetadataDataDomains.DataList || md?.dataDomain === MetadataDataDomains.UserID;
92
106
  return ([
93
- { dataField: 'value', dataType: md?.dataType === MetadataDataTypes.DateTime ? 'date' : 'string', caption: md?.nameLoc, width: 'min-content' },
107
+ { dataField: 'value', dataType: md?.dataType === MetadataDataTypes.DateTime ? 'date' : 'string', caption: md?.nameLoc, width: 'min-content', ...(needsCellRender && { cellRender: valueCellRender }) },
94
108
  { dataField: 'Count', dataType: 'number', caption: 'N°' }
95
109
  ]);
96
- }, [md]);
110
+ }, [md, valueCellRender]);
97
111
  const customSummary = useMemo(() => {
98
112
  return ({
99
113
  totalItems: [
@@ -16,6 +16,8 @@ interface ITMUserChooserProps extends ITMChooserProps {
16
16
  initialShowChooser?: boolean;
17
17
  /** Allow showing all users with toggle button */
18
18
  allowShowAllUsers?: boolean;
19
+ /** If true, uses UserListCacheService.GetAllAdminAsync() instead of GetAllAsync() */
20
+ adminMode?: boolean;
19
21
  /** Funzione per aggiornare lo stato di apertura della modale */
20
22
  updateIsModalOpen?: (isOpen: boolean) => void;
21
23
  }
@@ -30,6 +32,8 @@ interface ITMUserChooserFormProps extends ITMChooserFormProps<UserDescriptor> {
30
32
  hideShowId?: boolean;
31
33
  /** Allow showing all users with toggle button */
32
34
  allowShowAllUsers?: boolean;
35
+ /** If true, uses UserListCacheService.GetAllAdminAsync() instead of GetAllAsync() */
36
+ adminMode?: boolean;
33
37
  }
34
38
  export declare const TMUserChooserForm: React.FunctionComponent<ITMUserChooserFormProps>;
35
39
  export declare const TMUserIcon: ({ ud }: {
@@ -8,7 +8,7 @@ import TMSummary from '../editors/TMSummary';
8
8
  import TMChooserForm from '../forms/TMChooserForm';
9
9
  import TMButton from '../base/TMButton';
10
10
  import TMDataUserIdItemViewer from '../viewers/TMDataUserIdItemViewer';
11
- const TMUserChooser = ({ labelColor, titleForm, filter, readOnly = false, icon, width, dataSource, backgroundColor, openChooserBySingleClick, buttons = [], disabled = false, showBorder = true, hideRefresh = false, hideShowId = false, elementStyle, allowMultipleSelection, values, isModifiedWhen, label, placeHolder, validationItems = [], onValueChanged, showClearButton, initialShowChooser = false, allowShowAllUsers = false, updateIsModalOpen }) => {
11
+ const TMUserChooser = ({ labelColor, titleForm, filter, readOnly = false, icon, width, dataSource, backgroundColor, openChooserBySingleClick, buttons = [], disabled = false, showBorder = true, hideRefresh = false, hideShowId = false, elementStyle, allowMultipleSelection, values, isModifiedWhen, label, placeHolder, validationItems = [], onValueChanged, showClearButton, initialShowChooser = false, allowShowAllUsers = false, adminMode = false, updateIsModalOpen }) => {
12
12
  const [showChooser, setShowChooser] = useState(initialShowChooser);
13
13
  useEffect(() => {
14
14
  setShowChooser(initialShowChooser);
@@ -24,14 +24,14 @@ const TMUserChooser = ({ labelColor, titleForm, filter, readOnly = false, icon,
24
24
  updateIsModalOpen?.(true);
25
25
  }
26
26
  }, elementStyle: elementStyle, isModifiedWhen: isModifiedWhen, openEditorOnSummaryClick: openChooserBySingleClick, label: label, template: renderTemplate(), onClearClick: showClearButton ? () => { onValueChanged?.([]); } : undefined, validationItems: validationItems }), showChooser &&
27
- _jsx(TMUserChooserForm, { title: titleForm, allowMultipleSelection: allowMultipleSelection, hasShowOnlySelectedItems: true, dataSource: dataSource, filter: filter, selectedIDs: values, hideRefresh: hideRefresh, hideShowId: hideShowId, allowShowAllUsers: allowShowAllUsers, onClose: () => {
27
+ _jsx(TMUserChooserForm, { title: titleForm, allowMultipleSelection: allowMultipleSelection, hasShowOnlySelectedItems: true, dataSource: dataSource, filter: filter, selectedIDs: values, hideRefresh: hideRefresh, hideShowId: hideShowId, allowShowAllUsers: allowShowAllUsers, adminMode: adminMode, onClose: () => {
28
28
  setShowChooser(false);
29
29
  summaryInputRef.current?.focus();
30
30
  updateIsModalOpen?.(false);
31
31
  }, onChoose: (IDs) => { onValueChanged?.(IDs); } })] }));
32
32
  };
33
33
  export default TMUserChooser;
34
- export const TMUserChooserForm = ({ allowMultipleSelection, columns, hideRefresh = false, hideShowId = false, startWithShowOnlySelectedItems = true, filter, title, hasShowOnlySelectedItems, width, height, selectedIDs, dataSource, onClose, onChoose, allowShowAllUsers = false }) => {
34
+ export const TMUserChooserForm = ({ allowMultipleSelection, columns, hideRefresh = false, hideShowId = false, startWithShowOnlySelectedItems = true, filter, title, hasShowOnlySelectedItems, width, height, selectedIDs, dataSource, onClose, onChoose, allowShowAllUsers = false, adminMode = false }) => {
35
35
  const [currentDataSource, setCurrentDataSource] = useState(dataSource);
36
36
  const [showingAllUsers, setShowingAllUsers] = useState(false);
37
37
  const dataColumns = useMemo(() => {
@@ -45,8 +45,10 @@ export const TMUserChooserForm = ({ allowMultipleSelection, columns, hideRefresh
45
45
  const getItems = async (refreshCache) => {
46
46
  TMSpinner.show({ description: `${SDKUI_Localizator.Loading} - ${SDK_Localizator.Users} ...` });
47
47
  if (refreshCache)
48
- UserListCacheService.RemoveAll();
49
- let allUsers = await UserListCacheService.GetAllAsync();
48
+ adminMode ? UserListCacheService.RemoveAllAdmin() : UserListCacheService.RemoveAll();
49
+ let allUsers = adminMode
50
+ ? await UserListCacheService.GetAllAdminAsync()
51
+ : await UserListCacheService.GetAllAsync();
50
52
  let users = filter ? allUsers?.filter(filter) : allUsers;
51
53
  TMSpinner.hide();
52
54
  return users;
@@ -1,11 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useRef } from 'react';
2
+ import { useEffect, useId, useRef } from 'react';
3
3
  import { DateBox } from 'devextreme-react';
4
4
  import { DateDisplayTypes, Globalization } from '../../helper';
5
5
  import { TMColors } from '../../utils/theme';
6
6
  import TMVilViewer from '../base/TMVilViewer';
7
7
  const TMDateBox = (props) => {
8
8
  const resetTimeToZero = props.resetTimeToZeroOnKeyPress ?? true;
9
+ const autoId = useId();
10
+ const effectiveInputAttr = { id: autoId, ...props.inputAttr };
9
11
  useEffect(() => {
10
12
  let htmlElement = dateBoxRef?.current?.instance().element();
11
13
  if (!htmlElement)
@@ -63,7 +65,7 @@ const TMDateBox = (props) => {
63
65
  return "datetime";
64
66
  return props.dateDisplayType == DateDisplayTypes.Date ? "date" : "time";
65
67
  };
66
- return (_jsxs("div", { style: { display: 'flex', alignItems: 'center', width: '100%', padding: props.padding }, children: [props.icon && (_jsx("span", { style: { marginRight: '8px', marginTop: '8px', display: 'flex', alignItems: 'center' }, children: props.icon })), _jsxs("div", { onContextMenu: (e) => e.stopPropagation(), style: { display: 'flex', flexDirection: 'column', gap: '5px', width: '100%' }, children: [_jsx(DateBox, { readOnly: props.readOnly, ref: dateBoxRef, showClearButton: props.showClearButton, dateSerializationFormat: props.useDateSerializationFormat ? 'yyyy-MM-ddTHH:mm:ss' : undefined, disabled: props.disabled, displayFormat: props.displayFormat ?? Globalization.getDateDisplayFormat(props.dateDisplayType), dropDownOptions: dropDownOptions, label: props.label, labelMode: 'static', type: getType(), useMaskBehavior: true, height: '28px', value: props.value, width: props.width, valueChangeEvent: 'keyup input change', onValueChange: (e) => { props.onValueChange?.(e); }, onInitialized: (e) => { props.onInitialized?.(e); }, onContentReady: (e) => { props.onContentReady?.(e); }, placeholder: props.placeholder, onKeyUp: (e) => {
68
+ return (_jsxs("div", { style: { display: 'flex', alignItems: 'center', width: '100%', padding: props.padding }, children: [props.icon && (_jsx("span", { style: { marginRight: '8px', marginTop: '8px', display: 'flex', alignItems: 'center' }, children: props.icon })), _jsxs("div", { onContextMenu: (e) => e.stopPropagation(), style: { display: 'flex', flexDirection: 'column', gap: '5px', width: '100%' }, children: [_jsx(DateBox, { readOnly: props.readOnly, ref: dateBoxRef, showClearButton: props.showClearButton, dateSerializationFormat: props.useDateSerializationFormat ? 'yyyy-MM-ddTHH:mm:ss' : undefined, disabled: props.disabled, displayFormat: props.displayFormat ?? Globalization.getDateDisplayFormat(props.dateDisplayType), dropDownOptions: dropDownOptions, label: props.label, labelMode: 'static', type: getType(), useMaskBehavior: true, height: '28px', value: props.value, width: props.width, valueChangeEvent: 'keyup input change', onValueChange: (e) => { props.onValueChange?.(e); }, onInitialized: (e) => { props.onInitialized?.(e); }, onContentReady: (e) => { props.onContentReady?.(e); }, placeholder: props.placeholder, ...(props.name && { name: props.name }), inputAttr: effectiveInputAttr, onKeyUp: (e) => {
67
69
  if (e.event?.code == "Space") {
68
70
  const currentDate = new Date();
69
71
  currentDate.setHours(0, 0, 0, 0);
@@ -27,11 +27,13 @@ export declare class FormulaDescriptor {
27
27
  mid?: number;
28
28
  metadataDataTypeDest?: MetadataDataTypes;
29
29
  tid?: number;
30
+ description?: string;
30
31
  }
31
32
  export declare const renderFormulaIcon: (iconType: FormulaIconTypes, tid?: number, md?: MetadataDescriptor) => import("react/jsx-runtime").JSX.Element;
32
33
  declare const TMFormulaEditor: React.FunctionComponent<ITMApplyFormProps<FormulaDescriptor>>;
33
34
  export default TMFormulaEditor;
34
35
  export declare class FormulaHelper {
36
+ static translateDescInFormula: (text: string, returnType?: string) => string;
35
37
  static isFormula(value: string | undefined): boolean;
36
38
  static removeFormulaTag(value: string | undefined): string | undefined;
37
39
  static addFormulaTag(value: string | undefined): string | undefined;