@topconsultnpm/sdkui-react 6.19.0-dev1.49 → 6.19.0-dev1.50

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.
@@ -7,6 +7,7 @@ export declare const StyledMultiViewPanel: import("styled-components/dist/types"
7
7
  }>> & string;
8
8
  export declare const StyledParagraph: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, never>> & string;
9
9
  export declare const StyledToolbarForm: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>> & string;
10
+ export declare const StyledReferenceButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>> & string;
10
11
  export declare const StyledPanelPage: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components/dist/types").Substitute<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {
11
12
  $isOpen?: boolean;
12
13
  $padding?: string;
@@ -36,6 +36,46 @@ export const StyledToolbarForm = styled.div `
36
36
  gap: 2px;
37
37
  background-color: ${TMColors.toolbar_background};
38
38
  `;
39
+ export const StyledReferenceButton = styled.button `
40
+ display: flex;
41
+ flex-direction: column;
42
+ align-items: center;
43
+ justify-content: center;
44
+ padding: 10px 16px;
45
+ border-radius: 20px;
46
+ border: none;
47
+ background-color: ${TMColors.button_floating_background};
48
+ color: white;
49
+ font-size: 0.9rem;
50
+ font-weight: 500;
51
+ cursor: pointer;
52
+ transition: all 0.2s ease;
53
+ text-align: center;
54
+ max-width: 200px;
55
+ gap: 2px;
56
+
57
+ &:hover {
58
+ opacity: 0.9;
59
+ transform: translateY(-1px);
60
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
61
+ }
62
+
63
+ &:active {
64
+ transform: translateY(0);
65
+ }
66
+
67
+ &:disabled {
68
+ opacity: 0.5;
69
+ cursor: not-allowed;
70
+ }
71
+
72
+ span {
73
+ width: 100%;
74
+ white-space: nowrap;
75
+ overflow: hidden;
76
+ text-overflow: ellipsis;
77
+ }
78
+ `;
39
79
  export const StyledPanelPage = styled.div `
40
80
  position: absolute;
41
81
  width: calc(100% - 50px);
@@ -402,7 +402,6 @@ const TMMetadataValues = ({ showCheckBoxes = ShowCheckBoxesMode.Never, checkPerm
402
402
  return (_jsx("div", { style: { width: '100%' }, children: dsAttachsData.length > 0 && _jsx(TMAccordion, { title: SDKUI_Localizator.Attachment, children: dsAttachsData.map(item => renderMetadataItem(item, isReadOnly)) }) }));
403
403
  }, [metadataValues, showCheckBoxes, showNullValueCheckBoxes, isReadOnly, dynDataListsToBeRefreshed, validationItems, selectedMID, isOpenDistinctValues, openChooserBySingleClick, metadataValuesOrig]);
404
404
  const layoutCustom = useMemo(() => {
405
- console.log('Rendering custom layout with layout:', layout);
406
405
  if (!layout || !layout.items || layout.items.length === 0) {
407
406
  return metadataValues.map((item) => renderMetadataItem(item));
408
407
  }
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
- import { LayoutModes, SearchResultDescriptor, TaskDescriptor } from '@topconsultnpm/sdk-ts';
3
- import { DcmtInfo, FormModes, TaskContext } from '../../../ts';
2
+ import { LayoutModes, ObjectRef, SearchResultDescriptor, TaskDescriptor, ValidationItem } from '@topconsultnpm/sdk-ts';
3
+ import { DcmtInfo, FormModes, MetadataValueDescriptorEx, TaskContext } from '../../../ts';
4
4
  interface ITMDcmtFormProps {
5
5
  TID?: number;
6
6
  DID?: number;
@@ -49,6 +49,9 @@ interface ITMDcmtFormProps {
49
49
  isSharedDcmt?: boolean;
50
50
  sharedSourceTID?: number;
51
51
  sharedSourceDID?: number;
52
+ allowButtonsRefs?: boolean;
53
+ onReferenceClick?: (ref: ObjectRef) => void;
52
54
  }
53
55
  declare const TMDcmtForm: React.FC<ITMDcmtFormProps>;
54
56
  export default TMDcmtForm;
57
+ export declare const validateMetadataList: (mvdList?: MetadataValueDescriptorEx[]) => ValidationItem[];
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
+ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
3
  import TMDcmtPreview from './TMDcmtPreview';
4
- import { AccessLevels, ArchiveConstraints, ArchiveEngineByID, DcmtTypeListCacheService, LayoutCacheService, LayoutModes, MetadataDataTypes, ResultTypes, SDK_Globals, SDK_Localizator, SystemMIDsAsNumber, SystemTIDs, Task_States, TemplateTIDs, TID_DID, UpdateEngineByID, ValidationItem, WorkflowCacheService, WorkItemMetadataNames } from '@topconsultnpm/sdk-ts';
4
+ import { AccessLevels, ArchiveConstraints, ArchiveEngineByID, DcmtTypeListCacheService, LayoutCacheService, LayoutModes, MetadataDataTypes, ObjectClasses, ResultTypes, SDK_Globals, SDK_Localizator, SystemMIDsAsNumber, SystemTIDs, Task_States, TemplateTIDs, TID_DID, UpdateEngineByID, ValidationItem, WorkflowCacheService, WorkItemMetadataNames } from '@topconsultnpm/sdk-ts';
5
5
  import { ContextMenu } from 'devextreme-react';
6
6
  import { WorkFlowApproveRejectPopUp, WorkFlowMoreInfoPopUp, WorkFlowOperationButtons, WorkFlowReAssignPopUp } from '../workflow/TMWorkflowPopup';
7
7
  import { DownloadTypes, FormModes } from '../../../ts';
@@ -11,7 +11,7 @@ import { getWorkItemSetIDAsync, handleArchiveVisibility, searchResultToMetadataV
11
11
  import { genUniqueId, IconShow, SDKUI_Localizator, updateMruTids, IconBoard, IconDcmtTypeSys, IconDetailDcmts, svgToString, IconDownload, calcIsModified, IconMenuVertical, Globalization, getListMaxItems, getSystemMetadata, IconBoxArchiveIn, IconClear, IconUndo, SDKUI_Globals, IconPreview, isTaskMoreInfo, IconWorkflow, IconSearch, deepCompare, IconCheck } from '../../../helper';
12
12
  import { hasDetailRelations, hasMasterRelations, isXMLFileExt } from '../../../helper/dcmtsHelper';
13
13
  import { Gutters, TMColors } from '../../../utils/theme';
14
- import { StyledFormButtonsContainer, StyledLoadingContainer, StyledModalContainer, StyledSpinner, StyledToolbarCardContainer } from '../../base/Styled';
14
+ import { StyledFormButtonsContainer, StyledLoadingContainer, StyledModalContainer, StyledReferenceButton, StyledSpinner, StyledToolbarCardContainer } from '../../base/Styled';
15
15
  import ShowAlert from '../../base/TMAlert';
16
16
  import TMButton from '../../base/TMButton';
17
17
  import { TMExceptionBoxManager, TMMessageBoxManager, ButtonNames } from '../../base/TMPopUp';
@@ -37,7 +37,7 @@ import WFDiagram from '../workflow/diagram/WFDiagram';
37
37
  import TMTooltip from '../../base/TMTooltip';
38
38
  let abortControllerLocal = new AbortController();
39
39
  //#endregion
40
- const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes.Update, showBackButton = true, onClose, onSavedAsyncCallback, TID, DID, formMode = FormModes.Update, canNext, canPrev, count, itemIndex, onNext, onPrev, allowNavigation = true, allowRelations = true, isClosable = false, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, showDcmtFormSidebar = true, invokedByTodo = false, titleModal, isModal = false, widthModal = "100%", heightModal = "100%", groupId, onWFOperationCompleted, onTaskCompleted, inputFile = null, taskFormDialogComponent, taskMoreInfo, connectorFileSave = undefined, inputMids = [], onOpenS4TViewerRequest, s4TViewerDialogComponent, enableDragDropOverlay = false, passToSearch, isSharedDcmt = false, sharedSourceTID, sharedSourceDID }) => {
40
+ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes.Update, showBackButton = true, onClose, onSavedAsyncCallback, TID, DID, formMode = FormModes.Update, canNext, canPrev, count, itemIndex, onNext, onPrev, allowNavigation = true, allowRelations = true, isClosable = false, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, showDcmtFormSidebar = true, invokedByTodo = false, titleModal, isModal = false, widthModal = "100%", heightModal = "100%", groupId, onWFOperationCompleted, onTaskCompleted, inputFile = null, taskFormDialogComponent, taskMoreInfo, connectorFileSave = undefined, inputMids = [], onOpenS4TViewerRequest, s4TViewerDialogComponent, enableDragDropOverlay = false, passToSearch, isSharedDcmt = false, sharedSourceTID, sharedSourceDID, allowButtonsRefs = false, onReferenceClick, }) => {
41
41
  const [id, setID] = useState('');
42
42
  const [showWaitPanelLocal, setShowWaitPanelLocal] = useState(false);
43
43
  const [waitPanelTitleLocal, setWaitPanelTitleLocal] = useState('');
@@ -87,6 +87,11 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
87
87
  const [showCommentForm, setShowCommentForm] = useState(false);
88
88
  const [isInitialLoading, setIsInitialLoading] = useState(true);
89
89
  const [isNavigating, setIsNavigating] = useState(false);
90
+ const [dcmtReferences, setDcmtReferences] = useState(undefined);
91
+ useEffect(() => {
92
+ if (!allowButtonsRefs)
93
+ setDcmtReferences(undefined);
94
+ }, [allowButtonsRefs]);
90
95
  const { openConfirmAttachmentsDialog, ConfirmAttachmentsDialog } = useInputAttachmentsDialog();
91
96
  const { abortController, showWaitPanel, waitPanelTitle, showPrimary, waitPanelTextPrimary, waitPanelValuePrimary, waitPanelMaxValuePrimary, showSecondary, waitPanelTextSecondary, waitPanelValueSecondary, waitPanelMaxValueSecondary, downloadDcmtsAsync } = useDcmtOperations();
92
97
  // Custom hook to manage workflow approval data
@@ -165,9 +170,20 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
165
170
  // 3. CustomButtonsLayout - solo se layoutMode === Update
166
171
  layoutMode === LayoutModes.Update
167
172
  ? LayoutCacheService.GetAsync(TID, LayoutModes.None)
173
+ : Promise.resolve(undefined),
174
+ // 4. Opcionalmente FindAllReferencesAsync se abilitato nelle impostazioni e se i bottoni sono richiesti
175
+ (allowButtonsRefs && SDKUI_Globals.userSettings.searchSettings.autoFindReferences.length > 0)
176
+ ? SDK_Globals.tmSession?.NewSearchEngine().FindAllReferencesAsync(TID, DID, SDKUI_Globals.userSettings.searchSettings.autoFindReferences) ?? Promise.resolve(undefined)
168
177
  : Promise.resolve(undefined)
169
178
  ];
170
- const [getMetadataResult, resLayout, customButtonsLayoutResult] = await Promise.all(parallelCalls);
179
+ const results = await Promise.all(parallelCalls);
180
+ // Destructuring: first three are always the original ones, fourth is references (or undefined)
181
+ const getMetadataResult = results[0];
182
+ const resLayout = results[1];
183
+ const customButtonsLayoutResult = results[2];
184
+ const findRefsResult = results[3];
185
+ // Save references result into state (may be undefined)
186
+ setDcmtReferences(findRefsResult);
171
187
  // Imposta il layout e customButtonsLayout immediatamente
172
188
  setLayout(resLayout);
173
189
  if (layoutMode === LayoutModes.Update && customButtonsLayoutResult) {
@@ -196,7 +212,7 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
196
212
  setIsInitialLoading(false);
197
213
  setIsNavigating(false);
198
214
  }
199
- }, [TID, DID, layoutMode, inputFile, setMetadataList, handleReset]);
215
+ }, [TID, DID, layoutMode, inputFile, setMetadataList, handleReset, allowButtonsRefs]);
200
216
  const createChange = useCallback((mid, metadataType, modifiedValue) => {
201
217
  return { mid, metadataType, modifiedValue };
202
218
  }, []);
@@ -432,6 +448,7 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
432
448
  const isWFDisabled = useMemo(() => layoutMode !== LayoutModes.Update || fetchError || workItems.length <= 0, [layoutMode, fetchError, workItems.length]);
433
449
  const showToppyForApprove = useMemo(() => layoutMode === LayoutModes.Update && !fetchError && workItems.length > 0 && !isOpenDetails && !isOpenMaster, [layoutMode, fetchError, workItems.length, isOpenDetails, isOpenMaster]);
434
450
  const showToppyForCompleteMoreInfo = useMemo(() => layoutMode === LayoutModes.Update && isTaskMoreInfo(taskMoreInfo?.name) && taskMoreInfo?.state !== Task_States.Completed, [layoutMode, taskMoreInfo?.name, taskMoreInfo?.state]);
451
+ const showToppyForReferences = useMemo(() => allowButtonsRefs && layoutMode === LayoutModes.Update && dcmtReferences && dcmtReferences.length > 0 && !isOpenDetails && !isOpenMaster, [allowButtonsRefs, layoutMode, dcmtReferences, isOpenDetails, isOpenMaster]);
435
452
  const isMobile = useMemo(() => deviceType === DeviceType.MOBILE, [deviceType]);
436
453
  const isApprView = useMemo(() => fromDTD?.templateTID === TemplateTIDs.WF_WIApprView, [fromDTD?.templateTID]);
437
454
  const workitemSetID = useMemo(() => workItems.find(o => o.did === Number(DID))?.setID || formData.find(o => o.md?.name === WorkItemMetadataNames.WI_SetID)?.value, [workItems, DID, formData]);
@@ -1013,6 +1030,23 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
1013
1030
  title: SDKUI_Localizator.SignatureAndApprove,
1014
1031
  });
1015
1032
  }, [onOpenS4TViewerRequest, TID, DID]);
1033
+ const handleNavigateToReference = useCallback((ref) => {
1034
+ if (onReferenceClick) {
1035
+ try {
1036
+ onReferenceClick(ref);
1037
+ }
1038
+ catch (e) {
1039
+ console.error('onReferenceClick handler failed', e);
1040
+ }
1041
+ return;
1042
+ }
1043
+ }, [onReferenceClick]);
1044
+ // Mapping for objClass specific label/action. Easy to extend for future objClass types.
1045
+ const referenceActionMap = useMemo(() => ({
1046
+ [ObjectClasses.Dossier]: { label: 'Vai a pratica' },
1047
+ [ObjectClasses.WorkingGroup]: { label: 'Vai a gruppo di lavoro' },
1048
+ // add other ObjectClasses here as needed
1049
+ }), []);
1016
1050
  const renderDcmtForm = () => {
1017
1051
  // Show flat spinner during initial load (before component is mounted)
1018
1052
  if (isInitialLoading) {
@@ -1043,12 +1077,22 @@ const TMDcmtForm = ({ showHeader = true, onSaveRecents, layoutMode = LayoutModes
1043
1077
  isEditable: true,
1044
1078
  value: FormulaHelper.addFormulaTag(newFormula.expression)
1045
1079
  }));
1046
- } }), showApprovePopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, isReject: 0, onClose: () => setShowApprovePopup(false) }), showRejectPopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, isReject: 1, onClose: () => setShowRejectPopup(false) }), showReAssignPopup && _jsx(WorkFlowReAssignPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, onClose: () => setShowReAssignPopup(false) }), showMoreInfoPopup && _jsx(WorkFlowMoreInfoPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, onClose: () => setShowMoreInfoPopup(false) }), (isModal && onClose) && _jsx("div", { id: "TMDcmtFormShowConfirmForClose-" + id })] }), showToppyForApprove && (_jsx(ToppyHelpCenter, { deviceType: deviceType, usePortal: false, content: workItems.length === 1 ?
1047
- _jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: '10px' }, children: _jsx(WorkFlowOperationButtons, { deviceType: deviceType, onApprove: () => setShowApprovePopup(true), onSignApprove: handleSignApprove, onReject: () => setShowRejectPopup(true), onReAssign: () => setShowReAssignPopup(true), onMoreInfo: () => setShowMoreInfoPopup(true), dtd: fromDTD }) })
1048
- :
1049
- _jsxs("div", { style: { padding: 10, color: 'white', maxWidth: '180px', borderRadius: 10, background: '#1B1464 0% 0% no-repeat padding-box', border: '1px solid #FFFFFF' }, children: [`Devi approvare ${workItems.length} workitem(s) per questo documento.`, `Vai alla sezione di approvazione.`] }) })), showToppyForCompleteMoreInfo && (_jsx(ToppyHelpCenter, { deviceType: deviceType, usePortal: false, content: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 10 }, children: [_jsx("div", { style: { padding: 10, color: 'white', maxWidth: '180px', borderRadius: 10, background: '#1B1464 0% 0% no-repeat padding-box', border: '1px solid #FFFFFF' }, children: `${SDKUI_Localizator.MoreInfoCompleteRequestSentBy} ${taskMoreInfo?.fromName}!` }), _jsx(TMButton, { caption: SDKUI_Localizator.CommentAndComplete, color: 'success', showTooltip: false, onClick: () => {
1050
- setShowCommentForm(true);
1051
- } })] }) })), (showCommentForm && TID && DID) &&
1080
+ } }), showApprovePopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, isReject: 0, onClose: () => setShowApprovePopup(false) }), showRejectPopup && _jsx(WorkFlowApproveRejectPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, isReject: 1, onClose: () => setShowRejectPopup(false) }), showReAssignPopup && _jsx(WorkFlowReAssignPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, onClose: () => setShowReAssignPopup(false) }), showMoreInfoPopup && _jsx(WorkFlowMoreInfoPopUp, { deviceType: deviceType, onCompleted: handleWFOperationCompleted, TID: approvalVID, DID: DID, onClose: () => setShowMoreInfoPopup(false) }), (isModal && onClose) && _jsx("div", { id: "TMDcmtFormShowConfirmForClose-" + id })] }), (showToppyForApprove || showToppyForCompleteMoreInfo || showToppyForReferences) && (_jsx(ToppyHelpCenter, { deviceType: deviceType, usePortal: false, content: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: '10px' }, children: [showToppyForApprove && (workItems.length === 1 ?
1081
+ _jsx(WorkFlowOperationButtons, { deviceType: deviceType, onApprove: () => setShowApprovePopup(true), onSignApprove: handleSignApprove, onReject: () => setShowRejectPopup(true), onReAssign: () => setShowReAssignPopup(true), onMoreInfo: () => setShowMoreInfoPopup(true), dtd: fromDTD })
1082
+ :
1083
+ _jsxs("div", { style: { padding: 10, color: 'white', maxWidth: '180px', borderRadius: 10, background: '#1B1464 0% 0% no-repeat padding-box', border: '1px solid #FFFFFF' }, children: [`Devi approvare ${workItems.length} workitem(s) per questo documento.`, `Vai alla sezione di approvazione.`] })), showToppyForCompleteMoreInfo && (_jsxs(_Fragment, { children: [_jsx("div", { style: { padding: 10, color: 'white', maxWidth: '180px', borderRadius: 10, background: '#1B1464 0% 0% no-repeat padding-box', border: '1px solid #FFFFFF' }, children: `${SDKUI_Localizator.MoreInfoCompleteRequestSentBy} ${taskMoreInfo?.fromName}!` }), _jsx(TMButton, { caption: SDKUI_Localizator.CommentAndComplete, color: 'success', showTooltip: false, onClick: () => {
1084
+ setShowCommentForm(true);
1085
+ } })] })), showToppyForReferences && dcmtReferences && dcmtReferences
1086
+ .filter(ref => ref.objClass === ObjectClasses.Dossier || ref.objClass === ObjectClasses.WorkingGroup) // keep only known objClass types
1087
+ .map((ref, index, arr) => {
1088
+ const mapEntry = referenceActionMap[String(ref.objClass)];
1089
+ const label = mapEntry?.label ?? 'Vai a riferimento';
1090
+ return (_jsxs(React.Fragment, { children: [index === 0 && (showToppyForApprove || showToppyForCompleteMoreInfo) && (_jsx("div", { style: {
1091
+ height: 1,
1092
+ backgroundColor: 'rgba(255,255,255,0.2)',
1093
+ margin: '6px 0'
1094
+ } })), _jsxs(StyledReferenceButton, { onClick: () => handleNavigateToReference(ref), children: [_jsx("span", { children: label }), _jsx("span", { children: ref.objName })] }, `ref-${index}-${ref.objID}`)] }, `ref-frag-${index}-${ref.objID}`));
1095
+ })] }) })), (showCommentForm && TID && DID) &&
1052
1096
  _jsx(TMBlogCommentForm, { context: { engine: 'SearchEngine', object: { tid: TID, did: DID } }, onClose: () => setShowCommentForm(false), refreshCallback: handleCompleteMoreInfo, participants: [], showAttachmentsSection: false, allArchivedDocumentsFileItems: [] }), isOpenDetails &&
1053
1097
  _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 &&
1054
1098
  _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) => {
@@ -1088,7 +1132,7 @@ const applyMetadataFilter = (data, showAll, listMaxItems, TID) => {
1088
1132
  return showAll ? filteredData : filteredData.slice(0, listMaxItems);
1089
1133
  };
1090
1134
  //#region Validaion
1091
- const validateMetadataList = (mvdList = []) => {
1135
+ export const validateMetadataList = (mvdList = []) => {
1092
1136
  if (!Array.isArray(mvdList)) {
1093
1137
  throw new TypeError("metadataList must be an array of ITMMetadataProps.");
1094
1138
  }
@@ -279,7 +279,7 @@ const TMRelationViewerWrapper = ({ inputDcmts, isForMaster, showCurrentDcmtIndic
279
279
  const TMFormOrResultWrapper = ({ deviceType, focusedItem, onTaskCreateRequest }) => {
280
280
  const { setPanelVisibilityById } = useTMPanelManagerContext();
281
281
  return (_jsx(_Fragment, { children: focusedItem?.isDcmt ?
282
- _jsx(TMDcmtForm, { groupId: 'tmFormOrResult', TID: focusedItem?.tid, DID: focusedItem.did, isClosable: deviceType !== DeviceType.MOBILE, allowNavigation: false, allowRelations: deviceType !== DeviceType.MOBILE, showDcmtFormSidebar: false, onClose: () => {
282
+ _jsx(TMDcmtForm, { groupId: 'tmFormOrResult', TID: focusedItem?.tid, DID: focusedItem.did, allowButtonsRefs: true, isClosable: deviceType !== DeviceType.MOBILE, allowNavigation: false, allowRelations: deviceType !== DeviceType.MOBILE, showDcmtFormSidebar: false, onClose: () => {
283
283
  setPanelVisibilityById('tmTreeView', true);
284
284
  } }) :
285
285
  _jsx(TMSearchResult, { groupId: 'tmFormOrResult', isClosable: deviceType !== DeviceType.MOBILE, context: SearchResultContext.METADATA_SEARCH, allowFloatingBar: false, allowRelations: false, openDcmtFormAsModal: true, searchResults: focusedItem?.searchResult ?? [], showSearchResultSidebar: false, onTaskCreateRequest: onTaskCreateRequest, onClose: () => {
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { DcmtTypeDescriptor, TaskDescriptor } from '@topconsultnpm/sdk-ts';
2
+ import { DcmtTypeDescriptor, TaskDescriptor, ObjectRef } from '@topconsultnpm/sdk-ts';
3
3
  import { DcmtInfo, TaskContext } from '../../../ts';
4
4
  import { TMSearchResultFloatingActionConfig } from './TMSearchResultFloatingActionButton';
5
5
  interface ITMSearchProps {
@@ -27,6 +27,7 @@ interface ITMSearchProps {
27
27
  }>, tid?: number) => void;
28
28
  onCurrentTIDChangedCallback?: (tid: number | undefined) => void;
29
29
  onlyShowSearchQueryPanel?: boolean;
30
+ onReferenceClick?: (ref: ObjectRef) => void;
30
31
  }
31
32
  declare const TMSearch: React.FunctionComponent<ITMSearchProps>;
32
33
  export default TMSearch;
@@ -18,7 +18,7 @@ var TMSearchViews;
18
18
  TMSearchViews[TMSearchViews["Search"] = 0] = "Search";
19
19
  TMSearchViews[TMSearchViews["Result"] = 1] = "Result";
20
20
  })(TMSearchViews || (TMSearchViews = {}));
21
- const TMSearch = ({ openInOffice, isVisible, inputTID, inputSqdID, inputMids, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, floatingActionConfig, onFileOpened, onRefreshAfterAddDcmtToFavs, onTaskCreateRequest, openWGsCopyMoveForm, openEditPdf, openS4TViewer, onOpenS4TViewerRequest, showTodoDcmtForm, passToArchiveCallback, onCurrentTIDChangedCallback, onlyShowSearchQueryPanel }) => {
21
+ const TMSearch = ({ openInOffice, isVisible, inputTID, inputSqdID, inputMids, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, floatingActionConfig, onFileOpened, onRefreshAfterAddDcmtToFavs, onTaskCreateRequest, openWGsCopyMoveForm, openEditPdf, openS4TViewer, onOpenS4TViewerRequest, showTodoDcmtForm, passToArchiveCallback, onCurrentTIDChangedCallback, onlyShowSearchQueryPanel, onReferenceClick }) => {
22
22
  const [allSQDs, setAllSQDs] = useState([]);
23
23
  const [filteredByTIDSQDs, setFilteredByTIDSQDs] = useState([]);
24
24
  const [currentSQD, setCurrentSQD] = useState();
@@ -219,7 +219,7 @@ const TMSearch = ({ openInOffice, isVisible, inputTID, inputSqdID, inputMids, is
219
219
  toolbarOptions: { icon: _jsx(IconSavedQuery, { fontSize: 24 }), visible: true, orderNumber: 4, isActive: allInitialPanelVisibility['TMSavedQuerySelector'] }
220
220
  }
221
221
  ], [tmTreeSelectorElement, showSearchResults, tmRecentsManagerElement, tmSearchQueryPanelElement, tmSavedQuerySelectorElement, fromDTD, mruTIDs]);
222
- return (_jsxs(_Fragment, { children: [showSearchResults ? _jsx(StyledMultiViewPanel, { "$isVisible": currentSearchView === TMSearchViews.Search, children: _jsx(TMPanelManagerProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: initialPanelDimensions, initialDimensions: initialPanelDimensions, initialMobilePanelId: 'TMRecentsManager', children: _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", showToolbar: true }) }) }) : tmSearchQueryPanelElement, showSearchResults && _jsx(TMSearchResult, { isVisible: isVisible && currentSearchView === TMSearchViews.Result, context: SearchResultContext.METADATA_SEARCH, searchResults: searchResult, floatingActionConfig: floatingActionConfig, onRefreshAfterAddDcmtToFavs: onRefreshAfterAddDcmtToFavs, openInOffice: openInOffice, onRefreshSearchAsync: onRefreshSearchAsync, onClose: () => { onlyShowSearchQueryPanel ? setShowSearchResults(false) : setCurrentSearchView(TMSearchViews.Search); }, onFileOpened: onFileOpened, onTaskCreateRequest: onTaskCreateRequest, openWGsCopyMoveForm: openWGsCopyMoveForm, openEditPdf: openEditPdf, openS4TViewer: openS4TViewer, onOpenS4TViewerRequest: onOpenS4TViewerRequest, passToArchiveCallback: passToArchiveCallback, onSelectedTIDChanged: onCurrentTIDChangedCallback, showTodoDcmtForm: showTodoDcmtForm })] }));
222
+ return (_jsxs(_Fragment, { children: [showSearchResults ? _jsx(StyledMultiViewPanel, { "$isVisible": currentSearchView === TMSearchViews.Search, children: _jsx(TMPanelManagerProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: initialPanelDimensions, initialDimensions: initialPanelDimensions, initialMobilePanelId: 'TMRecentsManager', children: _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", showToolbar: true }) }) }) : tmSearchQueryPanelElement, showSearchResults && _jsx(TMSearchResult, { isVisible: isVisible && currentSearchView === TMSearchViews.Result, context: SearchResultContext.METADATA_SEARCH, searchResults: searchResult, floatingActionConfig: floatingActionConfig, onRefreshAfterAddDcmtToFavs: onRefreshAfterAddDcmtToFavs, openInOffice: openInOffice, onRefreshSearchAsync: onRefreshSearchAsync, onClose: () => { onlyShowSearchQueryPanel ? setShowSearchResults(false) : setCurrentSearchView(TMSearchViews.Search); }, onFileOpened: onFileOpened, onTaskCreateRequest: onTaskCreateRequest, openWGsCopyMoveForm: openWGsCopyMoveForm, openEditPdf: openEditPdf, openS4TViewer: openS4TViewer, onOpenS4TViewerRequest: onOpenS4TViewerRequest, passToArchiveCallback: passToArchiveCallback, onSelectedTIDChanged: onCurrentTIDChangedCallback, showTodoDcmtForm: showTodoDcmtForm, onReferenceClick: onReferenceClick })] }));
223
223
  };
224
224
  export default TMSearch;
225
225
  const TMTreeSelectorWrapper = ({ isMobile, onSelectedTIDChanged }) => {
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { SearchResultDescriptor, DcmtTypeDescriptor, TaskDescriptor, WorkingGroupDescriptor } from '@topconsultnpm/sdk-ts';
2
+ import { SearchResultDescriptor, DcmtTypeDescriptor, TaskDescriptor, WorkingGroupDescriptor, ObjectRef } from '@topconsultnpm/sdk-ts';
3
3
  import { DcmtInfo, SearchResultContext, TaskContext } from '../../../ts';
4
4
  import { TMSearchResultFloatingActionConfig } from './TMSearchResultFloatingActionButton';
5
5
  export declare const getSearchResultCountersSingleCategory: (searchResults: SearchResultDescriptor[]) => string;
@@ -40,6 +40,7 @@ interface ITMSearchResultProps {
40
40
  value: string;
41
41
  }>, tid?: number) => void;
42
42
  showTodoDcmtForm?: boolean;
43
+ onReferenceClick?: (ref: ObjectRef) => void;
43
44
  }
44
45
  declare const TMSearchResult: React.FC<ITMSearchResultProps>;
45
46
  export default TMSearchResult;
@@ -59,7 +59,7 @@ const orderByName = (array) => {
59
59
  return 1;
60
60
  } return 0; });
61
61
  };
62
- const TMSearchResult = ({ context = SearchResultContext.METADATA_SEARCH, isVisible = true, allowRelations = true, openDcmtFormAsModal = false, searchResults = [], showSearchResultSidebar = true, showSelector = false, groupId, title, isClosable = false, allowFloatingBar = true, showToolbarHeader = true, showBackButton = true, selectedSearchResultTID, workingGroupContext = undefined, disableAccordionIfSingleCategory = false, floatingActionConfig, openInOffice, onRefreshAfterAddDcmtToFavs, onRefreshSearchAsync, onSelectedTIDChanged, onWFOperationCompleted, onClose, onFileOpened, onTaskCreateRequest, openWGsCopyMoveForm, openEditPdf, openCommentFormCallback, openAddDocumentForm, openS4TViewer = false, onOpenS4TViewerRequest, passToArchiveCallback, showTodoDcmtForm = false }) => {
62
+ const TMSearchResult = ({ context = SearchResultContext.METADATA_SEARCH, isVisible = true, allowRelations = true, openDcmtFormAsModal = false, searchResults = [], showSearchResultSidebar = true, showSelector = false, groupId, title, isClosable = false, allowFloatingBar = true, showToolbarHeader = true, showBackButton = true, selectedSearchResultTID, workingGroupContext = undefined, disableAccordionIfSingleCategory = false, floatingActionConfig, openInOffice, onRefreshAfterAddDcmtToFavs, onRefreshSearchAsync, onSelectedTIDChanged, onWFOperationCompleted, onClose, onFileOpened, onTaskCreateRequest, openWGsCopyMoveForm, openEditPdf, openCommentFormCallback, openAddDocumentForm, openS4TViewer = false, onOpenS4TViewerRequest, passToArchiveCallback, showTodoDcmtForm = false, onReferenceClick }) => {
63
63
  const [id, setID] = useState('');
64
64
  const [showApprovePopup, setShowApprovePopup] = useState(false);
65
65
  const [showRejectPopup, setShowRejectPopup] = useState(false);
@@ -644,9 +644,9 @@ const TMSearchResult = ({ context = SearchResultContext.METADATA_SEARCH, isVisib
644
644
  :
645
645
  _jsx(TMPanelManagerProvider, { panels: initialPanels, initialVisibility: allInitialPanelVisibility, defaultDimensions: initialPanelDimensions, initialDimensions: initialPanelDimensions, initialMobilePanelId: 'tmSearchResult', children: _jsx(TMPanelManagerContainer, { panels: initialPanels, direction: "horizontal", parentId: groupId, showToolbar: showSearchResultSidebar }) }) }) }), _jsx(StyledMultiViewPanel, { "$isVisible": isOpenDetails, children: isOpenDetails && _jsx(TMMasterDetailDcmts, { deviceType: deviceType, isForMaster: false, inputDcmts: getSelectionDcmtInfo(), allowNavigation: focusedItem && selectedItems.length <= 0, canNext: canNavigateHandler('next'), canPrev: canNavigateHandler('prev'), onNext: () => onNavigateHandler('next'), onPrev: () => onNavigateHandler('prev'), onBack: () => setIsOpenDetails(false) }) }), _jsxs(StyledMultiViewPanel, { "$isVisible": isOpenMaster, children: [isOpenMaster && _jsx(TMMasterDetailDcmts, { deviceType: deviceType, inputDcmts: getSelectionDcmtInfo(), isForMaster: true, allowNavigation: focusedItem && selectedItems.length <= 0, canNext: canNavigateHandler('next'), canPrev: canNavigateHandler('prev'), onNext: () => onNavigateHandler('next'), onPrev: () => onNavigateHandler('prev'), onBack: () => setIsOpenMaster(false), appendMasterDcmts: handleAddItem }), secondaryMasterDcmts.length > 0 && secondaryMasterDcmts.map((dcmt, index) => {
646
646
  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}`));
