@topconsultnpm/sdkui-react-beta 6.13.42 → 6.13.44

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.
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import { LayoutModes } from '@topconsultnpm/sdk-ts-beta';
3
3
  import { FormModes } from '../../../ts';
4
+ import { DeviceType } from '../../base/TMDeviceProvider';
4
5
  import { TMCommandItemProps } from '../../sidebar/TMCommandsPanel';
5
6
  interface ITMDcmtFormProps {
6
7
  TID?: number;
@@ -37,3 +38,8 @@ interface ITMDcmtFormProps {
37
38
  }
38
39
  declare const TMDcmtForm: React.FC<ITMDcmtFormProps>;
39
40
  export default TMDcmtForm;
41
+ export declare const ToppyHelpCenter: ({ content, onClick, deviceType }: {
42
+ content?: any;
43
+ onClick?: () => void;
44
+ deviceType?: DeviceType;
45
+ }) => import("react/jsx-runtime").JSX.Element;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useState } from 'react';
3
- import styled from 'styled-components';
3
+ import styled, { keyframes } from 'styled-components';
4
4
  import TMDcmtPreview from './TMDcmtPreview';
5
5
  import { AccessLevels, ArchiveConstraints, ArchiveEngineByID, DcmtTypeListCacheService, LayoutModes, MetadataDataTypes, ResultTypes, SDK_Globals, SystemMIDsAsNumber, TemplateTIDs, UpdateEngineByID, ValidationItem } from '@topconsultnpm/sdk-ts-beta';
6
6
  import { ContextMenu } from 'devextreme-react';
@@ -31,6 +31,7 @@ import { useInputAttachmentsDialog } from '../../../hooks/useInputDialog';
31
31
  import TMModal from '../../base/TMModal';
32
32
  import TMPanel from '../../base/TMPanel';
33
33
  import TMCommandsPanel from '../../sidebar/TMCommandsPanel';
34
+ import toppy from '../../../assets/Toppy-generico.png';
34
35
  let abortControllerLocal = new AbortController();
35
36
  //#endregion
