@topconsultnpm/sdkui-react 6.20.0-dev1.123 → 6.20.0-dev1.124
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/styles.js +11 -34
- package/lib/components/NewComponents/FloatingMenuBar/TMFloatingMenuBar.js +57 -45
- package/lib/components/NewComponents/FloatingMenuBar/types.d.ts +2 -2
- package/lib/components/features/search/TMSearchResult.js +1 -1
- package/lib/components/features/workflow/diagram/WFDiagram.js +1 -1
- package/package.json +1 -1
|
@@ -239,11 +239,11 @@ export const Submenu = styled.div `
|
|
|
239
239
|
position: fixed;
|
|
240
240
|
left: ${props => {
|
|
241
241
|
const spaceOnRight = globalThis.innerWidth - props.$parentRect.right;
|
|
242
|
-
return spaceOnRight > 240 ? `${props.$parentRect.right -
|
|
242
|
+
return spaceOnRight > 240 ? `${props.$parentRect.right - 4}px` : 'auto';
|
|
243
243
|
}};
|
|
244
244
|
right: ${props => {
|
|
245
245
|
const spaceOnRight = globalThis.innerWidth - props.$parentRect.right;
|
|
246
|
-
return spaceOnRight > 240 ? 'auto' : `${globalThis.innerWidth - props.$parentRect.left +
|
|
246
|
+
return spaceOnRight > 240 ? 'auto' : `${globalThis.innerWidth - props.$parentRect.left + 4}px`;
|
|
247
247
|
}};
|
|
248
248
|
/* Vertical positioning: Each submenu independently decides direction based on its own space */
|
|
249
249
|
top: ${props => {
|
|
@@ -266,25 +266,25 @@ export const Submenu = styled.div `
|
|
|
266
266
|
backdrop-filter: blur(10px);
|
|
267
267
|
border: 1px solid rgba(0, 0, 0, 0.06);
|
|
268
268
|
|
|
269
|
-
/*
|
|
269
|
+
/* Invisible hover bridge on the LEFT side (for submenus opening left) */
|
|
270
270
|
&::before {
|
|
271
271
|
content: '';
|
|
272
272
|
position: absolute;
|
|
273
273
|
right: 100%;
|
|
274
|
-
top:
|
|
275
|
-
bottom:
|
|
276
|
-
width:
|
|
274
|
+
top: -20px;
|
|
275
|
+
bottom: -20px;
|
|
276
|
+
width: 25px;
|
|
277
277
|
background: transparent;
|
|
278
278
|
}
|
|
279
279
|
|
|
280
|
-
/*
|
|
280
|
+
/* Invisible hover bridge on the RIGHT side (for submenus opening right) */
|
|
281
281
|
&::after {
|
|
282
282
|
content: '';
|
|
283
283
|
position: absolute;
|
|
284
284
|
left: 100%;
|
|
285
|
-
top:
|
|
286
|
-
bottom:
|
|
287
|
-
width:
|
|
285
|
+
top: -20px;
|
|
286
|
+
bottom: -20px;
|
|
287
|
+
width: 25px;
|
|
288
288
|
background: transparent;
|
|
289
289
|
}
|
|
290
290
|
|
|
@@ -328,30 +328,7 @@ export const Submenu = styled.div `
|
|
|
328
328
|
&::-webkit-scrollbar-thumb:hover {
|
|
329
329
|
background: rgba(0, 0, 0, 0.3);
|
|
330
330
|
}
|
|
331
|
-
` :
|
|
332
|
-
/* Fallback max-height for submenus that fit */
|
|
333
|
-
max-height: calc(100vh - 40px);
|
|
334
|
-
overflow-y: auto;
|
|
335
|
-
overflow-x: hidden;
|
|
336
|
-
|
|
337
|
-
&::-webkit-scrollbar {
|
|
338
|
-
width: 8px;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
&::-webkit-scrollbar-track {
|
|
342
|
-
background: rgba(0, 0, 0, 0.05);
|
|
343
|
-
border-radius: 4px;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
&::-webkit-scrollbar-thumb {
|
|
347
|
-
background: rgba(0, 0, 0, 0.2);
|
|
348
|
-
border-radius: 4px;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
&::-webkit-scrollbar-thumb:hover {
|
|
352
|
-
background: rgba(0, 0, 0, 0.3);
|
|
353
|
-
}
|
|
354
|
-
`}
|
|
331
|
+
` : ``}
|
|
355
332
|
|
|
356
333
|
[data-theme='dark'] & {
|
|
357
334
|
&::-webkit-scrollbar-track {
|
|
@@ -7,7 +7,7 @@ import * as S from './styles';
|
|
|
7
7
|
import { IconDelete, IconMenuVertical, IconPin, IconRotate, IconSeparator, SDKUI_Globals } from '../../../helper';
|
|
8
8
|
const Separator = (props) => (_jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", height: "1em", width: "1em", ...props, children: _jsx("path", { d: "M12 2v20", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round" }) }));
|
|
9
9
|
const IconDraggableDots = (props) => (_jsx("svg", { fontSize: 18, viewBox: "0 0 24 24", fill: "currentColor", height: "1em", width: "1em", ...props, children: _jsx("path", { d: "M9 3a2 2 0 11-4 0 2 2 0 014 0zm0 9a2 2 0 11-4 0 2 2 0 014 0zm0 9a2 2 0 11-4 0 2 2 0 014 0zm10-18a2 2 0 11-4 0 2 2 0 014 0zm0 9a2 2 0 11-4 0 2 2 0 014 0zm0 9a2 2 0 11-4 0 2 2 0 014 0z" }) }));
|
|
10
|
-
const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained = false, defaultPosition = { x: 1, y: 90 }, defaultOrientation = 'horizontal', maxItems = 100,
|
|
10
|
+
const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained = false, defaultPosition = { x: 1, y: 90 }, defaultOrientation = 'horizontal', maxItems = 100, defaultPinnedItems = [], fixedItems = [], enableConfigMode = true, bgColor = undefined, hasContextMenu = true, pinnedItemIds: externalPinnedItemIds, onPinChange, }) => {
|
|
11
11
|
const percentToPixels = (percent, containerSize) => {
|
|
12
12
|
return (percent / 100) * containerSize;
|
|
13
13
|
};
|
|
@@ -28,7 +28,7 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
28
28
|
};
|
|
29
29
|
const getDefaultConfig = () => ({
|
|
30
30
|
orientation: defaultOrientation,
|
|
31
|
-
savedItemIds:
|
|
31
|
+
savedItemIds: defaultPinnedItems,
|
|
32
32
|
position: defaultPosition,
|
|
33
33
|
});
|
|
34
34
|
const resetFloatingBarSettings = () => {
|
|
@@ -44,14 +44,14 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
44
44
|
if (!enableConfigMode) {
|
|
45
45
|
return {
|
|
46
46
|
orientation: defaultOrientation,
|
|
47
|
-
savedItemIds:
|
|
47
|
+
savedItemIds: defaultPinnedItems,
|
|
48
48
|
position: defaultPosition,
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
51
|
try {
|
|
52
52
|
const settings = SDKUI_Globals.userSettings.searchSettings.floatingMenuBar;
|
|
53
|
-
// If localStorage is empty (first time), use props as defaults
|
|
54
|
-
if (!settings || !settings.position || !settings.itemIds) {
|
|
53
|
+
// If localStorage is empty (first time) or itemIds is empty array, use props as defaults
|
|
54
|
+
if (!settings || !settings.position || !settings.itemIds || settings.itemIds.length === 0) {
|
|
55
55
|
return getDefaultConfig();
|
|
56
56
|
}
|
|
57
57
|
// Validate position
|
|
@@ -145,6 +145,7 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
145
145
|
const isSyncingFromExternal = useRef(false);
|
|
146
146
|
const isLocalChange = useRef(false);
|
|
147
147
|
const dragStartPosition = useRef(null);
|
|
148
|
+
const isItemsInitialized = useRef(false);
|
|
148
149
|
useEffect(() => {
|
|
149
150
|
floatingBarItemIds.current = new Set(state.items.map(i => i.id));
|
|
150
151
|
floatingBarItemNames.current = new Set(state.items.map(i => i.name));
|
|
@@ -204,49 +205,56 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
204
205
|
});
|
|
205
206
|
return result;
|
|
206
207
|
}, [state.items]);
|
|
207
|
-
// Restore items on mount from savedItemIds
|
|
208
|
+
// Restore items on mount (and when contextMenuItems become available) from savedItemIds
|
|
208
209
|
useEffect(() => {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
if (!enableConfigMode && defaultItems.length > 0) {
|
|
214
|
-
itemsToSet = defaultItems;
|
|
215
|
-
}
|
|
216
|
-
else if (enableConfigMode && initialConfig.savedItemIds.length > 0) {
|
|
217
|
-
// Restore items in the saved order from localStorage (only if config mode is enabled)
|
|
218
|
-
const restoredItems = initialConfig.savedItemIds
|
|
219
|
-
.map((id) => {
|
|
220
|
-
if (id.startsWith('separator-')) {
|
|
221
|
-
return {
|
|
222
|
-
id,
|
|
223
|
-
name: 'Separator',
|
|
224
|
-
icon: _jsx(Separator, {}),
|
|
225
|
-
onClick: () => { },
|
|
226
|
-
isSeparator: true,
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
return flatItems.find(item => item.id === id);
|
|
230
|
-
})
|
|
231
|
-
.filter((item) => item !== undefined);
|
|
232
|
-
itemsToSet = restoredItems;
|
|
233
|
-
}
|
|
234
|
-
else if (contextMenuDefaultPinnedIds.length > 0) {
|
|
235
|
-
// First time: Use contextMenuDefaultPinnedIds from props to find items by ID
|
|
236
|
-
const defaultPinnedItems = contextMenuDefaultPinnedIds
|
|
237
|
-
.map((id) => flatItems.find(item => item.id === id))
|
|
238
|
-
.filter((item) => item !== undefined);
|
|
239
|
-
itemsToSet = defaultPinnedItems;
|
|
240
|
-
}
|
|
241
|
-
else if (defaultItems.length > 0) {
|
|
242
|
-
// Use defaultItems as fallback
|
|
243
|
-
itemsToSet = defaultItems;
|
|
244
|
-
}
|
|
245
|
-
if (itemsToSet.length > 0) {
|
|
246
|
-
setState(s => ({ ...s, items: itemsToSet }));
|
|
210
|
+
// For enableConfigMode=false: always sync with fixedItems
|
|
211
|
+
if (!enableConfigMode) {
|
|
212
|
+
if (fixedItems.length > 0) {
|
|
213
|
+
setState(s => ({ ...s, items: fixedItems }));
|
|
247
214
|
}
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
// For enableConfigMode=true: only initialize once
|
|
218
|
+
if (isItemsInitialized.current)
|
|
219
|
+
return;
|
|
220
|
+
// Wait until contextMenuItems is populated
|
|
221
|
+
if (contextMenuItems.length === 0)
|
|
222
|
+
return;
|
|
223
|
+
const flatItems = flattenMenuItems(contextMenuItems);
|
|
224
|
+
if (flatItems.length === 0)
|
|
225
|
+
return;
|
|
226
|
+
let itemsToSet = [];
|
|
227
|
+
if (initialConfig.savedItemIds.length > 0) {
|
|
228
|
+
// Restore items in the saved order from localStorage
|
|
229
|
+
const restoredItems = initialConfig.savedItemIds
|
|
230
|
+
.map((id) => {
|
|
231
|
+
if (id.startsWith('separator-')) {
|
|
232
|
+
return {
|
|
233
|
+
id,
|
|
234
|
+
name: 'Separator',
|
|
235
|
+
icon: _jsx(Separator, {}),
|
|
236
|
+
onClick: () => { },
|
|
237
|
+
isSeparator: true,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
return flatItems.find(item => item.id === id);
|
|
241
|
+
})
|
|
242
|
+
.filter((item) => item !== undefined);
|
|
243
|
+
itemsToSet = restoredItems;
|
|
244
|
+
}
|
|
245
|
+
// If still empty, try defaultPinnedItems
|
|
246
|
+
if (itemsToSet.length === 0 && defaultPinnedItems.length > 0) {
|
|
247
|
+
const resolvedDefaultItems = defaultPinnedItems
|
|
248
|
+
.map((id) => flatItems.find(item => item.id === id))
|
|
249
|
+
.filter((item) => item !== undefined);
|
|
250
|
+
itemsToSet = resolvedDefaultItems;
|
|
248
251
|
}
|
|
249
|
-
|
|
252
|
+
if (itemsToSet.length > 0) {
|
|
253
|
+
isItemsInitialized.current = true;
|
|
254
|
+
setState(s => ({ ...s, items: itemsToSet }));
|
|
255
|
+
}
|
|
256
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
257
|
+
}, [contextMenuItems, fixedItems, enableConfigMode]);
|
|
250
258
|
// Sync with external pinnedItemIds when they change (from parent component)
|
|
251
259
|
useEffect(() => {
|
|
252
260
|
// Skip sync if a local change was just made (e.g. right-click remove/add separator)
|
|
@@ -256,6 +264,10 @@ const TMFloatingMenuBar = ({ containerRef, contextMenuItems = [], isConstrained
|
|
|
256
264
|
}
|
|
257
265
|
if (externalPinnedItemIds === undefined || !enableConfigMode)
|
|
258
266
|
return;
|
|
267
|
+
// Skip sync if external is empty but we have initialized items (first login case)
|
|
268
|
+
// The parent hook starts with [] but we've initialized with defaults
|
|
269
|
+
if (externalPinnedItemIds.length === 0 && state.items.length > 0)
|
|
270
|
+
return;
|
|
259
271
|
const flatItems = flattenMenuItems(contextMenuItems);
|
|
260
272
|
// Build items from external pinned IDs
|
|
261
273
|
const itemsFromExternal = externalPinnedItemIds
|
|
@@ -16,9 +16,9 @@ export interface TMFloatingMenuBarProps {
|
|
|
16
16
|
isConstrained?: boolean;
|
|
17
17
|
defaultPosition?: Position;
|
|
18
18
|
maxItems?: number;
|
|
19
|
-
|
|
19
|
+
defaultPinnedItems?: string[];
|
|
20
20
|
defaultOrientation?: 'horizontal' | 'vertical';
|
|
21
|
-
|
|
21
|
+
fixedItems?: TMFloatingMenuItem[];
|
|
22
22
|
enableConfigMode?: boolean;
|
|
23
23
|
bgColor?: string;
|
|
24
24
|
hasContextMenu?: boolean;
|
|
@@ -614,7 +614,7 @@ const TMSearchResult = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, a
|
|
|
614
614
|
_jsx(TMLayoutItem, { children: _jsx(TMSearchResultSelector, { searchResults: currentSearchResults, disableAccordionIfSingleCategory: disableAccordionIfSingleCategory, selectedTID: selectedSearchResultTID, selectedSearchResult: selectedSearchResult, autoSelectFirst: !isMobile || currentSearchResults.length === 1, onSelectionChanged: onSearchResultSelectionChanged }) })
|
|
615
615
|
:
|
|
616
616
|
_jsx(_Fragment, {}), _jsx(TMLayoutItem, { children: _jsx(TMSearchResultGrid, { showSearch: showSearch, fromDTD: fromDTD, allUsers: allUsers, inputFocusedItem: focusedItem, inputSelectedItems: selectedItems, searchResult: searchResults.length > 1 ? selectedSearchResult : searchResults[0], lastUpdateSearchTime: lastUpdateSearchTime, openInOffice: openInOffice, onDblClick: () => openFormHandler(LayoutModes.Update), floatingMenuItems: floatingMenuItems, onSelectionChanged: (items) => { setSelectedItems(items); }, onVisibleItemChanged: setVisibleItems, onFocusedItemChanged: setFocusedItem, onDownloadDcmtsAsync: async (inputDcmts, downloadType, downloadMode, _y, confirmAttachments) => await downloadDcmtsAsync(inputDcmts, downloadType, downloadMode, onFileOpened, confirmAttachments), showExportForm: showExportForm, onCloseExportForm: onCloseExportForm }) })] }), allowFloatingBar && showFloatingBar && deviceType !== DeviceType.MOBILE &&
|
|
617
|
-
_jsx(TMFloatingMenuBar, { containerRef: floatingBarContainerRef, contextMenuItems: floatingMenuItems, isConstrained: true, defaultPosition: { x: 1, y: 88 },
|
|
617
|
+
_jsx(TMFloatingMenuBar, { containerRef: floatingBarContainerRef, contextMenuItems: floatingMenuItems, isConstrained: true, defaultPosition: { x: 1, y: 88 }, defaultPinnedItems: ['rel-det', 'rel-mst', 'dl'], defaultOrientation: 'horizontal', hasContextMenu: false, pinnedItemIds: pinnedItemIds, onPinChange: setPinnedItemIds })] }), showApprovePopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: onWFOperationCompleted, selectedItems: getSelectedDcmtsOrFocused(selectedItems, focusedItem), isReject: 0, onClose: () => setShowApprovePopup(false) }), showRejectPopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: onWFOperationCompleted, selectedItems: getSelectedDcmtsOrFocused(selectedItems, focusedItem), isReject: 1, onClose: () => setShowRejectPopup(false) }), showReAssignPopup && _jsx(WorkFlowReAssignPopUp, { deviceType: deviceType, onCompleted: onWFOperationCompleted, selectedItems: getSelectedDcmtsOrFocused(selectedItems, focusedItem), onClose: () => setShowReAssignPopup(false) }), showMoreInfoPopup && _jsx(WorkFlowMoreInfoPopUp, { TID: focusedItem?.TID, DID: focusedItem?.DID, deviceType: deviceType, onCompleted: onWFOperationCompleted, onClose: () => setShowMoreInfoPopup(false) }), isOpenBatchUpdate && _jsx(TMBatchUpdateForm, { isModal: true, titleModal: `${SDKUI_Localizator.BatchUpdate} (${getSelectionDcmtInfo().length} documenti selezionati)`, inputDcmts: getSelectionDcmtInfo(), TID: focusedItem ? focusedItem?.TID : selectedItems[0]?.TID, DID: focusedItem ? focusedItem?.DID : selectedItems[0]?.DID, onBack: () => {
|
|
618
618
|
setIsOpenBatchUpdate(false);
|
|
619
619
|
}, onSavedCallbackAsync: async () => {
|
|
620
620
|
setIsOpenBatchUpdate(false);
|
|
@@ -1822,7 +1822,7 @@ const WFDiagram = ({ xmlDiagramString, currentSetID, allowEdit = true, onDiagram
|
|
|
1822
1822
|
}, [isFullScreen]);
|
|
1823
1823
|
const diagramContent = (_jsxs(CanvasContainer, { onDoubleClick: handleCanvasDoubleClick, children: [_jsx("input", { ref: fileInputRef, type: "file", accept: ".xml" // Filtra per file XML
|
|
1824
1824
|
, onChange: handleFileChange, style: { display: 'none' } }), SDK_Globals.tmSession?.SessionDescr?.appModuleID === AppModules.SURFER ?
|
|
1825
|
-
_jsx(TMFloatingMenuBar, { containerRef: diagramRef, defaultPosition: { x: 45, y: 85 }, enableConfigMode: false,
|
|
1825
|
+
_jsx(TMFloatingMenuBar, { containerRef: diagramRef, defaultPosition: { x: 45, y: 85 }, enableConfigMode: false, fixedItems: [
|
|
1826
1826
|
{ icon: _jsx(IconZoomIn, {}), name: SDKUI_Localizator.ZoomIn, disabled: isAutoZoomEnabled, onClick: () => { handleZoomIn(); }, id: 'zoom-in', isPinned: true },
|
|
1827
1827
|
{ icon: _jsx(IconZoomOut, {}), name: SDKUI_Localizator.ZoomOut, disabled: isAutoZoomEnabled, onClick: () => { handleZoomOut(); }, id: 'zoom-out', isPinned: true },
|
|
1828
1828
|
{ icon: _jsx(IconZoomAuto, {}), name: 'AutoZoom', onClick: () => { handleToggleAutoZoom(); }, id: 'zoom-auto', isPinned: true, isToggle: isAutoZoomEnabled },
|