647
- })] }), _jsx(StyledMultiViewPanel, { "$isVisible": isOpenDcmtForm, children: isOpenDcmtForm && _jsx(TMDcmtForm, { isModal: openDcmtFormAsModal || (dcmtFormLayoutMode === LayoutModes.Ark && focusedItem?.DID), titleModal: fromDTD?.name ?? '', TID: focusedItem?.TID, DID: focusedItem?.DID, layoutMode: dcmtFormLayoutMode, count: visibleItems.length, itemIndex: visibleItems.findIndex(o => o.rowIndex === focusedItem?.rowIndex) + 1, canNext: canNavigateHandler('next'), canPrev: canNavigateHandler('prev'), onNext: () => onNavigateHandler('next'), onPrev: () => onNavigateHandler('prev'), onClose: () => { setIsOpenDcmtForm(false); }, onWFOperationCompleted: onWFOperationCompleted, onTaskCreateRequest: onTaskCreateRequest, onSavedAsyncCallback: async (tid, did, metadataResult) => {
647
+ })] }), _jsx(StyledMultiViewPanel, { "$isVisible": isOpenDcmtForm, children: isOpenDcmtForm && _jsx(TMDcmtForm, { isModal: openDcmtFormAsModal || (dcmtFormLayoutMode === LayoutModes.Ark && focusedItem?.DID), titleModal: fromDTD?.name ?? '', TID: focusedItem?.TID, DID: focusedItem?.DID, allowButtonsRefs: true, layoutMode: dcmtFormLayoutMode, count: visibleItems.length, itemIndex: visibleItems.findIndex(o => o.rowIndex === focusedItem?.rowIndex) + 1, canNext: canNavigateHandler('next'), canPrev: canNavigateHandler('prev'), onNext: () => onNavigateHandler('next'), onPrev: () => onNavigateHandler('prev'), onClose: () => { setIsOpenDcmtForm(false); }, onWFOperationCompleted: onWFOperationCompleted, onTaskCreateRequest: onTaskCreateRequest, onSavedAsyncCallback: async (tid, did, metadataResult) => {
648
648
  await refreshFocusedDataRowAsync(tid, did, true, metadataResult);
649
- }, onOpenS4TViewerRequest: onOpenS4TViewerRequest }) }), isOpenArchiveRelationForm && _jsx(TMDcmtForm, { isModal: true, titleModal: SDKUI_Localizator.Archive + ' - ' + (archiveType === 'detail' ? SDKUI_Localizator.DcmtsDetail : SDKUI_Localizator.DcmtsMaster), TID: archiveRelatedDcmtFormTID, layoutMode: LayoutModes.Ark, inputMids: archiveRelatedDcmtFormMids, showBackButton: false, onClose: () => {
649
+ }, onOpenS4TViewerRequest: onOpenS4TViewerRequest, onReferenceClick: onReferenceClick }) }), isOpenArchiveRelationForm && _jsx(TMDcmtForm, { isModal: true, titleModal: SDKUI_Localizator.Archive + ' - ' + (archiveType === 'detail' ? SDKUI_Localizator.DcmtsDetail : SDKUI_Localizator.DcmtsMaster), TID: archiveRelatedDcmtFormTID, layoutMode: LayoutModes.Ark, inputMids: archiveRelatedDcmtFormMids, showBackButton: false, allowButtonsRefs: false, onClose: () => {
650
650
  setIsOpenArchiveRelationForm(false);
651
651
  setArchiveType(undefined);
652
652
  setArchiveRelatedDcmtFormTID(undefined);
@@ -76,6 +76,7 @@ export declare const getAttachmentInfo: (attachment: BlogPostAttachment, treeFs:
76
76
  draftExist: boolean;
77
77
  archivedDocumentsExist: boolean;
78
78
  };
79
+ export declare const findFileItemByTidDid: (tree: FileItem | undefined, tid: number | undefined, did: number | undefined) => FileItem | null;
79
80
  export declare const AttachmentElement: (attachment: BlogPostAttachment, treeFs: FileItem | undefined, draftLatestInfoMap: Map<number, {
80
81
  latestVersion: number;
81
82
  folderId: number;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import styled from "styled-components";
3
- import { SDK_Globals } from "@topconsultnpm/sdk-ts";
3
+ import { SDK_Globals, SystemTIDs } from "@topconsultnpm/sdk-ts";
4
4
  import { extractInitialsFromName, formatBytes, getAvatarColor, IconAttachment, IconCADossier, IconMenuCAWorkingGroups, SDKUI_Localizator } from "../../helper";
5
5
  import TMTooltip from "../base/TMTooltip";
6
6
  import { TMColors } from '../../utils/theme';
@@ -130,14 +130,48 @@ export const getAttachmentInfo = (attachment, treeFs, draftLatestInfoMap, archiv
130
130
  }
131
131
  }
132
132
  if (descriptor) {
133
+ // Default name from descriptor
133
134
  name = descriptor.name ?? "-";
135
+ // If descriptor is DSAttachs, try to find the actual archived file in treeFs by tid/did
136
+ if (descriptor.id === SystemTIDs.DSAttachs && treeFs && attachment.tid && attachment.did) {
137
+ const found = findFileItemByTidDid(treeFs, attachment.tid, attachment.did);
138
+ if (found) {
139
+ name = found.name ?? name;
140
+ fileExt = found.ext ?? (found.name && found.name.includes('.') ? found.name.substring(found.name.lastIndexOf('.') + 1) : fileExt);
141
+ archivedDocumentsExist = true;
142
+ }
143
+ }
134
144
  const content = (_jsxs("div", { children: [archivedDocumentMap && (_jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.Size }), ": ", fileSize] })), _jsx("hr", {}), _jsxs("div", { children: [_jsx("span", { style: { fontWeight: 'bold' }, children: SDKUI_Localizator.Path }), ": \"", SDKUI_Localizator.ArchivedDocuments, "\\", `${descriptor.name} (DID: ${attachment.did})`, "\""] })] }));