36
37
  const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes.Update, onClose, onSavedAsyncCallback, TID, DID, formMode = FormModes.Update, canNext, canPrev, count, itemIndex, onNext, onPrev, customRightSidebarItems = [], allowNavigation = true, allowRelations = true, isClosable = false, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, showDcmtForm = true, showDcmtFormSidebar = true, showPreview = false, showBoard = false, showSysMetadata = false, onClosePreviewPanel, onCloseBlogPanel, onCloseSysMetadataPanel, titleModal, isModal = false, widthModal = "100%", heightModal = "100%" }) => {
@@ -453,7 +454,7 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
453
454
  gap: SDKUI_Globals.userSettings.themeSettings.gutters,
454
455
  width: '100%',
455
456
  height: '100%',
456
- }, children: [_jsx("div", { style: { flex: 1, minWidth: 0, height: '100%' }, children: _jsxs(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: useWaitPanelLocalState ? showWaitPanelLocal : showWaitPanel, showWaitPanelPrimary: useWaitPanelLocalState ? showPrimaryLocal : showPrimary, showWaitPanelSecondary: useWaitPanelLocalState ? showSecondaryLocal : showSecondary, waitPanelTitle: useWaitPanelLocalState ? waitPanelTitleLocal : waitPanelTitle, waitPanelTextPrimary: useWaitPanelLocalState ? waitPanelTextPrimaryLocal : waitPanelTextPrimary, waitPanelValuePrimary: useWaitPanelLocalState ? waitPanelValuePrimaryLocal : waitPanelValuePrimary, waitPanelMaxValuePrimary: useWaitPanelLocalState ? waitPanelMaxValuePrimaryLocal : waitPanelMaxValuePrimary, waitPanelTextSecondary: useWaitPanelLocalState ? waitPanelTextSecondaryLocal : waitPanelTextSecondary, waitPanelValueSecondary: useWaitPanelLocalState ? waitPanelValueSecondaryLocal : waitPanelValueSecondary, waitPanelMaxValueSecondary: useWaitPanelLocalState ? waitPanelMaxValueSecondaryLocal : waitPanelMaxValueSecondary, isCancelable: useWaitPanelLocalState ? dcmtFile ? dcmtFile.size >= 1000000 : false : true, abortController: useWaitPanelLocalState ? abortControllerLocal : abortController, children: [_jsxs(TMSplitterLayout, { direction: 'horizontal', overflow: 'visible', separatorSize: SDKUI_Globals.userSettings.themeSettings.gutters, separatorColor: 'transparent', showSeparator: (isOpenPreview || isOpenMiddlePanel()) && deviceType !== DeviceType.MOBILE && isOpenDcmtForm, start: getPrimarySplitterStartLayout(), min: deviceType !== DeviceType.MOBILE && isOpenDcmtForm ? ['150px', '0'] : ['0', '0'], children: [_jsx(TMLayoutItem, { children: _jsx(TMPanel, { showHeader: showHeader, title: fromDTD?.nameLoc, toolbar: allowNavigation ? formToolbar : _jsx(_Fragment, {}), onBack: isClosable && deviceType !== DeviceType.MOBILE ? undefined : handleClose, onClose: isClosable ? handleClose : undefined, children: metadataValuesSource.length > 0 && _jsxs(StyledToolbarCardContainer, { children: [_jsx(TMMetadataValues, { TID: TID, metadataValues: metadataValuesSource, metadataValuesOrig: metadataValuesSourceOrig, isExpertMode: isExpertMode, isOpenDistinctValues: isOpenDistinctValues, openChooserBySingleClick: !isOpenDistinctValues, selectedMID: focusedMetadataValue?.mid, layoutMode: layoutMode, deviceType: deviceType, validationItems: validationItems, onFocusedItemChanged: (item) => { (item?.mid !== focusedMetadataValue?.mid) && setFocusedMetadataValue(item); }, onValueChanged: (newItems) => {
457
+ }, children: [_jsx("div", { style: { flex: 1, minWidth: 0, height: '100%' }, children: _jsxs(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: useWaitPanelLocalState ? showWaitPanelLocal : showWaitPanel, showWaitPanelPrimary: useWaitPanelLocalState ? showPrimaryLocal : showPrimary, showWaitPanelSecondary: useWaitPanelLocalState ? showSecondaryLocal : showSecondary, waitPanelTitle: useWaitPanelLocalState ? waitPanelTitleLocal : waitPanelTitle, waitPanelTextPrimary: useWaitPanelLocalState ? waitPanelTextPrimaryLocal : waitPanelTextPrimary, waitPanelValuePrimary: useWaitPanelLocalState ? waitPanelValuePrimaryLocal : waitPanelValuePrimary, waitPanelMaxValuePrimary: useWaitPanelLocalState ? waitPanelMaxValuePrimaryLocal : waitPanelMaxValuePrimary, waitPanelTextSecondary: useWaitPanelLocalState ? waitPanelTextSecondaryLocal : waitPanelTextSecondary, waitPanelValueSecondary: useWaitPanelLocalState ? waitPanelValueSecondaryLocal : waitPanelValueSecondary, waitPanelMaxValueSecondary: useWaitPanelLocalState ? waitPanelMaxValueSecondaryLocal : waitPanelMaxValueSecondary, isCancelable: useWaitPanelLocalState ? dcmtFile ? dcmtFile.size >= 1000000 : false : true, abortController: useWaitPanelLocalState ? abortControllerLocal : abortController, children: [_jsxs(TMSplitterLayout, { direction: 'horizontal', overflow: 'visible', separatorSize: SDKUI_Globals.userSettings.themeSettings.gutters, separatorColor: 'transparent', showSeparator: (isOpenPreview || isOpenMiddlePanel()) && deviceType !== DeviceType.MOBILE && isOpenDcmtForm, start: getPrimarySplitterStartLayout(), min: deviceType !== DeviceType.MOBILE && isOpenDcmtForm ? ['150px', '0'] : ['0', '0'], children: [_jsx(TMLayoutItem, { children: _jsx(TMPanel, { showHeader: showHeader, title: fromDTD?.nameLoc, toolbar: allowNavigation ? formToolbar : _jsx(_Fragment, {}), onBack: (isClosable && deviceType !== DeviceType.MOBILE) ? undefined : handleClose, onClose: isClosable ? handleClose : undefined, children: metadataValuesSource.length > 0 && _jsxs(StyledToolbarCardContainer, { children: [_jsx(TMMetadataValues, { TID: TID, metadataValues: metadataValuesSource, metadataValuesOrig: metadataValuesSourceOrig, isExpertMode: isExpertMode, isOpenDistinctValues: isOpenDistinctValues, openChooserBySingleClick: !isOpenDistinctValues, selectedMID: focusedMetadataValue?.mid, layoutMode: layoutMode, deviceType: deviceType, validationItems: validationItems, onFocusedItemChanged: (item) => { (item?.mid !== focusedMetadataValue?.mid) && setFocusedMetadataValue(item); }, onValueChanged: (newItems) => {
457
458
  setFormData((prevItems) => prevItems.map((item) => {
458
459
  const newItem = newItems.find((newItem) => newItem.tid === item.tid && newItem.mid === item.mid);
459
460
  return newItem ? { ...item, ...newItem } : item;
@@ -467,8 +468,8 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
467
468
  setIsOpenFormulaEditor(!isOpenFormulaEditor);
468
469
  break;
469
470
  }
470
- } }), _jsxs(StyledFormButtonsContainer, { children: [_jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 10 }, children: [fromDTD?.templateTID === TemplateTIDs.WF_WIApprView && _jsx(WorkFlowOperationButtons, { onApprove: () => setShowApprovePopup(true), onReject: () => setShowRejectPopup(true), onReAssign: () => setShowReAssignPopup(true), isInDcmtForm: true }), _jsx("div", { style: { display: 'flex', justifyContent: 'center', alignItems: 'center', gap: '8px' }, children: layoutMode === LayoutModes.Update ? _jsxs(_Fragment, { children: [_jsx(TMSaveFormButtonSave, { showTooltip: false, btnStyle: 'advanced', advancedColor: '#f09c0a', isModified: isModified, formMode: formMode, errorsCount: validationItems.filter(o => o.ResultType == ResultTypes.ERROR).length, onSaveAsync: confirmActionPopup }), _jsx(TMSaveFormButtonUndo, { btnStyle: 'toolbar', showTooltip: true, color: 'primary', isModified: isModified, formMode: formMode, onUndo: onUndoHandler })] }) :
471
- _jsxs(_Fragment, { children: [_jsx(TMButton, { disabled: archiveBtnDisabled, btnStyle: 'advanced', icon: _jsx(IconBoxArchiveIn, {}), showTooltip: false, caption: 'Archivia', advancedColor: TMColors.success, onClick: confirmActionPopup }), _jsx(TMButton, { disabled: !clearFormBtnDisabled, btnStyle: 'advanced', icon: _jsx(IconClear, {}), showTooltip: false, caption: 'Pulisci', advancedColor: TMColors.tertiary, onClick: clearFormHandler }), DID && _jsx(TMButton, { disabled: undoBtnDisabled, btnStyle: 'advanced', icon: _jsx(IconUndo, {}), width: '150px', showTooltip: false, caption: 'Annulla modifiche', advancedColor: TMColors.tertiary, onClick: onUndoHandler })] }) })] }), totalItems > listMaxItems && _jsx(TMShowAllOrMaxItemsButton, { showAll: showAll, dataSourceLength: totalItems, onClick: () => { setShowAll(!showAll); } })] }), showApprovePopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, TID: TID, DID: DID, op: 0, onClose: () => setShowApprovePopup(false) }), showRejectPopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, TID: TID, DID: DID, op: 1, onClose: () => setShowRejectPopup(false) }), showReAssignPopup && _jsx(WorkFlowReAssignPopUp, { deviceType: deviceType, TID: TID, DID: DID, onClose: () => setShowReAssignPopup(false) }), _jsx(ConfirmAttachmentsDialog, {})] }) }) }), isOpenPreview || isOpenMiddlePanel() ?
471
+ } }), _jsxs(StyledFormButtonsContainer, { children: [_jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: 10 }, children: _jsx("div", { style: { display: 'flex', justifyContent: 'center', alignItems: 'center', gap: '8px' }, children: layoutMode === LayoutModes.Update ? _jsxs(_Fragment, { children: [_jsx(TMSaveFormButtonSave, { showTooltip: false, btnStyle: 'advanced', advancedColor: '#f09c0a', isModified: isModified, formMode: formMode, errorsCount: validationItems.filter(o => o.ResultType == ResultTypes.ERROR).length, onSaveAsync: confirmActionPopup }), _jsx(TMSaveFormButtonUndo, { btnStyle: 'toolbar', showTooltip: true, color: 'primary', isModified: isModified, formMode: formMode, onUndo: onUndoHandler })] }) :
472
+ _jsxs(_Fragment, { children: [_jsx(TMButton, { disabled: archiveBtnDisabled, btnStyle: 'advanced', icon: _jsx(IconBoxArchiveIn, {}), showTooltip: false, caption: 'Archivia', advancedColor: TMColors.success, onClick: confirmActionPopup }), _jsx(TMButton, { disabled: !clearFormBtnDisabled, btnStyle: 'advanced', icon: _jsx(IconClear, {}), showTooltip: false, caption: 'Pulisci', advancedColor: TMColors.tertiary, onClick: clearFormHandler }), DID && _jsx(TMButton, { disabled: undoBtnDisabled, btnStyle: 'advanced', icon: _jsx(IconUndo, {}), width: '150px', showTooltip: false, caption: 'Annulla modifiche', advancedColor: TMColors.tertiary, onClick: onUndoHandler })] }) }) }), totalItems > listMaxItems && _jsx(TMShowAllOrMaxItemsButton, { showAll: showAll, dataSourceLength: totalItems, onClick: () => { setShowAll(!showAll); } })] }), showApprovePopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, TID: TID, DID: DID, op: 0, onClose: () => setShowApprovePopup(false) }), showRejectPopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, TID: TID, DID: DID, op: 1, onClose: () => setShowRejectPopup(false) }), showReAssignPopup && _jsx(WorkFlowReAssignPopUp, { deviceType: deviceType, TID: TID, DID: DID, onClose: () => setShowReAssignPopup(false) }), _jsx(ConfirmAttachmentsDialog, {})] }) }) }), isOpenPreview || isOpenMiddlePanel() ?
472
473
  _jsx(TMLayoutItem, { children: _jsxs(TMSplitterLayout, { direction: 'horizontal', overflow: 'visible', separatorSize: SDKUI_Globals.userSettings.themeSettings.gutters, showSeparator: deviceType !== DeviceType.MOBILE && (isOpenPreview && isOpenMiddlePanel()), start: getSecondarySplitterStartLayout(), min: ['0', '0'], separatorColor: 'transparent', children: [isOpenMiddlePanel()
473
474
  ? _jsx(TMLayoutItem, { children: _jsxs(TMPanel, { showHeader: !(isOpenDetails && layoutMode === LayoutModes.Update), title: titleText(), onClose: () => { closeMiddlePanel(); }, children: [isOpenBoard && layoutMode === LayoutModes.Update &&
474
475
  _jsx(TMDcmtBlog, { tid: TID, did: DID }), isOpenSysMetadata && layoutMode === LayoutModes.Update &&
@@ -514,7 +515,10 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
514
515
  ...(allowRelations && currentTIDHasDetailRelations ? [{ icon: _jsx(IconDetailDcmts, { transform: 'scale(-1, 1)' }), selected: isOpenDetails, disabled: isDetailsDisabled, onClick: () => { if (!isDetailsDisabled)
515
516
  setIsOpenDetails(!isOpenDetails); } }] : []),
516
517
  ...customRightSidebarItems
517
- ] }), isOpenDetails &&
518
+ ] }), (fromDTD?.templateTID === TemplateTIDs.WF_WIApprView && !isOpenDetails && !isOpenMaster) &&
519
+ _jsx(ToppyHelpCenter, { deviceType: deviceType,
520
+ // onClick={() => isMobile ? openConfigureMode?.() : undefined}
521
+ content: _jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: '10px' }, children: _jsx(WorkFlowOperationButtons, { onApprove: () => setShowApprovePopup(true), onReject: () => setShowRejectPopup(true), onReAssign: () => setShowReAssignPopup(true), isInDcmtForm: deviceType === DeviceType.MOBILE }) }) }), isOpenDetails &&
518
522
  _jsx(StyledModalContainer, { style: { backgroundColor: 'white' }, children: _jsx(TMMasterDetailDcmts, { deviceType: deviceType, isForMaster: false, inputDcmts: getSelectionDcmtInfo(), allowNavigation: allowNavigation, canNext: canNext, canPrev: canPrev, onNext: onNext, onPrev: onPrev, onBack: () => setIsOpenDetails(false) }) }), isOpenMaster &&
519
523
  _jsxs(StyledModalContainer, { style: { backgroundColor: 'white' }, children: [_jsx(TMMasterDetailDcmts, { deviceType: deviceType, inputDcmts: getSelectionDcmtInfo(), isForMaster: true, allowNavigation: allowNavigation, canNext: canNext, canPrev: canPrev, onNext: onNext, onPrev: onPrev, onBack: () => setIsOpenMaster(false), appendMasterDcmts: handleAddItem }), secondaryMasterDcmts.length > 0 && secondaryMasterDcmts.map((dcmt, index) => {
520
524
  return (_jsx(StyledModalContainer, { style: { backgroundColor: 'white' }, children: _jsx(TMMasterDetailDcmts, { deviceType: deviceType, inputDcmts: [dcmt], isForMaster: true, allowNavigation: false, onBack: () => handleRemoveItem(dcmt.TID, dcmt.DID), appendMasterDcmts: handleAddItem }) }, `${index}-${dcmt.DID}`));
@@ -546,10 +550,6 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
546
550
  : renderDcmtForm() }));
547
551
  };
548
552
  export default TMDcmtForm;
549
- //#region Styled Components
550
- const StyledSectionContainer = styled.div ` width: 100%; height: 100%; display:flex; flex-direction: column; `;
551
- const StyledSidebarItemsContentContainer = styled.div `width: 100%; height: 100%; overflow:auto;`;
552
- //#endregion Styled Components
553
553
  //#region Validaion
554
554
  const validateMetadataList = (mvdList = []) => {
555
555
  if (!Array.isArray(mvdList)) {
@@ -580,3 +580,28 @@ const validateMaxLength = (mvd, value, validationItems) => {
580
580
  validationItems.push(new ValidationItem(ResultTypes.ERROR, mvd.md.nameLoc ?? "", message));
581
581
  }
582
582
  };
583
+ //#endregion Validation
584
+ const toppyEntrance = keyframes `
585
+ 0% { right: -200px; opacity: 0; }
586
+ 60% { opacity: 1; }
587
+ 100% { right: -70px; opacity: 1; }
588
+ `;
589
+ const ToppyContainer = styled.div `
590
+ position: absolute;
591
+ bottom: ${props => props.$isMobile ? '-70px' : '-50px'};
592
+ right: ${props => props.$isMobile ? '-70px' : '-50px'};
593
+ transform: rotate(-20deg);
594
+ display: flex;
595
+ align-items: center;
596
+ justify-content: center;
597
+ animation: ${toppyEntrance} 0.5s cubic-bezier(0.23, 1, 0.32, 1);
598
+ z-index: 1000;
599
+ `;
600
+ const ToppyImage = styled.img `
601
+ width: ${props => props.$isMobile ? '120px' : '170px'};
602
+ height: ${props => props.$isMobile ? '140px' : '200px'};
603
+ cursor: ${props => props.$isMobile ? 'pointer' : 'default'};
604
+ `;
605
+ export const ToppyHelpCenter = ({ content, onClick, deviceType }) => {
606
+ return (_jsxs(ToppyContainer, { children: [_jsx(ToppyImage, { "$isMobile": deviceType === DeviceType.MOBILE, onClick: onClick, src: toppy, alt: "Toppy" }), _jsx("div", { style: { top: deviceType === DeviceType.MOBILE ? -180 : -200, right: deviceType === DeviceType.MOBILE ? 20 : 1, transform: 'rotate(20deg)', position: 'absolute', width: 'max-content', height: 'max-content' }, children: content })] }));
607
+ };
@@ -387,7 +387,7 @@ const TMMasterDetailDcmts = ({ deviceType, inputDcmts, isForMaster, showCurrentD
387
387
  const renderTMFormOrResult = useMemo(() => (handleTogglePanel) => {
388
388
  return (_jsx(_Fragment, { children: focusedItem?.isDcmt ?
389
389
  _jsx(TMDcmtForm, { TID: focusedItem?.tid, DID: focusedItem.did, isClosable: deviceType !== DeviceType.MOBILE, allowNavigation: false, allowRelations: deviceType !== DeviceType.MOBILE, showDcmtFormSidebar: deviceType === DeviceType.MOBILE, showPreview: showPreview, showBoard: showBoard, showSysMetadata: showSysMetadata, showDcmtForm: showDcmtForm, onClose: () => { setShowDcmtForm(false); }, onClosePreviewPanel: () => { setShowPreview(false); } }) :
390
- _jsx(TMSearchResult, { context: SearchResultContext.METADATA_SEARCH, allowFloatingBar: false, searchResults: focusedItem?.searchResult ?? [], showPreview: showPreview, showSearchResultSidebar: false, onClose: () => { setShowDcmtForm(false); }, onClosePreviewPanel: () => {
390
+ _jsx(TMSearchResult, { context: SearchResultContext.METADATA_SEARCH, allowFloatingBar: false, searchResults: focusedItem?.searchResult ?? [], showPreview: showPreview, showBoard: showBoard, showSysMetadata: showSysMetadata, showSearchResultSidebar: false, onClose: () => { setShowDcmtForm(false); }, onClosePreviewPanel: () => {
391
391
  setShowPreview(false);
392
392
  handleTogglePanel("commandPreview");
393
393
  }, onTaskCreateRequest: onTaskCreateRequest }) }));
@@ -482,6 +482,7 @@ const TMMasterDetailDcmts = ({ deviceType, inputDcmts, isForMaster, showCurrentD
482
482
  visible: true,
483
483
  isActive: showZeroDcmts,
484
484
  orderNumber: 3,
485
+ beginGroup: true,
485
486
  },
486
487
  type: 'button',
487
488
  buttonOptions: {
@@ -1,17 +1,21 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useState } from 'react';
2
+ import { useCallback, useEffect, useRef, useState } from 'react';
3
3
  import { SavedQueryCacheService, DcmtTypeListCacheService, SDK_Localizator } from '@topconsultnpm/sdk-ts-beta';
4
4
  import TMSavedQuerySelector from './TMSavedQuerySelector';
5
5
  import TMTreeSelector from './TMTreeSelector';
6
6
  import { TabPanel, Item } from 'devextreme-react/tab-panel';
7
7
  import TMSearchQueryPanel, { refreshLastSearch } from './TMSearchQueryPanel';
8
- import { getSysAllDcmtsSQD, IconArrowRight, IconFilter, IconRecentlyViewed, IconSavedQuery, IconTree, SDKUI_Globals, SDKUI_Localizator } from '../../../helper';
8
+ import { getSysAllDcmtsSQD, IconFilter, IconInfo, IconRecentlyViewed, IconSavedQuery, IconTree, SDKUI_Globals, SDKUI_Localizator } from '../../../helper';
9
9
  import TMSearchResult from './TMSearchResult';
10
10
  import TMRecentsManager from '../../grids/TMRecentsManager';
11
11
  import { SearchResultContext } from '../../../ts';
12
12
  import { useDeviceType, DeviceType } from '../../base/TMDeviceProvider';
13
13
  import { StyledMultiViewPanel } from '../../base/Styled';
14
- import TMPanelManager from '../../base/TMPanelManager';
14
+ import { TMPanelManagerContextProvider, useTMPanelContext } from '../../layout/panel/TMPanelContext';
15
+ import { TMPanelToolbar } from '../../layout/panel/TMPanelToolbar';
16
+ import { useResizablePanels } from '../../layout/panel/useResizablePanels';
17
+ import TMPanel from '../../base/TMPanel';
18
+ import { Gutters } from '../../../utils/theme';
15
19
  var TMSearchViews;
16
20
  (function (TMSearchViews) {
17
21
  TMSearchViews[TMSearchViews["Search"] = 0] = "Search";
@@ -118,18 +122,18 @@ const TMSearch = ({ inputTID, inputSqdID, isExpertMode = SDKUI_Globals.userSetti
118
122
  await setSqdAsync?.(sqdToBeSet);
119
123
  }, []);
120
124
  const isMobile = deviceType === DeviceType.MOBILE;
121
- const renderTMTreeSelector = (handleTogglePanel) => _jsx(TMTreeSelector, { onClosePanel: () => handleTogglePanel('TMTreeSelector'), onSelectedTIDChanged: (tid) => {
125
+ const renderTMTreeSelector = (handleTogglePanel) => _jsx(TMTreeSelector, { onClosePanel: () => handleTogglePanel?.('TMTreeSelector'), onSelectedTIDChanged: (tid) => {
122
126
  setCurrentTID(tid);
123
127
  if (tid && mruTIDs.includes(tid))
124
128
  setCurrentMruTID(tid);
125
129
  else
126
130
  setCurrentMruTID(0);
127
- isMobile && handleTogglePanel('TMSearchQueryPanel');
131
+ isMobile && handleTogglePanel?.('TMSearchQueryPanel');
128
132
  } });
129
133
  const renderTMRecentsManager = (handleTogglePanel) => _jsx(TMRecentsManager, { mruTIDs: mruTIDs, currentMruTID: currentMruTID, deviceType: deviceType, onSelectedTID: (tid) => {
130
134
  setCurrentMruTID(tid);
131
135
  setCurrentTID(tid);
132
- isMobile && handleTogglePanel('TMSearchQueryPanel');
136
+ isMobile && handleTogglePanel?.('TMSearchQueryPanel');
133
137
  }, onDeletedTID: (tid) => {
134
138
  let newMruTIDS = mruTIDs.slice();
135
139
  let index = newMruTIDS.findIndex(o => o == tid);
@@ -162,90 +166,156 @@ const TMSearch = ({ inputTID, inputSqdID, isExpertMode = SDKUI_Globals.userSetti
162
166
  } });
163
167
  const renderTMSavedQuerySelector = (handleTogglePanel) => _jsxs(TabPanel, { width: "100%", height: "100%", showNavButtons: true, repaintChangesOnly: true, selectedIndex: currentSQDMode, onSelectedIndexChange: (index) => setCurrentSQDMode(index), children: [(currentTID || currentSQD) ? _jsx(Item, { title: fromDTD?.nameLoc, children: _jsx(TMSavedQuerySelector, { allowShowSearch: false, items: filteredByTIDSQDs, selectedId: currentSQD?.id, onRefreshData: () => { loadDataSQDsAsync(true); }, onItemClick: (sqd) => {
164
168
  onSQDItemClick(sqd, setSQDAsync);
165
- isMobile && handleTogglePanel('TMSearchQueryPanel');
169
+ isMobile && handleTogglePanel?.('TMSearchQueryPanel');
166
170
  }, onDeleted: (sqd) => onSQDDeleted(sqd, sqd.id == currentSQD?.id ? filteredByTIDSQDs.find(o => o.id == 1) : currentSQD, setSQDAsync) }) }) : _jsx(_Fragment, {}), _jsx(Item, { title: SDKUI_Localizator.Alls2, children: _jsx(TMSavedQuerySelector, { allowShowSearch: true, items: allSQDs, manageDefault: false,
167
171
  // selectedId={currentSQD?.id}
168
172
  onItemClick: (sqd) => {
169
173
  onSQDItemClick(sqd, setSQDAsync);
170
- isMobile && handleTogglePanel('TMSearchQueryPanel');
174
+ isMobile && handleTogglePanel?.('TMSearchQueryPanel');
171
175
  }, onDeleted: (sqd) => onSQDDeleted(sqd, sqd.id == currentSQD?.id ? undefined : currentSQD, setSQDAsync) }) })] });
172
- const panelsConfig = [
173
- {
174
- id: 'TMTreeSelector',
175
- name: SDK_Localizator.Trees,
176
- toolbarOptions: { icon: _jsx(IconTree, { fontSize: 24 }), visible: true, isActive: true, orderNumber: 1 },
177
- type: 'content',
178
- contentOptions: {
179
- visible: true,
180
- height: '100%',
181
- width: '20%',
182
- content: renderTMTreeSelector,
183
- },
184
- },
185
- {
186
- id: 'TMRecentsManager',
187
- name: "Scorciatoie",
188
- toolbarOptions: { icon: _jsx(IconRecentlyViewed, { fontSize: 24 }), visible: true, isActive: true, orderNumber: 2 },
189
- type: 'content',
190
- contentOptions: {
191
- visible: true,
192
- height: '100%',
193
- width: '20%',
194
- content: (handleTogglePanel) => renderTMRecentsManager(handleTogglePanel),
195
- panelContainer: {
196
- title: "Scorciatoie",
197
- totalItems: mruTIDs.length,
198
- allowMaximize: !isMobile
199
- },
200
- },
201
- },
202
- {
203
- id: 'TMSearchQueryPanel',
204
- name: SDK_Localizator.QueryWhere,
205
- toolbarOptions: { icon: _jsx(IconFilter, { fontSize: 24 }), visible: true, isActive: true, orderNumber: 3 },
206
- type: 'content',
207
- contentOptions: {
208
- visible: true,
209
- height: '100%',
210
- width: '40%',
211
- content: renderTMSearchQueryPanel,
212
- },
213
- },
214
- {
215
- id: 'TMSavedQuerySelector',
216
- name: SDK_Localizator.SavedQueries,
217
- toolbarOptions: { icon: _jsx(IconSavedQuery, { fontSize: 24 }), visible: true, isActive: true, orderNumber: 4 },
218
- type: 'content',
219
- contentOptions: {
220
- visible: true,
221
- height: '100%',
222
- width: '20%',
223
- content: renderTMSavedQuerySelector,
224
- panelContainer: {
225
- title: SDK_Localizator.SavedQueries,
226
- allowMaximize: !isMobile
227
- },
228
- },
229
- },
230
- {
231
- id: 'goToResult',
232
- name: 'Vai a risultato',
233
- toolbarOptions: {
234
- icon: _jsx(IconArrowRight, { fontSize: 24 }),
235
- visible: searchResult.length > 0,
236
- isActive: searchResult.length > 0,
237
- orderNumber: 5,
238
- beginGroup: true
239
- },
240
- type: 'button',
241
- buttonOptions: {
242
- onClick: () => setCurrentSearchView(TMSearchViews.Result),
243
- },
244
- },
245
- ];
246
- return (_jsxs(_Fragment, { children: [_jsx(StyledMultiViewPanel, { "$isVisible": currentSearchView === TMSearchViews.Search, children: _jsx(TMPanelManager, { panels: panelsConfig, initialMobilePanelId: 'TMRecentsManager', toolbarMode: 1 }) }), searchResult.length > 0 &&
176
+ return (_jsxs(_Fragment, { children: [_jsx(StyledMultiViewPanel, { "$isVisible": currentSearchView === TMSearchViews.Search, children: _jsx(TMPanelManagerContextProvider, { panels: panels, initialMobilePanelId: "TMRecentsManager", children: _jsx(TMSearchPanelContent, { isMobile: isMobile, panelTMTreeSelector: renderTMTreeSelector, panelTMRecentsManager: renderTMRecentsManager, panelTMSearchQueryPanel: renderTMSearchQueryPanel(), panelTMSavedQuerySelector: renderTMSavedQuerySelector }) }) }), searchResult.length > 0 &&
247
177
  _jsx(TMSearchResult, { isVisible: currentSearchView === TMSearchViews.Result, context: SearchResultContext.METADATA_SEARCH, searchResults: searchResult, onRefreshAfterAddDcmtToFavs: onRefreshAfterAddDcmtToFavs, onRefreshSearchAsync: async () => {
248
178
  setSearchResult(await refreshLastSearch(lastQdSearched) ?? []);
249
179
  }, onTaskCreateRequest: onTaskCreateRequest, onClose: () => { setCurrentSearchView(TMSearchViews.Search); } })] }));
250
180
  };
181
+ const TMSearchPanelContent = ({ isMobile, panelTMTreeSelector, panelTMRecentsManager, panelTMSearchQueryPanel, panelTMSavedQuerySelector }) => {
182
+ const gutters = Gutters.getGutters();
183
+ console.log('TMSearchPanelContent gutters', gutters);
184
+ const { visibility, maximizedPanelId, getPanelDimensions, togglePanel, toggleMaximizePanel, setPanelDisabledById, setPanelVisibility, hasVisiblePanels } = useTMPanelContext();
185
+ const containerRef = useRef(null);
186
+ const { onMouseDown } = useResizablePanels(containerRef);
187
+ const { width: widthPanel1, height: heightPanel1 } = getPanelDimensions('TMTreeSelector');
188
+ const { width: widthPanel2, height: heightPanel2 } = getPanelDimensions('TMRecentsManager');
189
+ const { width: widthPanel3, height: heightPanel3 } = getPanelDimensions('TMSearchQueryPanel');
190
+ const { width: widthPanel4, height: heightPanel4 } = getPanelDimensions('TMSavedQuerySelector');
191
+ return (_jsxs("div", { style: { display: 'flex', height: '100%', width: '100%', flexDirection: isMobile ? 'column' : 'row', gap: gutters }, children: [_jsx("div", { style: {
192
+ display: 'flex',
193
+ flexGrow: 1,
194
+ width: `calc(100% - ${isMobile ? 0 : 70}px)`,
195
+ height: `calc(100% - ${isMobile ? 55 : 0}px)`,
196
+ flexDirection: 'row'
197
+ }, children: _jsxs("div", { style: { width: '100%', height: '100%' }, children: [_jsxs("div", { ref: containerRef, style: {
198
+ display: hasVisiblePanels() ? 'flex' : 'none',
199
+ width: '100%',
200
+ height: '100%',
201
+ }, children: [_jsx("div", { style: {
202
+ display: visibility.TMTreeSelector ? 'block' : 'none',
203
+ width: widthPanel1,
204
+ height: heightPanel1,
205
+ overflow: 'hidden',
206
+ }, children: panelTMTreeSelector(() => togglePanel('TMSearchQueryPanel')) }), visibility.TMTreeSelector && visibility.TMRecentsManager && maximizedPanelId === null && (_jsx("div", { style: {
207
+ background: 'transparent',
208
+ cursor: 'col-resize',
209
+ width: `${gutters}px`,
210
+ height: '100%',
211
+ userSelect: 'none',
212
+ }, onMouseDown: (e) => onMouseDown(e, 'TMTreeSelector', 'TMRecentsManager', true) })), _jsx("div", { style: {
213
+ display: visibility.TMRecentsManager ? 'block' : 'none',
214
+ width: widthPanel2,
215
+ height: heightPanel2,
216
+ overflow: 'hidden',
217
+ }, children: _jsx(TMPanel, { title: 'Scorciatoie', onClose: () => togglePanel('TMRecentsManager'), onMaximize: () => toggleMaximizePanel('TMRecentsManager'), onHeaderDoubleClick: () => toggleMaximizePanel('TMRecentsManager'), allowMaximize: !isMobile, children: panelTMRecentsManager(() => togglePanel('TMSearchQueryPanel')) }) }), visibility.TMRecentsManager && visibility.TMSearchQueryPanel && maximizedPanelId === null && (_jsx("div", { style: {
218
+ background: 'transparent',
219
+ cursor: 'col-resize',
220
+ width: `${gutters}px`,
221
+ height: '100%',
222
+ userSelect: 'none',
223
+ }, onMouseDown: (e) => onMouseDown(e, 'TMRecentsManager', 'TMSearchQueryPanel', true) })), _jsx("div", { style: {
224
+ display: visibility.TMSearchQueryPanel ? 'block' : 'none',
225
+ width: widthPanel3,
226
+ height: heightPanel3,
227
+ overflow: 'hidden',
228
+ }, children: panelTMSearchQueryPanel }), visibility.TMSearchQueryPanel && visibility.TMSavedQuerySelector && maximizedPanelId === null && (_jsx("div", { style: {
229
+ background: 'transparent',
230
+ cursor: 'col-resize',
231
+ width: `${gutters}px`,
232
+ height: '100%',
233
+ userSelect: 'none',
234
+ }, onMouseDown: (e) => onMouseDown(e, 'TMSearchQueryPanel', 'TMSavedQuerySelector', true) })), _jsx("div", { style: {
235
+ display: visibility.TMSavedQuerySelector ? 'block' : 'none',
236
+ width: widthPanel4,
237
+ height: heightPanel4,
238
+ overflow: 'hidden',
239
+ }, children: _jsx(TMPanel, { title: SDK_Localizator.SavedQueries, onClose: () => togglePanel('TMSavedQuerySelector'), onMaximize: () => toggleMaximizePanel('TMSavedQuerySelector'), onHeaderDoubleClick: () => toggleMaximizePanel('TMSavedQuerySelector'), allowMaximize: !isMobile, children: panelTMSavedQuerySelector(() => togglePanel('TMSearchQueryPanel')) }) })] }), _jsxs("div", { style: {
240
+ display: hasVisiblePanels() ? 'none' : 'flex',
241
+ flexDirection: 'column',
242
+ width: '100%',
243
+ height: '100%',
244
+ justifyContent: 'center',
245
+ alignItems: 'center',
246
+ fontSize: '1.5rem',
247
+ fontWeight: 'bold',
248
+ color: '#888',
249
+ backgroundColor: '#fff',
250
+ borderRadius: '10px'
251
+ }, children: [_jsx(IconInfo, { style: { fontSize: 50 } }), _jsx("div", { children: SDKUI_Localizator.NoPanelSelected })] })] }) }), _jsx("div", { style: {
252
+ display: 'flex',
253
+ flexDirection: isMobile ? 'row' : 'column',
254
+ alignItems: 'center',
255
+ width: isMobile ? '100%' : '50px',
256
+ height: isMobile ? '50px' : 'max-content',
257
+ background: 'transparent linear-gradient(90deg, #CCE0F4 0%, #7EC1E7 14%, #39A6DB 28%, #1E9CD7 35%, #0075BE 78%, #005B97 99%) 0% 0% no-repeat padding-box',
258
+ borderRadius: isMobile ? '10px' : '10px 0px 0px 10px',
259
+ padding: '10px',
260
+ gap: '10px'
261
+ }, children: _jsx(TMPanelToolbar, {}) })] }));
262
+ };
251
263
  export default TMSearch;
264
+ const panels = [
265
+ {
266
+ id: 'TMTreeSelector',
267
+ name: SDK_Localizator.Trees,
268
+ children: [],
269
+ contentOptions: {
270
+ width: '20%',
271
+ height: '100%',
272
+ },
273
+ toolbarOptions: {
274
+ icon: _jsx(IconTree, { fontSize: 24 }),
275
+ visible: true,
276
+ isActive: true
277
+ }
278
+ },
279
+ {
280
+ id: 'TMRecentsManager',
281
+ name: 'Scorciatoie',
282
+ children: [],
283
+ contentOptions: {
284
+ width: '20%',
285
+ height: '100%',
286
+ },
287
+ toolbarOptions: {
288
+ icon: _jsx(IconRecentlyViewed, { fontSize: 24 }),
289
+ visible: true,
290
+ isActive: true
291
+ }
292
+ },
293
+ {
294
+ id: 'TMSearchQueryPanel',
295
+ name: SDK_Localizator.QueryWhere,
296
+ children: [],
297
+ contentOptions: {
298
+ width: '40%',
299
+ height: '100%',
300
+ },
301
+ toolbarOptions: {
302
+ icon: _jsx(IconFilter, { fontSize: 24 }),
303
+ visible: false,
304
+ isActive: true
305
+ }
306
+ },
307
+ {
308
+ id: 'TMSavedQuerySelector',
309
+ name: SDK_Localizator.SavedQueries,
310
+ children: [],
311
+ contentOptions: {
312
+ width: '20%',
313
+ height: '100%',
314
+ },
315
+ toolbarOptions: {
316
+ icon: _jsx(IconSavedQuery, { fontSize: 24 }),
317
+ visible: true,
318
+ isActive: true
319
+ }
320
+ },
321
+ ];
@@ -30,7 +30,7 @@ import TMFloatingToolbar from '../../base/TMFloatingToolbar';
30
30
  import { WorkFlowApproveRejectPopUp, WorkFlowOperationButtons, WorkFlowReAssignPopUp } from '../workflow/TMWorkflowPopup';
31
31
  import TMMasterDetailDcmts from '../documents/TMMasterDetailDcmts';
32
32
  import TMBatchUpdateForm from '../../features/documents/TMBatchUpdateForm';
33
- import TMDcmtForm from '../documents/TMDcmtForm';
33
+ import TMDcmtForm, { ToppyHelpCenter } from '../documents/TMDcmtForm';
34
34
  import TMDcmtBlog from '../documents/TMDcmtBlog';
35
35
  import TMDcmtIcon from '../documents/TMDcmtIcon';
36
36
  import TMPanelManager from '../../base/TMPanelManager';
@@ -325,7 +325,7 @@ const TMSearchResult = ({ context = SearchResultContext.METADATA_SEARCH, isVisib
325
325
  break;
326
326
  }
327
327
  };
328
- const searchResutlToolbar = _jsxs(_Fragment, { children: [context !== SearchResultContext.METADATA_SEARCH && fromDTD?.templateTID === TemplateTIDs.WF_WIApprView && _jsx(WorkFlowOperationButtons, { deviceType: deviceType, onApprove: () => setShowApprovePopup(true), onReject: () => setShowRejectPopup(true), onReAssign: () => setShowReAssignPopup(true), approveDisable: disable, rejectDisable: disable, reassignDisable: disable, infoDisable: getSelectedDcmtsOrFocused(selectedItems, focusedItem).length !== 1 }), (dcmtsReturned != dcmtsFound) && _jsx("p", { style: { backgroundColor: `white`, color: TMColors.primaryColor, textAlign: 'center', padding: '1px 4px', borderRadius: '3px', display: 'flex' }, children: `${dcmtsReturned}/${dcmtsFound} restituiti` }), context === SearchResultContext.FAVORITES_AND_RECENTS &&
328
+ const searchResutlToolbar = _jsxs(_Fragment, { children: [(dcmtsReturned != dcmtsFound) && _jsx("p", { style: { backgroundColor: `white`, color: TMColors.primaryColor, textAlign: 'center', padding: '1px 4px', borderRadius: '3px', display: 'flex' }, children: `${dcmtsReturned}/${dcmtsFound} restituiti` }), context === SearchResultContext.FAVORITES_AND_RECENTS &&
329
329
  _jsx("div", { style: { display: 'flex', alignItems: 'center', gap: '5px' }, children: _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconDelete, { color: 'white' }), caption: "Rimuovi da " + (selectedSearchResult?.category === "Favorites" ? '"Preferiti"' : '"Recenti"'), disabled: getSelectedDcmtsOrFocused(selectedItems, focusedItem).length <= 0, onClick: removeDcmtFromFavsOrRecents }) }), _jsx(TMButton, { btnStyle: 'icon', icon: _jsx(IconRefresh, { color: 'white' }), caption: SDKUI_Localizator.Refresh, onClick: onRefreshSearchAsync }), _jsx(IconMenuVertical, { id: `commands-header-${id}`, color: 'white', cursor: 'pointer' }), _jsx(CommandsContextMenu, { target: `#commands-header-${id}`, menuItems: getCommandsMenuItems(fromDTD, selectedItems, focusedItem, context, showFloatingBar, setShowFloatingBar, openFormHandler, downloadDcmtsAsync, runOperationAsync, onRefreshSearchAsync, refreshSelectionDataRowsAsync, onRefreshAfterAddDcmtToFavs, confirmFormat, openConfirmAttachmentsDialog, openTaskFormHandler, openDetailDcmtsFormHandler, openMasterDcmtsFormHandler, openBatchUpdateFormHandler) })] });
330
330
  const middlePanelToolbar = _jsxs("div", { style: { width: 'max-content', display: 'flex', alignItems: 'center', gap: '10px' }, children: [_jsx(TMSaveFormButtonPrevious, { btnStyle: 'icon', isModified: false, iconColor: TMColors.default_background, formMode: FormModes.ReadOnly, canPrev: canNavigateHandler('prev'), onPrev: () => onNavigateHandler('prev') }), _jsx(TMSaveFormButtonNext, { btnStyle: 'icon', isModified: false, iconColor: TMColors.default_background, formMode: FormModes.ReadOnly, canNext: canNavigateHandler('next'), onNext: () => onNavigateHandler('next') })] });
331
331
  const handleAddItem = (tid, did) => {
@@ -346,7 +346,10 @@ const TMSearchResult = ({ context = SearchResultContext.METADATA_SEARCH, isVisib
346
346
  , {
347
347
  // allowMultipleSelection={allowMultipleSelection}
348
348
  inputFocusedItem: focusedItem, inputSelectedItems: selectedItems, searchResult: searchResults.length > 1 ? selectedSearchResult : searchResults[0], lastUpdateSearchTime: lastUpdateSearchTime, onDblClick: () => openFormHandler(LayoutModes.Update), onContextMenuPreparing: onContextMenuPreparing, onSelectionChanged: (items) => { setSelectedItems(items); }, onVisibleItemChanged: setVisibleItems, onFocusedItemChanged: setFocusedItem }), allowFloatingBar && showFloatingBar && deviceType !== DeviceType.MOBILE &&
349
- _jsxs(TMFloatingToolbar, { backgroundColor: TMColors.primaryColor, initialLeft: '10px', initialTop: 'calc(100% - 75px)', children: [fromDTD?.perm?.canRetrieveFile === AccessLevels.Yes && _jsx(TMButton, { btnStyle: 'icon', caption: "Download file", disabled: fromDTD?.perm?.canRetrieveFile !== AccessLevels.Yes, icon: _jsx(IconDownload, { color: 'white' }), onClick: () => { downloadDcmtsAsync(getSelectedDcmtsOrFocused(selectedItems, focusedItem), DownloadTypes.Dcmt); } }), _jsx(TMButton, { btnStyle: 'icon', caption: 'Firma e marca', icon: _jsx(IconSignature, { color: 'white' }), onClick: () => { ShowAlert({ message: "TODO Firma e marca ", mode: 'info', title: `${"TODO"}`, duration: 3000 }); } }), _jsx(IconMenuVertical, { id: `commands-floating-${id}`, color: 'white', cursor: 'pointer' }), _jsx(CommandsContextMenu, { target: `#commands-floating-${id}`, menuItems: getCommandsMenuItems(fromDTD, selectedItems, focusedItem, context, showFloatingBar, setShowFloatingBar, openFormHandler, downloadDcmtsAsync, runOperationAsync, onRefreshSearchAsync, refreshSelectionDataRowsAsync, onRefreshAfterAddDcmtToFavs, confirmFormat, openConfirmAttachmentsDialog, openTaskFormHandler, openDetailDcmtsFormHandler, openMasterDcmtsFormHandler, openBatchUpdateFormHandler) })] })] })] }), showApprovePopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onUpdate: onUpdate, selectedItems: getSelectedDcmtsOrFocused(selectedItems, focusedItem), op: 0, onClose: () => setShowApprovePopup(false) }), showRejectPopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onUpdate: onUpdate, selectedItems: getSelectedDcmtsOrFocused(selectedItems, focusedItem), op: 1, onClose: () => setShowRejectPopup(false) }), showReAssignPopup && _jsx(WorkFlowReAssignPopUp, { deviceType: deviceType, onUpdate: onUpdate, selectedItems: getSelectedDcmtsOrFocused(selectedItems, focusedItem), onClose: () => setShowReAssignPopup(false) })] }), _jsx(ConfirmFormatDialog, {}), _jsx(ConfirmAttachmentsDialog, {})] });
349
+ _jsxs(TMFloatingToolbar, { backgroundColor: TMColors.primaryColor, initialLeft: '10px', initialTop: 'calc(100% - 75px)', children: [fromDTD?.perm?.canRetrieveFile === AccessLevels.Yes && _jsx(TMButton, { btnStyle: 'icon', caption: "Download file", disabled: fromDTD?.perm?.canRetrieveFile !== AccessLevels.Yes, icon: _jsx(IconDownload, { color: 'white' }), onClick: () => { downloadDcmtsAsync(getSelectedDcmtsOrFocused(selectedItems, focusedItem), DownloadTypes.Dcmt); } }), _jsx(TMButton, { btnStyle: 'icon', caption: 'Firma e marca', icon: _jsx(IconSignature, { color: 'white' }), onClick: () => { ShowAlert({ message: "TODO Firma e marca ", mode: 'info', title: `${"TODO"}`, duration: 3000 }); } }), _jsx(IconMenuVertical, { id: `commands-floating-${id}`, color: 'white', cursor: 'pointer' }), _jsx(CommandsContextMenu, { target: `#commands-floating-${id}`, menuItems: getCommandsMenuItems(fromDTD, selectedItems, focusedItem, context, showFloatingBar, setShowFloatingBar, openFormHandler, downloadDcmtsAsync, runOperationAsync, onRefreshSearchAsync, refreshSelectionDataRowsAsync, onRefreshAfterAddDcmtToFavs, confirmFormat, openConfirmAttachmentsDialog, openTaskFormHandler, openDetailDcmtsFormHandler, openMasterDcmtsFormHandler, openBatchUpdateFormHandler) })] })] })] }), showApprovePopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onUpdate: onUpdate, selectedItems: getSelectedDcmtsOrFocused(selectedItems, focusedItem), op: 0, onClose: () => setShowApprovePopup(false) }), showRejectPopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onUpdate: onUpdate, selectedItems: getSelectedDcmtsOrFocused(selectedItems, focusedItem), op: 1, onClose: () => setShowRejectPopup(false) }), showReAssignPopup && _jsx(WorkFlowReAssignPopUp, { deviceType: deviceType, onUpdate: onUpdate, selectedItems: getSelectedDcmtsOrFocused(selectedItems, focusedItem), onClose: () => setShowReAssignPopup(false) }), (isVisible && fromDTD?.templateTID === TemplateTIDs.WF_WIApprView && !isOpenDcmtForm && !isOpenDetails && !isOpenMaster) &&
350
+ _jsx(ToppyHelpCenter, { deviceType: deviceType,
351
+ // onClick={() => isMobile ? openConfigureMode?.() : undefined}
352
+ content: _jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: '10px' }, children: _jsx(WorkFlowOperationButtons, { deviceType: deviceType, onApprove: () => setShowApprovePopup(true), onReject: () => setShowRejectPopup(true), onReAssign: () => setShowReAssignPopup(true), approveDisable: disable, rejectDisable: disable, reassignDisable: disable, infoDisable: getSelectedDcmtsOrFocused(selectedItems, focusedItem).length !== 1 }) }) })] }), _jsx(ConfirmFormatDialog, {}), _jsx(ConfirmAttachmentsDialog, {})] });
350
353
  const renderTMBlog = (handleTogglePanel) => _jsx(TMDcmtBlog, { tid: focusedItem?.TID, did: focusedItem?.DID });
