@topconsultnpm/sdkui-react 6.20.0-dev1.6 → 6.20.0-dev1.60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/NewComponents/ContextMenu/TMContextMenu.d.ts +4 -0
- package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +416 -0
- package/lib/components/NewComponents/ContextMenu/hooks.d.ts +13 -0
- package/lib/components/NewComponents/ContextMenu/hooks.js +61 -0
- package/lib/components/NewComponents/ContextMenu/index.d.ts +5 -0
- package/lib/components/NewComponents/ContextMenu/index.js +3 -0
- package/lib/components/NewComponents/ContextMenu/styles.d.ts +31 -0
- package/lib/components/NewComponents/ContextMenu/styles.js +336 -0
- package/lib/components/NewComponents/ContextMenu/types.d.ts +39 -0
- package/lib/components/NewComponents/ContextMenu/types.js +1 -0
- package/lib/components/NewComponents/ContextMenu/useLongPress.d.ts +21 -0
- package/lib/components/NewComponents/ContextMenu/useLongPress.js +112 -0
- package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.d.ts +4 -0
- package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +745 -0
- package/lib/components/NewComponents/FloatingMenuBar/index.d.ts +2 -0
- package/lib/components/NewComponents/FloatingMenuBar/index.js +2 -0
- package/lib/components/NewComponents/FloatingMenuBar/styles.d.ts +51 -0
- package/lib/components/NewComponents/FloatingMenuBar/styles.js +385 -0
- package/lib/components/NewComponents/FloatingMenuBar/types.d.ts +29 -0
- package/lib/components/NewComponents/FloatingMenuBar/types.js +1 -0
- package/lib/components/base/TMAccordionNew.js +35 -14
- package/lib/components/base/TMCustomButton.js +61 -17
- package/lib/components/base/TMDataGrid.d.ts +7 -4
- package/lib/components/base/TMDataGrid.js +142 -11
- package/lib/components/choosers/TMMetadataChooser.js +8 -1
- package/lib/components/editors/TMMetadataValues.js +23 -5
- package/lib/components/editors/TMTextBox.js +6 -3
- package/lib/components/features/documents/TMDcmtForm.d.ts +13 -1
- package/lib/components/features/documents/TMDcmtForm.js +386 -194
- package/lib/components/features/documents/TMDcmtPreview.js +40 -69
- package/lib/components/features/documents/TMMasterDetailDcmts.js +37 -52
- package/lib/components/features/search/TMDcmtCheckoutInfoForm.d.ts +8 -0
- package/lib/components/features/search/{TMSearchResultCheckoutInfoForm.js → TMDcmtCheckoutInfoForm.js} +5 -10
- package/lib/components/features/search/TMSavedQuerySelector.js +72 -67
- package/lib/components/features/search/TMSearch.js +30 -5
- package/lib/components/features/search/TMSearchQueryPanel.js +13 -12
- package/lib/components/features/search/TMSearchResult.js +57 -216
- package/lib/components/features/search/TMSearchResultsMenuItems.d.ts +3 -3
- package/lib/components/features/search/TMSearchResultsMenuItems.js +205 -169
- package/lib/components/features/search/TMSignSettingsForm.js +1 -1
- package/lib/components/features/search/TMSignatureInfoContent.d.ts +6 -0
- package/lib/components/features/search/TMSignatureInfoContent.js +140 -0
- package/lib/components/features/search/TMViewHistoryDcmt.js +1 -1
- package/lib/components/features/tasks/TMTaskForm.js +20 -1
- package/lib/components/features/tasks/TMTasksUtils.d.ts +2 -2
- package/lib/components/features/tasks/TMTasksUtils.js +62 -52
- package/lib/components/features/tasks/TMTasksView.js +6 -6
- package/lib/components/features/workflow/TMWorkflowPopup.d.ts +32 -2
- package/lib/components/features/workflow/TMWorkflowPopup.js +112 -14
- package/lib/components/features/workflow/diagram/WFDiagram.js +2 -2
- package/lib/components/forms/Login/LoginValidatorService.d.ts +2 -0
- package/lib/components/forms/Login/LoginValidatorService.js +7 -2
- package/lib/components/forms/Login/TMLoginForm.js +34 -6
- package/lib/components/forms/TMChooserForm.js +1 -1
- package/lib/components/grids/TMBlogsPost.js +55 -30
- package/lib/components/index.d.ts +2 -0
- package/lib/components/index.js +2 -0
- package/lib/components/viewers/TMDataListItemViewer.d.ts +2 -1
- package/lib/components/viewers/TMDataListItemViewer.js +12 -11
- package/lib/css/tm-sdkui.css +1 -1
- package/lib/helper/SDKUI_Globals.d.ts +17 -0
- package/lib/helper/SDKUI_Globals.js +9 -0
- package/lib/helper/SDKUI_Localizator.d.ts +9 -1
- package/lib/helper/SDKUI_Localizator.js +87 -1
- package/lib/helper/TMIcons.d.ts +2 -0
- package/lib/helper/TMIcons.js +6 -0
- package/lib/helper/TMPdfViewer.d.ts +8 -0
- package/lib/helper/TMPdfViewer.js +368 -0
- package/lib/helper/checkinCheckoutManager.d.ts +32 -2
- package/lib/helper/checkinCheckoutManager.js +115 -38
- package/lib/helper/devextremeCustomMessages.d.ts +30 -0
- package/lib/helper/devextremeCustomMessages.js +30 -0
- package/lib/helper/helpers.d.ts +2 -1
- package/lib/helper/helpers.js +14 -3
- package/lib/helper/index.d.ts +1 -0
- package/lib/helper/index.js +1 -0
- package/lib/helper/queryHelper.js +29 -0
- package/lib/hooks/useCheckInOutOperations.d.ts +28 -0
- package/lib/hooks/useCheckInOutOperations.js +223 -0
- package/lib/hooks/useWorkflowApprove.d.ts +4 -0
- package/lib/hooks/useWorkflowApprove.js +14 -1
- package/lib/ts/types.d.ts +56 -1
- package/package.json +5 -2
- package/lib/components/features/search/TMSearchResultCheckoutInfoForm.d.ts +0 -8
|
@@ -4,31 +4,68 @@ import TMModal from './TMModal';
|
|
|
4
4
|
import styled from 'styled-components';
|
|
5
5
|
import { SDKUI_Localizator, TMLayoutWaitingContainer } from '../..';
|
|
6
6
|
import { getButtonAttributes, getSelectedItem } from '../../helper/dcmtsHelper';
|
|
7
|
+
import { DeviceType, useDeviceType } from './TMDeviceProvider';
|
|
7
8
|
const IframeContainer = styled.div `
|
|
8
9
|
display: flex;
|
|
9
10
|
height: 100%;
|
|
10
11
|
flex-direction: column;
|
|
11
|
-
|
|
12
|
+
position: relative;
|
|
12
13
|
`;
|
|
13
14
|
const StyledIframe = styled.iframe `
|
|
14
15
|
border: none;
|
|
15
16
|
flex: 1;
|
|
16
17
|
`;
|
|
18
|
+
const LoadingOverlay = styled.div `
|
|
19
|
+
position: absolute;
|
|
20
|
+
top: 0;
|
|
21
|
+
left: 0;
|
|
22
|
+
right: 0;
|
|
23
|
+
bottom: 0;
|
|
24
|
+
background-color: rgba(128, 128, 128, 0.3);
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
justify-content: center;
|
|
28
|
+
z-index: 1000;
|
|
29
|
+
|
|
30
|
+
&::after {
|
|
31
|
+
content: '';
|
|
32
|
+
width: 40px;
|
|
33
|
+
height: 40px;
|
|
34
|
+
border: 4px solid rgba(255, 255, 255, 0.3);
|
|
35
|
+
border-top-color: #fff;
|
|
36
|
+
border-radius: 50%;
|
|
37
|
+
animation: spin 0.8s linear infinite;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@keyframes spin {
|
|
41
|
+
to {
|
|
42
|
+
transform: rotate(360deg);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
`;
|
|
17
46
|
const TMCustomButton = (props) => {
|
|
18
47
|
const { button, isModal = true, formData, selectedItems, onClose } = props;
|
|
19
48
|
const { appName: scriptUrl, arguments: args } = button;
|
|
49
|
+
const Device = useDeviceType();
|
|
20
50
|
const iframeRef = useRef(null);
|
|
21
51
|
const attributes = useMemo(() => getButtonAttributes(args, formData, selectedItems), [args, formData, selectedItems]);
|
|
22
52
|
const RunOnce = button.mode === "RunOnce";
|
|
23
53
|
const [loading, setLoading] = useState(true);
|
|
24
54
|
const [error, setError] = useState(false);
|
|
25
|
-
const
|
|
55
|
+
const itemsToProcess = useMemo(() => selectedItems && selectedItems.length > 0 ? selectedItems : [attributes], [selectedItems, attributes]);
|
|
26
56
|
// Stati per il wait panel
|
|
27
|
-
const [showWaitPanel, setShowWaitPanel] = useState(
|
|
28
|
-
const [waitPanelText, setWaitPanelText] = useState(SDKUI_Localizator.CustomButtonActions.replaceParams(1,
|
|
57
|
+
const [showWaitPanel, setShowWaitPanel] = useState(itemsToProcess.length > 0 && !RunOnce);
|
|
58
|
+
const [waitPanelText, setWaitPanelText] = useState(SDKUI_Localizator.CustomButtonActions.replaceParams(1, itemsToProcess.length));
|
|
29
59
|
const [waitPanelValue, setWaitPanelValue] = useState(0);
|
|
30
|
-
const [waitPanelMaxValue, setWaitPanelMaxValue] = useState(
|
|
60
|
+
const [waitPanelMaxValue, setWaitPanelMaxValue] = useState(itemsToProcess.length);
|
|
31
61
|
const [abortController, setAbortController] = useState(undefined);
|
|
62
|
+
// Aggiungi timestamp all'URL per evitare cache
|
|
63
|
+
const iframeUrl = useMemo(() => {
|
|
64
|
+
if (!scriptUrl)
|
|
65
|
+
return '';
|
|
66
|
+
const separator = scriptUrl.includes('?') ? '&' : '?';
|
|
67
|
+
return `${scriptUrl}${separator}t=${Date.now()}`;
|
|
68
|
+
}, [scriptUrl]);
|
|
32
69
|
const targetOrigin = useMemo(() => {
|
|
33
70
|
if (!scriptUrl)
|
|
34
71
|
return '*';
|
|
@@ -41,26 +78,35 @@ const TMCustomButton = (props) => {
|
|
|
41
78
|
}
|
|
42
79
|
}, [scriptUrl]);
|
|
43
80
|
const handleLoad = () => setLoading(false);
|
|
81
|
+
const isMobile = Device === DeviceType.MOBILE;
|
|
44
82
|
const handleError = () => {
|
|
45
83
|
setLoading(false);
|
|
46
84
|
setError(true);
|
|
47
85
|
};
|
|
48
86
|
const executeSequentially = async (controller) => {
|
|
49
|
-
if (!
|
|
87
|
+
if (!itemsToProcess)
|
|
50
88
|
return;
|
|
51
|
-
for (const [index, item] of
|
|
89
|
+
for (const [index, item] of itemsToProcess.entries()) {
|
|
52
90
|
if (controller.signal.aborted)
|
|
53
91
|
break;
|
|
54
|
-
setWaitPanelText(SDKUI_Localizator.CustomButtonActions.replaceParams(index + 1,
|
|
92
|
+
setWaitPanelText(SDKUI_Localizator.CustomButtonActions.replaceParams(index + 1, itemsToProcess.length));
|
|
55
93
|
setWaitPanelValue(index);
|
|
56
94
|
// Attendi che l'iframe sia pronto e invia il messaggio
|
|
57
95
|
await new Promise((resolve) => {
|
|
58
96
|
const checkIframe = setInterval(() => {
|
|
59
97
|
if (iframeRef.current?.contentWindow) {
|
|
60
98
|
clearInterval(checkIframe);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
99
|
+
if (selectedItems && selectedItems.length > 0) {
|
|
100
|
+
//devo convertire item in formData
|
|
101
|
+
const processedItem = getSelectedItem(args, formData, item);
|
|
102
|
+
postMessageIframe(processedItem);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
postMessageIframe(item);
|
|
106
|
+
}
|
|
107
|
+
//imposta 100% se sono all'ultimo item
|
|
108
|
+
if (index === itemsToProcess.length - 1)
|
|
109
|
+
setWaitPanelValue(index + 1);
|
|
64
110
|
// Attendi prima di passare al prossimo
|
|
65
111
|
setTimeout(() => {
|
|
66
112
|
setWaitPanelValue(index + 1);
|
|
@@ -82,8 +128,7 @@ const TMCustomButton = (props) => {
|
|
|
82
128
|
useEffect(() => {
|
|
83
129
|
if (loading || error)
|
|
84
130
|
return;
|
|
85
|
-
|
|
86
|
-
if (!RunOnce && selectedItemsCount > 0) {
|
|
131
|
+
if (!RunOnce && itemsToProcess.length > 0) {
|
|
87
132
|
// esegui per ogni item selezionato
|
|
88
133
|
const controller = new AbortController();
|
|
89
134
|
controller.signal.addEventListener('abort', () => {
|
|
@@ -91,7 +136,7 @@ const TMCustomButton = (props) => {
|
|
|
91
136
|
onClose?.();
|
|
92
137
|
});
|
|
93
138
|
setAbortController(controller);
|
|
94
|
-
setWaitPanelMaxValue(
|
|
139
|
+
setWaitPanelMaxValue(itemsToProcess.length);
|
|
95
140
|
executeSequentially(controller);
|
|
96
141
|
}
|
|
97
142
|
else {
|
|
@@ -103,7 +148,6 @@ const TMCustomButton = (props) => {
|
|
|
103
148
|
onClose?.();
|
|
104
149
|
}, 2000);
|
|
105
150
|
}
|
|
106
|
-
//clearTimeout(timeoutIframe);
|
|
107
151
|
}
|
|
108
152
|
}, [loading, error, RunOnce]);
|
|
109
153
|
useEffect(() => {
|
|
@@ -112,7 +156,7 @@ const TMCustomButton = (props) => {
|
|
|
112
156
|
onClose?.();
|
|
113
157
|
}
|
|
114
158
|
}, []);
|
|
115
|
-
const iframeContent = (_jsxs(IframeContainer, { style: !RunOnce ? { visibility: 'hidden' } : {}, children: [error && _jsx("div", { children: "Si \u00E8 verificato un errore nel caricamento del contenuto." }), !error && _jsx(StyledIframe, { ref: iframeRef, loading: 'lazy', onLoad: handleLoad, onError: handleError, src:
|
|
116
|
-
return isModal && RunOnce ? (_jsx(TMModal, { title: button.title, width: '60%', height: '70%', resizable: true, expandable: true, onClose: onClose, children: iframeContent })) : !RunOnce && (_jsxs(_Fragment, { children: [_jsx(TMLayoutWaitingContainer, { showWaitPanel: showWaitPanel, waitPanelTitle: SDKUI_Localizator.CustomButtonAction, showWaitPanelPrimary: true, waitPanelTextPrimary: waitPanelText, waitPanelValuePrimary: waitPanelValue, waitPanelMaxValuePrimary: waitPanelMaxValue, showWaitPanelSecondary: false, isCancelable: true, abortController: abortController, children: undefined }), iframeContent] }));
|
|
159
|
+
const iframeContent = (_jsxs(IframeContainer, { style: !RunOnce ? { visibility: 'hidden' } : {}, children: [loading && _jsx(LoadingOverlay, {}), error && _jsx("div", { children: "Si \u00E8 verificato un errore nel caricamento del contenuto." }), !error && _jsx(StyledIframe, { ref: iframeRef, loading: 'lazy', onLoad: handleLoad, onError: handleError, src: iframeUrl })] }));
|
|
160
|
+
return isModal && RunOnce ? (_jsx(TMModal, { title: button.title, width: isMobile ? '95%' : '60%', height: isMobile ? '95%' : '70%', resizable: isMobile ? false : true, expandable: isMobile ? false : true, onClose: onClose, children: iframeContent })) : !RunOnce && (_jsxs(_Fragment, { children: [_jsx(TMLayoutWaitingContainer, { showWaitPanel: showWaitPanel, waitPanelTitle: SDKUI_Localizator.CustomButtonAction, showWaitPanelPrimary: true, waitPanelTextPrimary: waitPanelText, waitPanelValuePrimary: waitPanelValue, waitPanelMaxValuePrimary: waitPanelMaxValue, showWaitPanelSecondary: false, isCancelable: true, abortController: abortController, children: undefined }), iframeContent] }));
|
|
117
161
|
};
|
|
118
162
|
export default TMCustomButton;
|
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { IColumnProps, IDataGridOptions, IMasterDetailProps } from 'devextreme-react/data-grid';
|
|
3
3
|
import dxDataGrid from 'devextreme/ui/data_grid';
|
|
4
4
|
import { ITMCounterContainerProps } from './TMCounterContainer';
|
|
5
|
+
import { TMContextMenuItemProps } from '../NewComponents/ContextMenu/types';
|
|
5
6
|
export interface TMDataGridContextMenuItem {
|
|
6
7
|
text: string;
|
|
7
8
|
icon: string;
|
|
@@ -31,16 +32,16 @@ export interface TMDataGridProps<T> extends IDataGridOptions {
|
|
|
31
32
|
pageSize?: TMDataGridPageSize;
|
|
32
33
|
/** Configures the search panel position in the toolbar */
|
|
33
34
|
searchPanelToolbarPosition?: 'before' | 'default';
|
|
34
|
-
/**
|
|
35
|
-
|
|
35
|
+
/** Trigger to set focus on SearchPanel (only if visible) - change the number to trigger focus */
|
|
36
|
+
searchPanelFocusTrigger?: number;
|
|
36
37
|
/** Show the header filter */
|
|
37
38
|
showHeaderFilter?: boolean;
|
|
38
39
|
/** Show the filter panel */
|
|
39
40
|
showFilterPanel?: boolean;
|
|
40
41
|
/** Show the load panel */
|
|
41
42
|
showLoadPanel?: boolean;
|
|
42
|
-
/** Show the column chooser */
|
|
43
|
-
|
|
43
|
+
/** Show the header column chooser in context menu */
|
|
44
|
+
showHeaderColumnChooser?: boolean;
|
|
44
45
|
/** Show the search panel */
|
|
45
46
|
showSearchPanel?: boolean;
|
|
46
47
|
/** Show the group panel */
|
|
@@ -51,6 +52,8 @@ export interface TMDataGridProps<T> extends IDataGridOptions {
|
|
|
51
52
|
masterDetail?: IMasterDetailProps;
|
|
52
53
|
/** On Has Filters Change */
|
|
53
54
|
onHasFiltersChange?: (hasFilters: boolean) => void;
|
|
55
|
+
/** Custom context menu items - when provided, replaces DevExtreme's native context menu with TMContextMenu */
|
|
56
|
+
customContextMenuItems?: TMContextMenuItemProps[];
|
|
54
57
|
}
|
|
55
58
|
declare const TMDataGrid: React.ForwardRefExoticComponent<TMDataGridProps<unknown> & React.RefAttributes<dxDataGrid<any, any>>>;
|
|
56
59
|
export default TMDataGrid;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React, { useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
|
3
|
-
import DataGrid, { Column, HeaderFilter, Selection, Scrolling, LoadPanel, SearchPanel, Pager, Sorting, Paging, FilterPanel, ColumnChooser, Grouping, GroupPanel, Summary, Editing, FilterRow, StateStoring, RowDragging, MasterDetail } from 'devextreme-react/data-grid';
|
|
3
|
+
import DataGrid, { Column, HeaderFilter, Selection, Scrolling, LoadPanel, SearchPanel, Pager, Sorting, Paging, FilterPanel, ColumnChooser, Grouping, GroupPanel, Summary, Editing, FilterRow, StateStoring, RowDragging, MasterDetail, Position, ColumnChooserSearch, ColumnChooserSelection } from 'devextreme-react/data-grid';
|
|
4
4
|
import DataSource from 'devextreme/data/data_source';
|
|
5
5
|
import { IconAll, IconSelected, IconVisible, SDKUI_Globals, SDKUI_Localizator } from '../../helper';
|
|
6
6
|
import TMCounterContainer, { CounterItemKey } from './TMCounterContainer';
|
|
7
|
+
import TMContextMenu from '../NewComponents/ContextMenu/TMContextMenu';
|
|
8
|
+
import { useLongPress } from '../NewComponents/ContextMenu/useLongPress';
|
|
7
9
|
;
|
|
8
10
|
export var TMDataGridPageSize;
|
|
9
11
|
(function (TMDataGridPageSize) {
|
|
@@ -16,9 +18,9 @@ const TMDataGrid = React.forwardRef((props, ref) => {
|
|
|
16
18
|
// main properties
|
|
17
19
|
keyExpr = 'id', dataSource, focusedRowEnabled = true, hoverStateEnabled = true, focusedRowKey, selectedRowKeys = [],
|
|
18
20
|
// custom options
|
|
19
|
-
dataColumns = [], pageSize = TMDataGridPageSize.Large, showHeaderFilter = true, showFilterPanel = true, showLoadPanel = true, showSearchPanel = true, searchPanelToolbarPosition = 'before',
|
|
21
|
+
dataColumns = [], pageSize = TMDataGridPageSize.Large, showHeaderFilter = true, showFilterPanel = true, showHeaderColumnChooser = false, showLoadPanel = true, showSearchPanel = true, searchPanelToolbarPosition = 'before', searchPanelFocusTrigger = 0, counterConfig = { show: false, items: new Map() }, onHasFiltersChange, customContextMenuItems,
|
|
20
22
|
// events and callbacks
|
|
21
|
-
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,
|
|
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,
|
|
22
24
|
// other properties
|
|
23
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,
|
|
24
26
|
// styles
|
|
@@ -29,10 +31,82 @@ const TMDataGrid = React.forwardRef((props, ref) => {
|
|
|
29
31
|
const [totalRecordCount, setTotalRecordCount] = useState(0);
|
|
30
32
|
const [visibleItemsCount, setVisibleItemsCount] = useState(0);
|
|
31
33
|
const [hasFilters, setHasFilters] = useState(false);
|
|
34
|
+
// Custom context menu states
|
|
35
|
+
const [customContextMenuVisible, setCustomContextMenuVisible] = useState(false);
|
|
36
|
+
const [customContextMenuPosition, setCustomContextMenuPosition] = useState({ x: 0, y: 0 });
|
|
37
|
+
const [customContextMenuRowKey, setCustomContextMenuRowKey] = useState(undefined);
|
|
38
|
+
const gridContainerRef = useRef(null);
|
|
32
39
|
useEffect(() => {
|
|
33
40
|
const count = getRecordCount(dataSource);
|
|
34
41
|
setTotalRecordCount(count);
|
|
35
42
|
}, [dataSource]);
|
|
43
|
+
// Handle search panel focus when trigger changes
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (!searchPanelFocusTrigger || searchPanelFocusTrigger <= 0 || !showSearchPanel || !internalRef.current)
|
|
46
|
+
return;
|
|
47
|
+
setTimeout(() => {
|
|
48
|
+
const searchInput = internalRef.current?.instance().element().querySelector('.dx-datagrid-search-panel input');
|
|
49
|
+
if (searchInput) {
|
|
50
|
+
searchInput.focus();
|
|
51
|
+
}
|
|
52
|
+
}, 100);
|
|
53
|
+
}, [searchPanelFocusTrigger, showSearchPanel]);
|
|
54
|
+
// Handle custom context menu (only when customContextMenuItems is provided)
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (!customContextMenuItems || !gridContainerRef.current)
|
|
57
|
+
return;
|
|
58
|
+
const gridContainer = gridContainerRef.current;
|
|
59
|
+
const handleContextMenu = (e) => {
|
|
60
|
+
e.preventDefault();
|
|
61
|
+
e.stopPropagation();
|
|
62
|
+
// Get the clicked row
|
|
63
|
+
const target = e.target;
|
|
64
|
+
const rowElement = target.closest('.dx-data-row');
|
|
65
|
+
if (rowElement && internalRef.current) {
|
|
66
|
+
const rowIndex = Array.from(rowElement.parentElement?.children || []).indexOf(rowElement);
|
|
67
|
+
const rowKey = internalRef.current.instance().getKeyByRowIndex(rowIndex);
|
|
68
|
+
// Change focused row
|
|
69
|
+
internalRef.current.instance().option('focusedRowKey', rowKey);
|
|
70
|
+
// Show custom context menu
|
|
71
|
+
setCustomContextMenuVisible(true);
|
|
72
|
+
setCustomContextMenuPosition({ x: e.clientX, y: e.clientY });
|
|
73
|
+
setCustomContextMenuRowKey(rowKey);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
gridContainer.addEventListener('contextmenu', handleContextMenu);
|
|
77
|
+
return () => {
|
|
78
|
+
gridContainer.removeEventListener('contextmenu', handleContextMenu);
|
|
79
|
+
};
|
|
80
|
+
}, [customContextMenuItems]);
|
|
81
|
+
// iOS-specific: Handle touch for focused row change and long-press for context menu
|
|
82
|
+
useLongPress({
|
|
83
|
+
containerRef: gridContainerRef,
|
|
84
|
+
targetSelector: '.dx-data-row',
|
|
85
|
+
enabled: !!customContextMenuItems,
|
|
86
|
+
onTouchStart: ({ rowElement }) => {
|
|
87
|
+
// Change focused row immediately on touch (fixes focus issue)
|
|
88
|
+
if (!internalRef.current)
|
|
89
|
+
return;
|
|
90
|
+
const rowIndex = Array.from(rowElement.parentElement?.children || []).indexOf(rowElement);
|
|
91
|
+
const rowKey = internalRef.current.instance().getKeyByRowIndex(rowIndex);
|
|
92
|
+
if (rowKey !== undefined && rowKey !== focusedRowKey) {
|
|
93
|
+
internalRef.current.instance().option('focusedRowKey', rowKey);
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
onLongPress: ({ clientX, clientY, target }) => {
|
|
97
|
+
if (!internalRef.current)
|
|
98
|
+
return;
|
|
99
|
+
const rowElement = target.closest('.dx-data-row');
|
|
100
|
+
if (!rowElement)
|
|
101
|
+
return;
|
|
102
|
+
const rowIndex = Array.from(rowElement.parentElement?.children || []).indexOf(rowElement);
|
|
103
|
+
const rowKey = internalRef.current.instance().getKeyByRowIndex(rowIndex);
|
|
104
|
+
// Show context menu
|
|
105
|
+
setCustomContextMenuVisible(true);
|
|
106
|
+
setCustomContextMenuPosition({ x: clientX, y: clientY });
|
|
107
|
+
setCustomContextMenuRowKey(rowKey);
|
|
108
|
+
},
|
|
109
|
+
});
|
|
36
110
|
// Creating a ref to store the timestamp of the last selection change
|
|
37
111
|
const lastSelectionChangeTime = useRef(Date.now());
|
|
38
112
|
useEffect(() => {
|
|
@@ -101,6 +175,8 @@ const TMDataGrid = React.forwardRef((props, ref) => {
|
|
|
101
175
|
}
|
|
102
176
|
return {
|
|
103
177
|
...item,
|
|
178
|
+
// Ensure icon is not null/undefined to prevent DevExtreme errors
|
|
179
|
+
icon: item.icon || '',
|
|
104
180
|
disabled: disabled || disabledCalculation, // An item is disabled if it's explicitly set to `true` or if the calculation above determines so
|
|
105
181
|
// Define the behavior when the menu item is clicked
|
|
106
182
|
onClick: () => {
|
|
@@ -132,10 +208,51 @@ const TMDataGrid = React.forwardRef((props, ref) => {
|
|
|
132
208
|
};
|
|
133
209
|
});
|
|
134
210
|
}, [focusedRowEnabled, focusedRowKey, selectedRowKeys]);
|
|
211
|
+
// Process custom context menu items (for TMContextMenuItemProps)
|
|
212
|
+
const processCustomContextMenuItems = useCallback((items, rowID) => {
|
|
213
|
+
return items.map(item => {
|
|
214
|
+
let disabled = item.disabled ?? false;
|
|
215
|
+
let disabledCalculation = false;
|
|
216
|
+
const id = focusedRowEnabled ? focusedRowKey : rowID;
|
|
217
|
+
if (item.operationType === 'singleRow') {
|
|
218
|
+
disabledCalculation = selectedRowKeys.length > 1 || id === undefined;
|
|
219
|
+
}
|
|
220
|
+
if (item.operationType === 'multiRow') {
|
|
221
|
+
disabledCalculation = selectedRowKeys.length === 0 && id === undefined;
|
|
222
|
+
}
|
|
223
|
+
const originalOnClick = item.onClick;
|
|
224
|
+
return {
|
|
225
|
+
...item,
|
|
226
|
+
disabled: disabled || disabledCalculation,
|
|
227
|
+
onClick: originalOnClick ? () => {
|
|
228
|
+
if (item.operationType === 'singleRow' && id !== undefined) {
|
|
229
|
+
originalOnClick(id);
|
|
230
|
+
}
|
|
231
|
+
else if (item.operationType === 'multiRow' && id !== undefined) {
|
|
232
|
+
if (selectedRowKeys.length > 0) {
|
|
233
|
+
originalOnClick(selectedRowKeys);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
originalOnClick([id]);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
originalOnClick();
|
|
241
|
+
}
|
|
242
|
+
} : undefined,
|
|
243
|
+
submenu: item.submenu ? processCustomContextMenuItems(item.submenu, id) : undefined,
|
|
244
|
+
};
|
|
245
|
+
});
|
|
246
|
+
}, [focusedRowEnabled, focusedRowKey, selectedRowKeys]);
|
|
135
247
|
// Handle context menu preparation
|
|
136
248
|
const onContextMenuPreparingCallback = useCallback((e) => {
|
|
137
249
|
if (e === undefined)
|
|
138
250
|
return;
|
|
251
|
+
// If custom context menu is enabled, completely disable DevExtreme's native context menu
|
|
252
|
+
if (customContextMenuItems && e.target === 'content') {
|
|
253
|
+
e.items = undefined;
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
139
256
|
if (onContextMenuPreparing)
|
|
140
257
|
onContextMenuPreparing(e);
|
|
141
258
|
if (e.target === 'content') {
|
|
@@ -146,7 +263,18 @@ const TMDataGrid = React.forwardRef((props, ref) => {
|
|
|
146
263
|
e.items = [...updatedContextMenuItems];
|
|
147
264
|
}
|
|
148
265
|
}
|
|
149
|
-
|
|
266
|
+
// Add column chooser to header context menu
|
|
267
|
+
if (e.target === 'header' && showHeaderColumnChooser) {
|
|
268
|
+
e.items = e.items || [];
|
|
269
|
+
e.items.push({
|
|
270
|
+
text: SDKUI_Localizator.ShowColumnSelection,
|
|
271
|
+
icon: 'columnchooser',
|
|
272
|
+
onItemClick: () => {
|
|
273
|
+
internalRef.current?.instance().showColumnChooser();
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
}, [updateContextMenuItems, onContextMenuPreparing, showHeaderColumnChooser, customContextMenuItems]);
|
|
150
278
|
// Handle toolbar preparation, especially for the search panel
|
|
151
279
|
const onToolbarPreparingCallback = useCallback((e) => {
|
|
152
280
|
if (e === undefined || e.toolbarOptions === undefined || e.toolbarOptions.items === undefined)
|
|
@@ -171,10 +299,9 @@ const TMDataGrid = React.forwardRef((props, ref) => {
|
|
|
171
299
|
return;
|
|
172
300
|
// Update state with the current number of visible rows in the DataGrid
|
|
173
301
|
setVisibleItemsCount(internalRef.current.instance()?.getVisibleRows()?.length ?? 0);
|
|
174
|
-
// Focusing SearchPanel
|
|
175
|
-
if (showSearchPanel &&
|
|
302
|
+
// Focusing SearchPanel on content ready
|
|
303
|
+
if (showSearchPanel && searchPanelFocusTrigger && searchPanelFocusTrigger > 0) {
|
|
176
304
|
// Use a small delay to ensure the DOM is fully rendered before trying to focus
|
|
177
|
-
// This can prevent issues with the focus not being set correctly
|
|
178
305
|
setTimeout(() => {
|
|
179
306
|
const searchInput = internalRef.current?.instance().element().querySelector('.dx-datagrid-search-panel input');
|
|
180
307
|
if (searchInput) {
|
|
@@ -182,7 +309,7 @@ const TMDataGrid = React.forwardRef((props, ref) => {
|
|
|
182
309
|
}
|
|
183
310
|
}, 100);
|
|
184
311
|
}
|
|
185
|
-
}, [onContentReady]);
|
|
312
|
+
}, [onContentReady, showSearchPanel, searchPanelFocusTrigger]);
|
|
186
313
|
const onOptionChangedCallback = useCallback((e) => {
|
|
187
314
|
// Assicurati che component esista
|
|
188
315
|
const grid = e.component;
|
|
@@ -215,15 +342,19 @@ const TMDataGrid = React.forwardRef((props, ref) => {
|
|
|
215
342
|
// Propaga l'evento originale
|
|
216
343
|
onOptionChanged?.(e);
|
|
217
344
|
}, [onOptionChanged, onHasFiltersChange]);
|
|
218
|
-
return _jsxs("div", { style: { width: "100%", height: "100%" }, children: [_jsx("div", { style: { width: "100%", height: counterConfig.show ? "calc(100% - 25px)" : "100%" }, children: _jsxs(DataGrid, { ref: internalRef, id: id, className: `tm-datagrid ${hasFilters ? 'has-filters' : ''}`,
|
|
345
|
+
return _jsxs("div", { style: { width: "100%", height: "100%" }, children: [_jsx("div", { ref: gridContainerRef, style: { width: "100%", height: counterConfig.show ? "calc(100% - 25px)" : "100%" }, children: _jsxs(DataGrid, { ref: internalRef, id: id, className: `tm-datagrid ${hasFilters ? 'has-filters' : ''}`,
|
|
219
346
|
// main properties
|
|
220
347
|
keyExpr: keyExpr, dataSource: dataSource, selectedRowKeys: selectedRowKeys, focusedRowEnabled: focusedRowEnabled, hoverStateEnabled: hoverStateEnabled,
|
|
221
348
|
// events and callbacks
|
|
222
|
-
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,
|
|
349
|
+
onSelectionChanged: onSelectionChangedCallback, onRowDblClick: onRowDblClickCallback, onRowPrepared: onRowPrepared, onContextMenuPreparing: customContextMenuItems ? undefined : 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,
|
|
223
350
|
// other properties
|
|
224
351
|
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,
|
|
225
352
|
// styles
|
|
226
|
-
width: width, height: height, style: { userSelect: 'none' }, children: [dataColumns.map((column, index) => (_jsx(Column, { ...column }, column.caption + index.toString()))), sorting && _jsx(Sorting, { ...sorting }), selection && _jsx(Selection, { ...selection }), scrolling && _jsx(Scrolling, { ...scrolling }), summary && _jsx(Summary, { ...summary }), showHeaderFilter && _jsx(HeaderFilter, { visible: true, ...headerFilter }), rowDragging && _jsx(RowDragging, { ...rowDragging }), filterRow && _jsx(FilterRow, { ...filterRow }), showFilterPanel && _jsx(FilterPanel, { visible: true }),
|
|
353
|
+
width: width, height: height, style: { userSelect: 'none' }, children: [dataColumns.map((column, index) => (_jsx(Column, { ...column }, column.caption + index.toString()))), sorting && _jsx(Sorting, { ...sorting }), selection && _jsx(Selection, { ...selection }), scrolling && _jsx(Scrolling, { ...scrolling }), summary && _jsx(Summary, { ...summary }), showHeaderFilter && _jsx(HeaderFilter, { visible: true, ...headerFilter }), rowDragging && _jsx(RowDragging, { ...rowDragging }), filterRow && _jsx(FilterRow, { ...filterRow }), showFilterPanel && _jsx(FilterPanel, { visible: true }), showHeaderColumnChooser && _jsxs(ColumnChooser, { height: "400px", enabled: !showHeaderColumnChooser, mode: "select", children: [_jsx(Position, { my: "center", at: "center", of: window }), _jsx(ColumnChooserSearch, { enabled: true }), _jsx(ColumnChooserSelection, { allowSelectAll: false, selectByClick: true, recursive: true })] }), stateStoring && _jsx(StateStoring, { ...stateStoring }), groupPanel && _jsx(GroupPanel, { ...groupPanel }), _jsx(Grouping, { contextMenuEnabled: true, ...grouping }), _jsx(LoadPanel, { enabled: showLoadPanel }), _jsx(SearchPanel, { visible: showSearchPanel, searchVisibleColumnsOnly: true, highlightSearchText: true }), editing && _jsx(Editing, { ...editing }), paging && _jsx(Paging, { ...paging }), pager && _jsx(Pager, { ...pager, visible: totalRecordCount > pageSize }), masterDetail && _jsx(MasterDetail, { ...masterDetail })] }) }), counterConfig.show && _jsx("div", { style: { width: "100%", height: "25px", display: "flex", alignItems: "center", gap: "15px", backgroundColor: "#e0e0e0" }, children: _jsx(TMCounterContainer, { items: counterValues, bgColorContainer: counterConfig.bgColorContainer, bgColorItem: counterConfig.bgColorItem, hoverColorItem: counterConfig.hoverColorItem, textColorItem: counterConfig.textColorItem }) }), customContextMenuItems && (_jsx(TMContextMenu, { target: ".dx-data-row", items: processCustomContextMenuItems(customContextMenuItems, customContextMenuRowKey), externalControl: {
|
|
354
|
+
visible: customContextMenuVisible,
|
|
355
|
+
position: customContextMenuPosition,
|
|
356
|
+
onClose: () => setCustomContextMenuVisible(false)
|
|
357
|
+
} }))] });
|
|
227
358
|
});
|
|
228
359
|
export default TMDataGrid;
|
|
229
360
|
const getRecordCount = (dataSource) => {
|
|
@@ -13,8 +13,15 @@ import TMChooserForm from '../forms/TMChooserForm';
|
|
|
13
13
|
import TMSpinner from '../base/TMSpinner';
|
|
14
14
|
const TMMetadataChooser = ({ tmSession, dataSource, showEditButton = true, buttons = [], disabled, validationItems, getColorIndex, showCompleteMetadataName, qdShowOnlySelectItems, borderRadius = '4px', fontSize = FontSize.defaultFontSize, backgroundColor, openEditorOnSummaryClick, showBorder = true, showId = false, elementStyle, allowMultipleSelection, allowSysMetadata, showSysMetadataDirectly, value, values, isModifiedWhen, tids, label, width, height, showClearButton, qd, placeHolder, filterMetadata, onValueChanged }) => {
|
|
15
15
|
const [showChooser, setShowChooser] = useState(false);
|
|
16
|
+
const getinputMd = () => {
|
|
17
|
+
if (values && values.length > 0 && values[0].mid && values[0].mid < 0) {
|
|
18
|
+
let md = dataSource?.find((md) => md.id === values[0].mid);
|
|
19
|
+
return md;
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
};
|
|
16
23
|
const renderTemplate = useMemo(() => {
|
|
17
|
-
return (_jsxs(StyledDivHorizontal, { style: { width: 'max-content', height: '100%' }, children: [values && _jsx(TMMidViewer, { tmSession: tmSession, tid_mid: values[0], showIcon: true, showId: showId, showCompleteName: showCompleteMetadataName }), values && values.length > 1 && _jsx("p", { style: { marginLeft: '10px' }, children: `(+${values.length - 1} ${values.length == 2 ? 'altro' : 'altri'})` }), (values == undefined || values.length == 0) && _jsx("p", { children: placeHolder })] }));
|
|
24
|
+
return (_jsxs(StyledDivHorizontal, { style: { width: 'max-content', height: '100%' }, children: [values && values.length > 0 && values[0].mid && values[0].mid > 0 && _jsx(TMMidViewer, { tmSession: tmSession, tid_mid: values[0], showIcon: true, showId: showId, showCompleteName: showCompleteMetadataName }), values && values.length > 0 && values[0].mid && values[0].mid < 0 && _jsx(TMMidViewer, { tmSession: tmSession, tid_mid: values[0], inputMd: getinputMd(), showIcon: true, showId: showId, showCompleteName: showCompleteMetadataName }), values && values.length > 1 && _jsx("p", { style: { marginLeft: '10px' }, children: `(+${values.length - 1} ${values.length == 2 ? 'altro' : 'altri'})` }), (values == undefined || values.length == 0) && _jsx("p", { children: placeHolder })] }));
|
|
18
25
|
}, [values, tmSession, showId, showCompleteMetadataName, placeHolder]);
|
|
19
26
|
return (_jsxs(_Fragment, { children: [_jsx(TMSummary, { label: label, width: width, height: height, disabled: disabled, validationItems: validationItems, backgroundColor: backgroundColor, buttons: buttons, placeHolder: placeHolder, fontSize: fontSize, showBorder: showBorder, borderRadius: borderRadius, hasValue: values && values.length > 0, showClearButton: showClearButton, showEditButton: showEditButton, iconEditButton: _jsx(IconSearch, { fontSize: 16 }), openEditorOnSummaryClick: openEditorOnSummaryClick, onEditorClick: () => !disabled && setShowChooser(true), elementStyle: elementStyle, isModifiedWhen: isModifiedWhen, template: renderTemplate, onClearClick: showClearButton ? () => { onValueChanged?.([]); } : undefined }), showChooser &&
|
|
20
27
|
_jsx(TMMetadataChooserForm, { tmSession: tmSession, allowMultipleSelection: allowMultipleSelection, height: '500px', width: '600px', allowSysMetadata: allowSysMetadata, showSysMetadataDirectly: showSysMetadataDirectly, getColorIndex: getColorIndex, dataSource: dataSource, tids: tids, qd: qd, qdShowOnlySelectItems: qdShowOnlySelectItems, filterMetadata: filterMetadata, selectedIDs: values, onClose: () => setShowChooser(false), onChoose: (tid_mids) => { onValueChanged?.(tid_mids); } })] }));
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
|
3
3
|
import styled from "styled-components";
|
|
4
|
-
import { AccessLevels, DcmtTypeListCacheService, LayoutGroupBorderStyles, LayoutGroupOrientations, LayoutItemTypes, LayoutModes, MetadataDataDomains, MetadataDataTypes, SDK_Globals, SystemMIDsAsNumber, SystemTIDs,
|
|
5
|
-
import { IconUndo, IconPencil, IconFunction, IconMenuVertical, IconDataList, SDKUI_Localizator, IconNull, stringIsNullOrEmpty, deepCompare, SDKUI_Globals, IconDcmtTypeSys } from "../../helper";
|
|
4
|
+
import { AccessLevels, DcmtTypeListCacheService, LayoutGroupBorderStyles, LayoutGroupOrientations, LayoutItemTypes, LayoutModes, MetadataDataDomains, MetadataDataTypes, SDK_Globals, SystemMIDsAsNumber, SystemTIDs, WorkItemMetadataNames } from '@topconsultnpm/sdk-ts';
|
|
5
|
+
import { IconUndo, IconPencil, IconFunction, IconMenuVertical, IconDataList, SDKUI_Localizator, IconNull, stringIsNullOrEmpty, deepCompare, SDKUI_Globals, IconDcmtTypeSys, isApprovalWorkflowView } from "../../helper";
|
|
6
6
|
import { TMColors } from "../../utils/theme";
|
|
7
7
|
import TMButton from "../base/TMButton";
|
|
8
8
|
import TMDropDownMenu from "../base/TMDropDownMenu";
|
|
@@ -389,17 +389,35 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
|
|
|
389
389
|
return (_jsxs("div", { style: { width: '100%' }, children: [draftData.length > 0 && _jsx(TMAccordion, { title: SDKUI_Localizator.Draft, children: draftData.map(item => renderMetadataItem(item, isReadOnly)) }), checkOutData.length > 0 && _jsx(TMAccordion, { title: `${SDKUI_Localizator.CheckIn}/${SDKUI_Localizator.CheckOut}`, children: checkOutData.map(item => renderMetadataItem(item, true)) })] }));
|
|
390
390
|
}, [metadataValues, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig]);
|
|
391
391
|
const layoutChronology = useMemo(() => {
|
|
392
|
-
|
|
392
|
+
// Definiamo l'ordine desiderato: Version, Tipo, Dimensione, Autore, Data Ultima modifica
|
|
393
|
+
const desiredChronologyOrder = [
|
|
394
|
+
ChronologyMIDs.Ver,
|
|
395
|
+
SystemMIDsAsNumber.FileExt,
|
|
396
|
+
SystemMIDsAsNumber.FileSize,
|
|
397
|
+
ChronologyMIDs.AuthorID,
|
|
398
|
+
ChronologyMIDs.CheckInTime,
|
|
399
|
+
];
|
|
400
|
+
const tempChronologyDataMap = {};
|
|
393
401
|
metadataValues.forEach(item => {
|
|
394
402
|
switch (item.md?.id) {
|
|
395
403
|
case ChronologyMIDs.Ver:
|
|
396
404
|
case ChronologyMIDs.AuthorID:
|
|
397
|
-
|
|
405
|
+
case ChronologyMIDs.CheckInTime:
|
|
406
|
+
case SystemMIDsAsNumber.FileExt:
|
|
407
|
+
case SystemMIDsAsNumber.FileSize:
|
|
408
|
+
tempChronologyDataMap[item.md.id] = item;
|
|
398
409
|
break;
|
|
399
410
|
default:
|
|
400
411
|
break;
|
|
401
412
|
}
|
|
402
413
|
});
|
|
414
|
+
// Visualizziamo nell'ordine desiderato
|
|
415
|
+
const chronologyData = [];
|
|
416
|
+
desiredChronologyOrder.forEach(id => {
|
|
417
|
+
if (tempChronologyDataMap[id]) {
|
|
418
|
+
chronologyData.push(tempChronologyDataMap[id]);
|
|
419
|
+
}
|
|
420
|
+
});
|
|
403
421
|
return (_jsx("div", { style: { width: '100%' }, children: chronologyData.length > 0 && chronologyData.map(item => renderMetadataItem(item, isReadOnly)) }));
|
|
404
422
|
}, [metadataValues, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig]);
|
|
405
423
|
const layoutDsAttachs = useMemo(() => {
|
|
@@ -550,7 +568,7 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
|
|
|
550
568
|
if (allSystem) {
|
|
551
569
|
return metadataValues.map((item) => renderMetadataItem(item, true));
|
|
552
570
|
}
|
|
553
|
-
if (currentDTD
|
|
571
|
+
if (isApprovalWorkflowView(currentDTD) && !isReadOnly) {
|
|
554
572
|
return layoutWorkItem;
|
|
555
573
|
}
|
|
556
574
|
switch (currentDTD?.id) {
|
|
@@ -9,7 +9,7 @@ import { TMExceptionBoxManager } from '../base/TMPopUp';
|
|
|
9
9
|
import TMLayoutContainer, { TMLayoutItem } from '../base/TMLayout';
|
|
10
10
|
import TMVilViewer from '../base/TMVilViewer';
|
|
11
11
|
import TMTooltip from '../base/TMTooltip';
|
|
12
|
-
import
|
|
12
|
+
import TMContextMenu from '../NewComponents/ContextMenu/TMContextMenu';
|
|
13
13
|
import { DeviceType, useDeviceType } from '../base/TMDeviceProvider';
|
|
14
14
|
import TMChooserForm from '../forms/TMChooserForm';
|
|
15
15
|
import { FormulaItemHelper } from './TMTextExpression';
|
|
@@ -94,7 +94,10 @@ const TMTextBox = ({ autoFocus, maxLength, labelColor, precision, fromModal = fa
|
|
|
94
94
|
if (formulaItems && formulaItems.length > 0) {
|
|
95
95
|
let menuItems = [];
|
|
96
96
|
for (const formula of formulaItems) {
|
|
97
|
-
menuItems.push({
|
|
97
|
+
menuItems.push({
|
|
98
|
+
name: formula,
|
|
99
|
+
onClick: () => insertText(formula)
|
|
100
|
+
});
|
|
98
101
|
}
|
|
99
102
|
setFormulaMenuItems(menuItems);
|
|
100
103
|
}
|
|
@@ -269,7 +272,7 @@ const TMTextBox = ({ autoFocus, maxLength, labelColor, precision, fromModal = fa
|
|
|
269
272
|
onBlur?.(undefined);
|
|
270
273
|
}, children: _jsx(IconClearButton, {}) }), buttons.map((buttonItem, index) => {
|
|
271
274
|
return (_jsx(StyledTextBoxEditorButton, { onClick: buttonItem.onClick, children: _jsx(TMTooltip, { content: buttonItem.text, children: buttonItem.icon }) }, buttonItem.text));
|
|
272
|
-
})] }), openFormulaItemsChooser(), formulaItems.length > 0 && (_jsx(
|
|
275
|
+
})] }), openFormulaItemsChooser(), formulaItems.length > 0 && (_jsx(TMContextMenu, { items: formulaMenuItems, target: `#text-${id}` })), _jsx(TMVilViewer, { vil: validationItems })] }));
|
|
273
276
|
};
|
|
274
277
|
const renderedLeftLabelTextBox = () => {
|
|
275
278
|
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,18 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { HomeBlogPost, LayoutModes, ObjectRef, SearchResultDescriptor, TaskDescriptor, ValidationItem } from '@topconsultnpm/sdk-ts';
|
|
3
3
|
import { DcmtInfo, FormModes, MetadataValueDescriptorEx, TaskContext } from '../../../ts';
|
|
4
|
+
/**
|
|
5
|
+
* Definisce il contesto da cui è stato invocato il TMDcmtForm.
|
|
6
|
+
* Permette di gestire logiche diverse in base alla provenienza.
|
|
7
|
+
*/
|
|
8
|
+
export declare enum InvocationContext {
|
|
9
|
+
/** Invocazione standard */
|
|
10
|
+
Default = "default",
|
|
11
|
+
/** Invocato dalla pagina Todo/Task */
|
|
12
|
+
Todo = "todo",
|
|
13
|
+
/** Invocato dalla pagina WorkflowCtrl */
|
|
14
|
+
WorkflowCtrl = "workflowCtrl"
|
|
15
|
+
}
|
|
4
16
|
interface ITMDcmtFormProps {
|
|
5
17
|
allTasks?: Array<TaskDescriptor>;
|
|
6
18
|
getAllTasks?: () => Promise<void>;
|
|
@@ -24,7 +36,7 @@ interface ITMDcmtFormProps {
|
|
|
24
36
|
canPrev?: boolean;
|
|
25
37
|
isClosable?: boolean;
|
|
26
38
|
groupId?: string;
|
|
27
|
-
|
|
39
|
+
invocationContext?: InvocationContext;
|
|
28
40
|
taskFormDialogComponent?: React.ReactNode;
|
|
29
41
|
taskMoreInfo?: TaskDescriptor;
|
|
30
42
|
showBackButton?: boolean;
|