135
145
  tooltipContent = getTooltipContent(descriptor.name, content);
136
- nameElement = (_jsx("span", { children: highlightText(`${name} (DID: ${attachment.did})`, searchText, isSelected) }));
146
+ nameElement = (_jsx("span", { children: descriptor.id !== SystemTIDs.DSAttachs
147
+ ? highlightText(`${name} (DID: ${attachment.did})`, searchText, isSelected)
148
+ : highlightText(`${name}`, searchText, isSelected) }));
137
149
  }
138
150
  }
139
151
  return { name, nameElement, tooltipContent, folderId, fileExt, draftExist, archivedDocumentsExist };
140
152
  };
153
+ // Helper: find a file item by tid and did inside the treeFs structure
154
+ export const findFileItemByTidDid = (tree, tid, did) => {
155
+ if (!tree || tid === undefined || did === undefined)
156
+ return null;
157
+ const stack = [tree];
158
+ while (stack.length > 0) {
159
+ const node = stack.pop();
160
+ if (!node)
161
+ continue;
162
+ if (!node.isDirectory) {
163
+ if ((node.tid === tid || node.tid === Number(tid)) && (node.did === did || node.did === Number(did))) {
164
+ return node;
165
+ }
166
+ }
167
+ if (node.items && node.items.length > 0) {
168
+ for (const child of node.items) {
169
+ stack.push(child);
170
+ }
171
+ }
172
+ }
173
+ return null;
174
+ };
141
175
  export const AttachmentElement = (attachment, treeFs, draftLatestInfoMap, archivedDocumentMap, dcmtTypeDescriptors, isSelected, searchText, color, setShowDcmtForm, handleFocusedAttachment, setAnchorEl, contextMenuRef) => {
142
176
  const { name, nameElement, tooltipContent, fileExt, archivedDocumentsExist, draftExist } = getAttachmentInfo(attachment, treeFs, draftLatestInfoMap, archivedDocumentMap, dcmtTypeDescriptors, isSelected, searchText, color);
143
177
  const onDoubleClick = (e) => {
@@ -50,6 +50,7 @@ declare class TMColors {
50
50
  static separator: string;
51
51
  static button_primary: string;
52
52
  static iconLight: string;
53
+ static button_floating_background: string;
53
54
  }
54
55
  declare class FontSize {
55
56
  static defaultFontSize: string;
@@ -58,6 +58,7 @@ TMColors._colorHeader = "black";
58
58
  TMColors.separator = "#00A99D";
59
59
  TMColors.button_primary = '#4A96D2';
60
60
  TMColors.iconLight = "#9fc6e7";
61
+ TMColors.button_floating_background = "#C2388B";
61
62
  class FontSize {
62
63
  }
63
64
  FontSize.defaultFontSize = '1rem';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.19.0-dev1.49",
3
+ "version": "6.19.0-dev1.50",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",