351
354
  const renderTMSysMetadata = (handleTogglePanel) => _jsx(TMMetadataValues, { layoutMode: LayoutModes.Update, openChooserBySingleClick: true, TID: focusedItem?.TID, isReadOnly: true, deviceType: deviceType, metadataValues: currentMetadataValues.filter(o => (o.mid != undefined && o.mid <= 100)), metadataValuesOrig: currentMetadataValues.filter(o => (o.mid != undefined && o.mid <= 100)), validationItems: [] });
352
355
  const renderTMDcmtPreview = (handleTogglePanel) => _jsx(TMDcmtPreview, { onClose: () => {
@@ -373,7 +376,7 @@ const TMSearchResult = ({ context = SearchResultContext.METADATA_SEARCH, isVisib
373
376
  title: getTitleHeader(),
374
377
  showHeader: showToolbarHeader,
375
378
  allowMaximize: !isMobile,
376
- onBack: !isClosable ? onBack : undefined,
379
+ onBack: (!isClosable && context === SearchResultContext.METADATA_SEARCH) ? onBack : undefined,
377
380
  onClose: isClosable ? onBack : undefined,
378
381
  toolbar: searchResutlToolbar
379
382
  },
@@ -456,7 +459,7 @@ const TMSearchResult = ({ context = SearchResultContext.METADATA_SEARCH, isVisib
456
459
  },
457
460
  },
458
461
  {
459
- id: 'showMaster',
462
+ id: 'commandMaster',
460
463
  name: SDKUI_Localizator.DcmtsMaster,
461
464
  toolbarOptions: {
462
465
  icon: _jsx(IconDetailDcmts, { fontSize: 24 }),
@@ -472,7 +475,7 @@ const TMSearchResult = ({ context = SearchResultContext.METADATA_SEARCH, isVisib
472
475
  },
473
476
  },
474
477
  {
475
- id: 'showDetails',
478
+ id: 'commandDetails',
476
479
  name: SDKUI_Localizator.DcmtsDetail,
477
480
  toolbarOptions: {
478
481
  icon: _jsx(IconDetailDcmts, { transform: 'scale(-1, 1)', fontSize: 24 }),
@@ -1,7 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useMemo, useState } from "react";
3
3
  import { SDK_Globals } from '@topconsultnpm/sdk-ts-beta';
4
- import { Menu } from "devextreme-react";
5
4
  import styled from "styled-components";
6
5
  import { SDKUI_Localizator, IconApply, IconCloseOutline, IconUser, IconInfo } from "../../../helper";
7
6
  import { TMColors } from "../../../utils/theme";
@@ -16,6 +15,7 @@ const StyledWorkFlowOperationButtonsContainer = styled.div `
16
15
  align-items: center;
17
16
  gap: 15px;
18
17
  margin-left: ${props => props.$isInDcmtForm ? '0' : '50px'};
18
+ flex-direction: column;
19
19
  `;
20
20
  const StyledTextArea = styled.textarea `
21
21
  width: 100%;
@@ -41,9 +41,16 @@ export const WorkFlowOperationButtons = ({ isInDcmtForm = false, deviceType = De
41
41
  ],
42
42
  }]);
43
43
  }, []);
44
- return (deviceType === DeviceType.DESKTOP ?
45
- _jsxs(StyledWorkFlowOperationButtonsContainer, { "$isInDcmtForm": isInDcmtForm, children: [_jsx(TMButton, { btnStyle: isInDcmtForm ? 'toolbar' : 'advanced', showTooltip: isInDcmtForm, icon: _jsx(IconApply, {}), caption: SDKUI_Localizator.Approve, disabled: approveDisable, onClick: () => !approveDisable && onApprove && onApprove(), advancedColor: TMColors.success, color: 'success' }), _jsx(TMButton, { btnStyle: isInDcmtForm ? 'toolbar' : 'advanced', showTooltip: isInDcmtForm, icon: _jsx(IconCloseOutline, {}), caption: SDKUI_Localizator.Reject, disabled: rejectDisable, onClick: () => !rejectDisable && onReject && onReject(), advancedColor: TMColors.error, color: 'error' }), _jsx(TMButton, { btnStyle: isInDcmtForm ? 'toolbar' : 'advanced', showTooltip: isInDcmtForm, icon: _jsx(IconUser, { fontSize: 16 }), caption: SDKUI_Localizator.Reassign, disabled: reassignDisable, onClick: () => !reassignDisable && onReAssign && onReAssign(), advancedColor: TMColors.tertiary, color: 'tertiary' }), _jsx(TMButton, { btnStyle: isInDcmtForm ? 'toolbar' : 'advanced', showTooltip: isInDcmtForm, icon: _jsx(IconInfo, { fontSize: 16 }), caption: SDKUI_Localizator.MoreInformation, width: '180px', disabled: infoDisable, onClick: () => alert('TODO!!!'), advancedColor: TMColors.info, color: 'info' })] }) :
46
- _jsx(Menu, { elementAttr: { class: 'custom-dx-menu' }, disabled: approveDisable && reassignDisable && rejectDisable && infoDisable, dataSource: operations, displayExpr: "name" }));
44
+ return (
45
+ // deviceType === DeviceType.DESKTOP ?
46
+ _jsxs(StyledWorkFlowOperationButtonsContainer, { "$isInDcmtForm": isInDcmtForm, children: [_jsx(TMButton, { btnStyle: isInDcmtForm ? 'toolbar' : 'advanced', showTooltip: isInDcmtForm, icon: _jsx(IconApply, {}), caption: SDKUI_Localizator.Approve, disabled: approveDisable, onClick: () => !approveDisable && onApprove && onApprove(), advancedColor: TMColors.success, color: 'success' }), _jsx(TMButton, { btnStyle: isInDcmtForm ? 'toolbar' : 'advanced', showTooltip: isInDcmtForm, icon: _jsx(IconCloseOutline, {}), caption: SDKUI_Localizator.Reject, disabled: rejectDisable, onClick: () => !rejectDisable && onReject && onReject(), advancedColor: TMColors.error, color: 'error' }), _jsx(TMButton, { btnStyle: isInDcmtForm ? 'toolbar' : 'advanced', showTooltip: isInDcmtForm, icon: _jsx(IconUser, { fontSize: 16 }), caption: SDKUI_Localizator.Reassign, disabled: reassignDisable, onClick: () => !reassignDisable && onReAssign && onReAssign(), advancedColor: TMColors.tertiary, color: 'tertiary' }), _jsx(TMButton, { btnStyle: isInDcmtForm ? 'toolbar' : 'advanced', showTooltip: isInDcmtForm, icon: _jsx(IconInfo, { fontSize: 16 }), caption: SDKUI_Localizator.MoreInformation, width: '180px', disabled: infoDisable, onClick: () => alert('TODO!!!'), advancedColor: TMColors.info, color: 'info' })] })
47
+ // : <Menu
48
+ // elementAttr={{ class: 'custom-dx-menu' }}
49
+ // disabled={approveDisable && reassignDisable && rejectDisable && infoDisable}
50
+ // dataSource={operations}
51
+ // displayExpr="name"
52
+ // />
53
+ );
47
54
  };
48
55
  export const WorkFlowApproveRejectPopUp = ({ TID = 0, DID = 0, deviceType = DeviceType.DESKTOP, op, onClose, selectedItems = [], onUpdate }) => {
49
56
  const [commentValue, setCommentValue] = useState('');
@@ -81,3 +81,6 @@ export { default as TMFileManagerThumbnailItems } from "./base/TMFileManagerThum
81
81
  export { default as TMCounterContainer } from "./base/TMCounterContainer";
82
82
  export * from "./base/TMCounterContainer";
83
83
  export { default as TMAreaManager } from "./base/TMAreaManager";
84
+ export * from "./layout/panel/TMPanelContext";
85
+ export * from "./layout/panel/TMPanelToolbar";
86
+ export * from "./layout/panel/useResizablePanels";
@@ -96,3 +96,7 @@ export { default as TMFileManagerThumbnailItems } from "./base/TMFileManagerThum
96
96
  export { default as TMCounterContainer } from "./base/TMCounterContainer";
97
97
  export * from "./base/TMCounterContainer";
98
98
  export { default as TMAreaManager } from "./base/TMAreaManager";
99
+ // layout
100
+ export * from "./layout/panel/TMPanelContext";
101
+ export * from "./layout/panel/TMPanelToolbar";
102
+ export * from "./layout/panel/useResizablePanels";
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import React, { useRef, useState, Children, cloneElement, isValidElement, useEffect, useMemo, } from 'react';
3
3
  import { SDKUI_Globals } from '../../helper';
4
+ import { useDeviceType } from '../base/TMDeviceProvider';
4
5
  export const TMPanelItem = (props) => (_jsx("div", { style: {
5
6
  flexBasis: props.width || props.height || 'auto',
6
7
  minWidth: props.minWidth,
@@ -9,7 +10,7 @@ export const TMPanelItem = (props) => (_jsx("div", { style: {
9
10
  flexShrink: 0,
10
11
  height: '100%',
11
12
  width: '100%',
12
- overflow: 'auto',
13
+ // overflow: 'auto',
13
14
  position: 'relative',
14
15
  boxSizing: 'border-box',
15
16
  display: 'flex',
@@ -100,35 +101,32 @@ export const TMPanelGroup = ({ orientation = 'horizontal', allowItemResize = fal
100
101
  filteredAccHidden += renderedSizes[i];
101
102
  }
102
103
  }
103
- // --- CORRECTED MERGING LOGIC ---
104
+ // --- CORRECTED MERGING LOGIC: merge hidden into previous visible, or into the first visible if at the start ---
104
105
  // Merge hidden panel sizes into the nearest visible sibling (prefer previous, else next)
105
106
  const mergedPanels = [];
106
107
  const mergedSizes = [];
107
108
  const mergedPaths = [];
109
+ let lastVisibleIdx = -1;
108
110
  for (let i = 0; i < filteredPanels.length; i++) {
109
111
  if (filteredPanels[i] !== null && filteredPanels[i] !== undefined) {
112
+ // If there were hidden panels before the first visible, merge their sizes into this first visible
113
+ if (lastVisibleIdx === -1 && i > 0) {
114
+ let acc = 0;
115
+ for (let j = 0; j < i; j++)
116
+ acc += filteredSizes[j];
117
+ mergedSizes.push(filteredSizes[i] + acc);
118
+ }
119
+ else {
120
+ mergedSizes.push(filteredSizes[i]);
121
+ }
110
122
  mergedPanels.push(filteredPanels[i]);
111
- mergedSizes.push(filteredSizes[i]);
112
123
  mergedPaths.push(filteredPaths[i]);
124
+ lastVisibleIdx = mergedSizes.length - 1;
113
125
  }
114
126
  else {
115
- // Hidden panel: merge its size into previous visible, or next if first
116
- if (mergedPanels.length > 0) {
117
- mergedSizes[mergedSizes.length - 1] += filteredSizes[i];
118
- }
119
- else {
120
- // No previous, merge into next visible
121
- let j = i + 1;
122
- while (j < filteredPanels.length &&
123
- (filteredPanels[j] === null || filteredPanels[j] === undefined)) {
124
- j++;
125
- }
126
- if (j < filteredPanels.length) {
127
- // Next visible found
128
- if (filteredSizes[j] !== undefined) {
129
- filteredSizes[j] += filteredSizes[i];
130
- }
131
- }
127
+ // Hidden panel: merge its size into the last visible panel (if any)
128
+ if (lastVisibleIdx >= 0) {
129
+ mergedSizes[lastVisibleIdx] += filteredSizes[i];
132
130
  }
133
131
  }
134
132
  }
@@ -268,6 +266,8 @@ const TMPanelLayout = ({ children, showToolbar = true, emptyContent, }) => {
268
266
  };
269
267
  // For nested: you can extend this to track nested visibility state if needed
270
268
  const allHidden = isAllPanelsHidden();
269
+ const deviceType = useDeviceType();
270
+ const isMobile = useMemo(() => deviceType === 'mobile', [deviceType]);
271
271
  return (_jsx("div", { style: {
272
272
  width: '100%',
273
273
  height: '100%',
@@ -275,23 +275,21 @@ const TMPanelLayout = ({ children, showToolbar = true, emptyContent, }) => {
275
275
  overflow: 'hidden',
276
276
  display: 'flex',
277
277
  flexDirection: 'column',
278
- }, children: _jsxs("div", { style: { width: '100%', height: '100%', position: 'relative' }, children: [!allHidden &&
278
+ }, children: _jsxs("div", { style: { display: 'flex', flexDirection: isMobile ? 'column' : 'row', height: '100%', width: '100%', gap: !isMobile ? SDKUI_Globals.userSettings.themeSettings.gutters : 0 }, children: [!allHidden &&
279
279
  cloneElement(group, {
280
280
  panelVisibility,
281
281
  onTogglePanel: handleTogglePanel,
282
282
  panelLabels: allPanels.map(p => p.label),
283
283
  }), showToolbar && (_jsx("div", { style: {
284
- position: 'absolute',
285
- top: 10,
286
- right: 10,
287
- zIndex: 1000,
288
- background: 'rgba(255,255,255,0.9)',
289
- borderRadius: 8,
290
- boxShadow: '0 2px 8px #0002',
291
- padding: 8,
292
284
  display: 'flex',
293
- flexDirection: 'column',
294
- gap: 8,
285
+ flexDirection: isMobile ? 'row' : 'column',
286
+ alignItems: 'center',
287
+ width: isMobile ? '100%' : '50px',
288
+ height: isMobile ? '50px' : 'max-content',
289
+ background: 'transparent linear-gradient(90deg, #CCE0F4 0%, #7EC1E7 14%, #39A6DB 28%, #1E9CD7 35%, #0075BE 78%, #005B97 99%) 0% 0% no-repeat padding-box',
290
+ borderRadius: isMobile ? '10px' : '10px 0px 0px 10px',
291
+ padding: '10px',
292
+ gap: '10px'
295
293
  }, children: _jsx(TMPanelLayoutToolbar, { panelLabels: allPanels.map(p => p.label), panelVisibility: panelVisibility, onTogglePanel: handleTogglePanel }) })), allHidden && (_jsx("div", { style: {
296
294
  position: 'absolute',
297
295
  left: 0,
@@ -0,0 +1,45 @@
1
+ import { ReactNode } from 'react';
2
+ export interface TMPanelManagerItemContext {
3
+ id: string;
4
+ name: string;
5
+ contentOptions: {
6
+ width: string;
7
+ height: string;
8
+ };
9
+ toolbarOptions: {
10
+ icon: string | JSX.Element;
11
+ visible: boolean;
12
+ isActive: boolean;
13
+ disabled?: boolean;
14
+ orderNumber?: number;
15
+ beginGroup?: boolean;
16
+ alwaysActiveColor?: boolean;
17
+ };
18
+ children: Array<TMPanelManagerItemContext>;
19
+ }
20
+ interface ITMPanelManagerContext {
21
+ panelTree: Array<TMPanelManagerItemContext>;
22
+ visibility: Record<string, boolean>;
23
+ calculateEffectiveVisibility: Record<string, boolean>;
24
+ setPanelVisibility: (id: string, visible: boolean) => void;
25
+ togglePanel: (id: string) => void;
26
+ findPanelById: (id: string) => TMPanelManagerItemContext | undefined;
27
+ getPanelDimensions: (id: string) => {
28
+ width: string;
29
+ height: string;
30
+ };
31
+ toggleMaximizePanel: (id: string) => void;
32
+ maximizedPanelId: string | null;
33
+ updatePanelSize: (id: string, width: string | number, height: string | number) => void;
34
+ setPanelVisibleById: (id: string, visible: boolean) => void;
35
+ setPanelDisabledById: (id: string, disabled: boolean) => void;
36
+ hasVisiblePanels: () => boolean;
37
+ }
38
+ export declare function useTMPanelContext(): ITMPanelManagerContext;
39
+ interface TMPanelContextProviderProps {
40
+ panels: Array<TMPanelManagerItemContext>;
41
+ initialMobilePanelId: string;
42
+ children: ReactNode;
43
+ }
44
+ export declare const TMPanelManagerContextProvider: (props: TMPanelContextProviderProps) => import("react/jsx-runtime").JSX.Element;
45
+ export {};
@@ -0,0 +1,314 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useMemo, useState, useEffect, } from 'react';
3
+ import { DeviceType, useDeviceType } from '../../base/TMDeviceProvider';
4
+ // Creazione del context
5
+ const TMPanelManagerContext = createContext(undefined);
6
+ // Hook custom per accedere al context
7
+ export function useTMPanelContext() {
8
+ const context = useContext(TMPanelManagerContext);
9
+ if (!context) {
10
+ throw new Error('useTMPanelContext must be used within a TMPanelContextProvider');
11
+ }
12
+ return context;
13
+ }
14
+ // Provider del context
15
+ export const TMPanelManagerContextProvider = (props) => {
16
+ const { panels, initialMobilePanelId, children } = props;
17
+ const [panelTree, setPanelTree] = useState(panels);
18
+ const [maximizedPanelId, setMaximizedPanelId] = useState(null);
19
+ const deviceType = useDeviceType();
20
+ let isMobile = useMemo(() => { return deviceType === DeviceType.MOBILE; }, [deviceType]);
21
+ useEffect(() => {
22
+ if (isMobile) {
23
+ setVisibility(prev => updatePanelVisibility(initialMobilePanelId, true, prev));
24
+ }
25
+ }, [isMobile]);
26
+ // Stato iniziale per dimensioni pannelli
27
+ const [panelSizes, setPanelSizes] = useState(() => {
28
+ const sizes = {};
29
+ const flattenPanels = (panels) => panels.reduce((acc, p) => [...acc, p, ...flattenPanels(p.children)], []);
30
+ const allPanels = flattenPanels(panelTree);
31
+ allPanels.forEach(panel => {
32
+ sizes[panel.id] = { width: panel.contentOptions.width, height: panel.contentOptions.height };
33
+ });
34
+ return sizes;
35
+ });
36
+ // Trova un pannello tramite ID
37
+ const findPanelById = (id) => {
38
+ const findRecursive = (panels) => {
39
+ for (const panel of panels) {
40
+ if (panel.id === id)
41
+ return panel;
42
+ const found = findRecursive(panel.children);
43
+ if (found)
44
+ return found;
45
+ }
46
+ return undefined;
47
+ };
48
+ return findRecursive(panelTree);
49
+ };
50
+ // Mappa figlio -> genitori
51
+ const parentMap = useMemo(() => {
52
+ const map = new Map();
53
+ const buildMap = (panels, parents = []) => {
54
+ for (const panel of panels) {
55
+ map.set(panel.id, [...parents]);
56
+ buildMap(panel.children, [...parents, panel.id]);
57
+ }
58
+ };
59
+ buildMap(panelTree);
60
+ return map;
61
+ }, [panelTree]);
62
+ // Mappa genitore -> figli
63
+ const parentToChildrenMap = useMemo(() => {
64
+ const map = new Map();
65
+ const buildMap = (panels) => {
66
+ for (const panel of panels) {
67
+ map.set(panel.id, panel.children.map(c => c.id));
68
+ buildMap(panel.children);
69
+ }
70
+ };
71
+ buildMap(panelTree);
72
+ return map;
73
+ }, [panelTree]);
74
+ // Stato visibilità iniziale
75
+ const getInitialVisibility = (panels) => {
76
+ const vis = {};
77
+ const collect = (panels) => {
78
+ for (const panel of panels) {
79
+ vis[panel.id] = panel.toolbarOptions?.isActive ?? false;
80
+ collect(panel.children);
81
+ }
82
+ };
83
+ collect(panels);
84
+ return vis;
85
+ };
86
+ const [visibility, setVisibility] = useState(() => getInitialVisibility(panelTree));
87
+ const getParentsOfPanel = (id) => parentMap.get(id) || [];
88
+ // Visibilità effettiva tenendo conto della gerarchia
89
+ const calculateEffectiveVisibility = useMemo(() => {
90
+ if (maximizedPanelId) {
91
+ return { ...visibility };
92
+ }
93
+ const updatedVisibility = { ...visibility };
94
+ const propagateToParents = (id) => {
95
+ for (const parent of parentMap.get(id) || []) {
96
+ if (!updatedVisibility[parent]) {
97
+ updatedVisibility[parent] = true;
98
+ propagateToParents(parent);
99
+ }
100
+ }
101
+ };
102
+ Object.entries(updatedVisibility).forEach(([id, isVisible]) => {
103
+ if (isVisible)
104
+ propagateToParents(id);
105
+ });
106
+ const deactivateIfNoVisibleChildren = (parentId) => {
107
+ const children = parentToChildrenMap.get(parentId) || [];
108
+ if (children.length === 0)
109
+ return;
110
+ const anyVisible = children.some(id => updatedVisibility[id]);
111
+ if (!anyVisible && updatedVisibility[parentId]) {
112
+ updatedVisibility[parentId] = false;
113
+ for (const grand of parentMap.get(parentId) || []) {
114
+ deactivateIfNoVisibleChildren(grand);
115
+ }
116
+ }
117
+ };
118
+ for (const parentId of parentToChildrenMap.keys()) {
119
+ deactivateIfNoVisibleChildren(parentId);
120
+ }
121
+ return updatedVisibility;
122
+ }, [visibility, parentMap, parentToChildrenMap, maximizedPanelId]);
123
+ // Calcolo delle dimensioni dinamiche in base alla visibilità
124
+ const dynamicSizesMap = useMemo(() => {
125
+ const flattenPanels = (panels) => panels.reduce((acc, p) => [...acc, p, ...flattenPanels(p.children)], []);
126
+ const allPanels = flattenPanels(panelTree);
127
+ const originalHeights = new Map();
128
+ const originalWidths = new Map();
129
+ allPanels.forEach(panel => {
130
+ originalHeights.set(panel.id, parseFloat(panel.contentOptions.height) || 0);
131
+ originalWidths.set(panel.id, parseFloat(panel.contentOptions.width) || 0);
132
+ });
133
+ if (maximizedPanelId) {
134
+ const parents = getParentsOfPanel(maximizedPanelId);
135
+ const allowed = new Set([maximizedPanelId, ...parents]);
136
+ const sizesMap = {};
137
+ allPanels.forEach(panel => {
138
+ sizesMap[panel.id] = allowed.has(panel.id)
139
+ ? { width: '100%', height: '100%' }
140
+ : { width: '0%', height: '0%' };
141
+ });
142
+ return sizesMap;
143
+ }
144
+ const calcSiblingSizes = (siblings, originalSizes) => {
145
+ const visibleSiblings = siblings.filter(s => calculateEffectiveVisibility[s.id]);
146
+ const totalVisible = visibleSiblings.reduce((sum, s) => sum + (originalSizes.get(s.id) || 0), 0);
147
+ const totalAll = siblings.reduce((sum, s) => sum + (originalSizes.get(s.id) || 0), 0);
148
+ const map = {};
149
+ visibleSiblings.forEach(s => {
150
+ const orig = originalSizes.get(s.id) || 0;
151
+ map[s.id] = totalVisible === 0 ? 0 : (orig / totalVisible) * totalAll;
152
+ });
153
+ siblings.forEach(s => {
154
+ if (!calculateEffectiveVisibility[s.id])
155
+ map[s.id] = 0;
156
+ });
157
+ return map;
158
+ };
159
+ const widthSizesMap = {};
160
+ const heightSizesMap = {};
161
+ Object.assign(widthSizesMap, calcSiblingSizes(panelTree, originalWidths));
162
+ Object.assign(heightSizesMap, calcSiblingSizes(panelTree, originalHeights));
163
+ const processChildrenSizes = (panels) => {
164
+ panels.forEach(panel => {
165
+ if (panel.children.length > 0) {
166
+ Object.assign(widthSizesMap, calcSiblingSizes(panel.children, originalWidths));
167
+ Object.assign(heightSizesMap, calcSiblingSizes(panel.children, originalHeights));
168
+ processChildrenSizes(panel.children);
169
+ }
170
+ });
171
+ };
172
+ processChildrenSizes(panelTree);
173
+ const sizesMap = {};
174
+ allPanels.forEach(panel => {
175
+ const width = Math.min(widthSizesMap[panel.id] ?? 0, 100);
176
+ const height = Math.min(heightSizesMap[panel.id] ?? 0, 100);
177
+ sizesMap[panel.id] = {
178
+ width: calculateEffectiveVisibility[panel.id] ? `${width.toFixed(2)}%` : '0%',
179
+ height: calculateEffectiveVisibility[panel.id] ? `${height.toFixed(2)}%` : '0%',
180
+ };
181
+ });
182
+ return sizesMap;
183
+ }, [calculateEffectiveVisibility, panelTree, maximizedPanelId]);
184
+ // Ottieni dimensioni di un pannello (override -> dinamico -> default)
185
+ const getPanelDimensions = (id) => {
186
+ if (panelSizes[id])
187
+ return panelSizes[id];
188
+ if (dynamicSizesMap[id])
189
+ return dynamicSizesMap[id];
190
+ const panel = findPanelById(id);
191
+ return panel ? { width: panel.contentOptions.width, height: panel.contentOptions.height } : { width: 'auto', height: 'auto' };
192
+ };
193
+ // Imposta manualmente le dimensioni di un pannello
194
+ const updatePanelSize = (id, width, height) => {
195
+ setPanelSizes(prev => ({
196
+ ...prev,
197
+ [id]: {
198
+ width: typeof width === 'number' ? `${width}%` : width,
199
+ height: typeof height === 'number' ? `${height}%` : height,
200
+ },
201
+ }));
202
+ };
203
+ // Quando cambia visibilità o massimizzazione, resetta override
204
+ useEffect(() => {
205
+ setPanelSizes({});
206
+ }, [visibility, maximizedPanelId]);
207
+ // Massimizza o ripristina un pannello
208
+ const toggleMaximizePanel = (id) => {
209
+ setMaximizedPanelId(prev => (prev === id ? null : id));
210
+ };
211
+ const updatePanelVisibility = (id, visible, currentVisibility) => {
212
+ let next = { ...currentVisibility };
213
+ if (!visible && maximizedPanelId === id) {
214
+ setMaximizedPanelId(null);
215
+ }
216
+ // Se siamo su mobile, resettiamo tutto tranne il pannello selezionato e i suoi parent
217
+ if (isMobile && visible) {
218
+ const parents = parentMap.get(id) || [];
219
+ // Imposta tutti i pannelli come invisibili tranne il selezionato e i suoi parent
220
+ Object.keys(next).forEach(panelId => {
221
+ next[panelId] = (panelId === id || parents.includes(panelId));
222
+ });
223
+ // Applichiamo propagazione verso l’alto (attivazione dei genitori)
224
+ const activateParents = (childId) => {
225
+ for (const parent of parentMap.get(childId) || []) {
226
+ if (!next[parent]) {
227
+ next[parent] = true;
228
+ activateParents(parent);
229
+ }
230
+ }
231
+ };
232
+ activateParents(id);
233
+ return next;
234
+ }
235
+ // Normal behavior (desktop)
236
+ next[id] = visible;
237
+ if (visible) {
238
+ const activateParents = (childId) => {
239
+ for (const parent of parentMap.get(childId) || []) {
240
+ if (!next[parent]) {
241
+ next[parent] = true;
242
+ activateParents(parent);
243
+ }
244
+ }
245
+ };
246
+ activateParents(id);
247
+ }
248
+ else {
249
+ const deactivateParents = (childId) => {
250
+ for (const parent of parentMap.get(childId) || []) {
251
+ const children = parentToChildrenMap.get(parent) || [];
252
+ const anyVisible = children.some(cId => next[cId]);
253
+ if (!anyVisible && next[parent]) {
254
+ next[parent] = false;
255
+ deactivateParents(parent);
256
+ }
257
+ }
258
+ };
259
+ deactivateParents(id);
260
+ }
261
+ return next;
262
+ };
263
+ // Attiva/disattiva visibilità di un pannello
264
+ const togglePanel = (id) => {
265
+ setVisibility(prev => updatePanelVisibility(id, !prev[id], prev));
266
+ };
267
+ // Imposta visibilità esplicita di un pannello
268
+ const setPanelVisibility = (id, visible) => {
269
+ setVisibility(prev => updatePanelVisibility(id, visible, prev));
270
+ };
271
+ // Cambia la visibilità direttamente nel pannello (opzionale, ma richiesto da te)
272
+ const setPanelVisibleById = (id, visible) => {
273
+ setPanelTree(prevTree => {
274
+ const update = (panels) => panels.map(panel => {
275
+ if (panel.id === id) {
276
+ return { ...panel, toolbarOptions: { ...panel.toolbarOptions, visible } };
277
+ }
278
+ return { ...panel, children: update(panel.children) };
279
+ });
280
+ return update(prevTree);
281
+ });
282
+ };
283
+ // Cambia il valore di disabled direttamente nel pannello
284
+ const setPanelDisabledById = (id, disabled) => {
285
+ setPanelTree(prevTree => {
286
+ const update = (panels) => panels.map(panel => {
287
+ if (panel.id === id) {
288
+ return { ...panel, toolbarOptions: { ...panel.toolbarOptions, disabled, } };
289
+ }
290
+ return { ...panel, children: update(panel.children) };
291
+ });
292
+ return update(prevTree);
293
+ });
294
+ };
295
+ const hasVisiblePanels = () => {
296
+ return Object.values(calculateEffectiveVisibility).some(visible => visible);
297
+ };
298
+ // Valori esposti dal context
299
+ return (_jsx(TMPanelManagerContext.Provider, { value: {
300
+ panelTree,
301
+ visibility,
302
+ calculateEffectiveVisibility,
303
+ setPanelVisibility,
304
+ togglePanel,
305
+ findPanelById,
306
+ getPanelDimensions,
307
+ toggleMaximizePanel,
308
+ maximizedPanelId,
309
+ updatePanelSize,
310
+ setPanelVisibleById,
311
+ setPanelDisabledById,
312
+ hasVisiblePanels
313
+ }, children: children }));
314
+ };
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ export declare const TMPanelToolbar: () => import("react/jsx-runtime").JSX.Element;
3
+ export declare const StyledToolbarButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, {
4
+ $isActive?: boolean;
5
+ $isDisabled?: boolean;
6
+ }>> & string;
@@ -0,0 +1,66 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useMemo } from 'react';
3
+ import { useTMPanelContext } from './TMPanelContext';
4
+ import styled from 'styled-components';
5
+ import { DeviceType, useDeviceType } from '../../base/TMDeviceProvider';
6
+ import TMTooltip from '../../base/TMTooltip';
7
+ export const TMPanelToolbar = () => {
8
+ const { panelTree, togglePanel, calculateEffectiveVisibility } = useTMPanelContext();
9
+ const deviceType = useDeviceType();
10
+ let isMobile = useMemo(() => { return deviceType === DeviceType.MOBILE; }, [deviceType]);
11
+ // Ricorsivamente trova tutti i pannelli parent (hanno figli)
12
+ const getParentIds = (panels, parents = new Set()) => {
13
+ for (const panel of panels) {
14
+ if (panel.children.length > 0) {
15
+ parents.add(panel.id);
16
+ getParentIds(panel.children, parents);
17
+ }
18
+ }
19
+ return parents;
20
+ };
21
+ // Ricorsivamente trova tutti i pannelli foglia (senza figli)
22
+ const getLeafPanels = (panels, leaves = []) => {
23
+ for (const panel of panels) {
24
+ if (panel.children.length === 0) {
25
+ leaves.push(panel);
26
+ }
27
+ else {
28
+ getLeafPanels(panel.children, leaves);
29
+ }
30
+ }
31
+ return leaves;
32
+ };
33
+ const parentIds = getParentIds(panelTree);
34
+ const leafPanels = getLeafPanels(panelTree);
35
+ return (_jsx("div", { style: {
36
+ display: 'flex',
37
+ flexDirection: isMobile ? 'row' : 'column',
38
+ gap: '6px',
39
+ alignItems: 'center',
40
+ justifyContent: isMobile ? 'center' : 'flex-start',
41
+ width: '100%',
42
+ height: '100%'
43
+ }, children: leafPanels.filter(panel => panel.toolbarOptions.visible).map((item) => {
44
+ const isActive = calculateEffectiveVisibility[item.id];
45
+ return _jsx(TMTooltip, { content: item.name, position: isMobile ? 'top' : 'left', children: _jsx(StyledToolbarButton, { "$isActive": isActive || item.toolbarOptions?.alwaysActiveColor, "$isDisabled": item.toolbarOptions?.disabled, disabled: item.toolbarOptions?.disabled, onClick: () => { togglePanel(item.id); }, children: typeof item.toolbarOptions?.icon === 'string' ? (_jsx("i", { className: `dx-icon dx-icon-${item.toolbarOptions?.icon}` })) : (item.toolbarOptions?.icon) }) }, item.id);
46
+ }) }));
47
+ };
48
+ export const StyledToolbarButton = styled.button `
49
+ display: flex;
50
+ align-items: center;
51
+ justify-content: center;
52
+ height: 32px;
53
+ width: 32px;
54
+ border: none;
55
+ border-radius: 8px;
56
+ font-size: 18px;
57
+ padding: 0px;
58
+ color: #fff;
59
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
60
+ cursor: ${({ $isDisabled }) => ($isDisabled ? 'not-allowed' : 'pointer')};
61
+ opacity: ${({ $isDisabled }) => ($isDisabled ? 0.6 : 1)};
62
+ background: ${({ $isActive }) => $isActive ? 'rgba(255,255,255,0.35)' : 'transparent'};
63
+ &:hover {
64
+ background: ${({ $isDisabled }) => !$isDisabled ? 'rgba(255,255,255,0.35)' : undefined};
65
+ }
66
+ `;
@@ -0,0 +1,3 @@
1
+ export declare function useResizablePanels(containerRef: React.RefObject<HTMLDivElement | null>): {
2
+ onMouseDown: (e: React.MouseEvent, panelBeforeId: string, panelAfterId: string, isRow: boolean) => void;
3
+ };
@@ -0,0 +1,67 @@
1
+ import { useRef, useCallback } from 'react';
2
+ import { useTMPanelContext } from './TMPanelContext';
3
+ export function useResizablePanels(containerRef) {
4
+ const { getPanelDimensions, updatePanelSize } = useTMPanelContext();
5
+ const resizingRef = useRef(null);
6
+ const getSizePercent = useCallback((panelId, isRow) => {
7
+ const dim = getPanelDimensions(panelId);
8
+ return isRow
9
+ ? parseFloat(dim.width.replace('%', ''))
10
+ : parseFloat(dim.height.replace('%', ''));
11
+ }, [getPanelDimensions]);
12
+ const getContainerSize = useCallback((isRow) => {
13
+ if (!containerRef.current)
14
+ return 0;
15
+ return isRow ? containerRef.current.clientWidth : containerRef.current.clientHeight;
16
+ }, [containerRef]);
17
+ const updateSize = useCallback((panelId, sizePercent, otherDimension, isRow) => {
18
+ if (isRow) {
19
+ updatePanelSize(panelId, `${sizePercent.toFixed(2)}%`, otherDimension);
20
+ }
21
+ else {
22
+ updatePanelSize(panelId, otherDimension, `${sizePercent.toFixed(2)}%`);
23
+ }
24
+ }, [updatePanelSize]);
25
+ const onMouseMove = useCallback((e) => {
26
+ const data = resizingRef.current;
27
+ if (!data || !containerRef.current)
28
+ return;
29
+ const { panelBeforeId, panelAfterId, startPos, startSizeBefore, startSizeAfter, isRow } = data;
30
+ const containerSize = getContainerSize(isRow);
31
+ const currentPos = isRow ? e.clientX : e.clientY;
32
+ const delta = currentPos - startPos;
33
+ const sizeBeforePx = (startSizeBefore / 100) * containerSize + delta;
34
+ const sizeAfterPx = (startSizeAfter / 100) * containerSize - delta;
35
+ if (sizeBeforePx < 50 || sizeAfterPx < 50)
36
+ return;
37
+ const newSizeBefore = (sizeBeforePx / containerSize) * 100;
38
+ const newSizeAfter = (sizeAfterPx / containerSize) * 100;
39
+ const dimBefore = getPanelDimensions(panelBeforeId);
40
+ const dimAfter = getPanelDimensions(panelAfterId);
41
+ const otherDimBefore = isRow ? dimBefore.height : dimBefore.width;
42
+ const otherDimAfter = isRow ? dimAfter.height : dimAfter.width;
43
+ updateSize(panelBeforeId, newSizeBefore, otherDimBefore, isRow);
44
+ updateSize(panelAfterId, newSizeAfter, otherDimAfter, isRow);
45
+ }, [getContainerSize, getPanelDimensions, updateSize, containerRef]);
46
+ const onMouseUp = useCallback(() => {
47
+ resizingRef.current = null;
48
+ window.removeEventListener('mousemove', onMouseMove);
49
+ window.removeEventListener('mouseup', onMouseUp);
50
+ }, [onMouseMove]);
51
+ const onMouseDown = useCallback((e, panelBeforeId, panelAfterId, isRow) => {
52
+ e.preventDefault();
53
+ if (!containerRef.current)
54
+ return;
55
+ resizingRef.current = {
56
+ panelBeforeId,
57
+ panelAfterId,
58
+ isRow,
59
+ startPos: isRow ? e.clientX : e.clientY,
60
+ startSizeBefore: getSizePercent(panelBeforeId, isRow),
61
+ startSizeAfter: getSizePercent(panelAfterId, isRow),
62
+ };
63
+ window.addEventListener('mousemove', onMouseMove);
64
+ window.addEventListener('mouseup', onMouseUp);
65
+ }, [getSizePercent, onMouseMove, onMouseUp, containerRef]);
66
+ return { onMouseDown };
67
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react-beta",
3
- "version": "6.13.42",
3
+ "version": "6.13.44",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -42,7 +42,7 @@
42
42
  "lib"
43
43
  ],
44
44
  "dependencies": {
45
- "@topconsultnpm/sdk-ts-beta": "6.13.7",
45
+ "@topconsultnpm/sdk-ts-beta": "6.13.8",
46
46
  "buffer": "^6.0.3",
47
47
  "devextreme": "24.2.6",
48
48
  "devextreme-react": "24.2.6",