@topconsultnpm/sdkui-react 6.20.0-dev1.78 → 6.20.0-dev1.80
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/NewComponents/ContextMenu/TMContextMenu.js +2 -2
- package/lib/components/NewComponents/ContextMenu/styles.js +1 -1
- package/lib/components/NewComponents/ContextMenu/types.d.ts +1 -1
- package/lib/components/base/TMDataGrid.js +8 -6
- package/lib/components/features/documents/TMDcmtForm.js +58 -7
- package/lib/components/features/tasks/TMTasksAgenda.d.ts +3 -1
- package/lib/components/features/tasks/TMTasksAgenda.js +48 -9
- package/lib/components/features/tasks/TMTasksCalendar.d.ts +2 -0
- package/lib/components/features/tasks/TMTasksCalendar.js +19 -7
- package/lib/components/features/tasks/TMTasksUtils.d.ts +2 -2
- package/lib/components/features/tasks/TMTasksUtils.js +43 -36
- package/lib/components/features/tasks/TMTasksView.js +26 -17
- package/lib/helper/index.d.ts +1 -0
- package/lib/helper/index.js +1 -0
- package/lib/helper/workItemsHelper.d.ts +6 -0
- package/lib/helper/workItemsHelper.js +230 -0
- package/lib/services/platform_services.d.ts +1 -1
- package/lib/ts/types.d.ts +5 -2
- package/package.json +2 -2
|
@@ -344,7 +344,7 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
|
|
|
344
344
|
}));
|
|
345
345
|
};
|
|
346
346
|
const handleMouseEnter = (item, event, depth = 0) => {
|
|
347
|
-
if (isMobile || !item.submenu || item.submenu.length === 0)
|
|
347
|
+
if (isMobile || !item.submenu || item.submenu.length === 0 || item.disabled)
|
|
348
348
|
return;
|
|
349
349
|
if (submenuTimeoutRef.current) {
|
|
350
350
|
clearTimeout(submenuTimeoutRef.current);
|
|
@@ -424,7 +424,7 @@ const TMContextMenu = ({ items, trigger = 'right', children, target, externalCon
|
|
|
424
424
|
item.onRightIconClick?.();
|
|
425
425
|
handleClose();
|
|
426
426
|
};
|
|
427
|
-
return (_jsxs(S.MenuItem, { "$disabled": item.disabled, "$hasSubmenu": !!item.submenu && item.submenu.length > 0, "$beginGroup": item.beginGroup, onMouseDown: handleClick, onMouseEnter: (e) => !isMobile && handleMouseEnter(item, e, depth + 1), onMouseLeave: () => !isMobile && handleMouseLeave(depth + 1), title: item.tooltip, children: [_jsxs(S.MenuItemContent, { children: [item.icon && _jsx(S.IconWrapper, { children: item.icon }), _jsx(S.MenuItemName, { children: item.name })] }), item.rightIcon && item.onRightIconClick && (_jsx(S.RightIconButton, { onClick: handleRightIconClick, onMouseDown: (e) => e.stopPropagation(), "aria-label": `Action for ${item.name}`, children: item.rightIcon })), item.submenu && item.submenu.length > 0 && (_jsx(S.SubmenuIndicator, { "$isMobile": isMobile, children: isMobile ? '›' : '▸' }))] }, itemKey));
|
|
427
|
+
return (_jsxs(S.MenuItem, { "$disabled": item.disabled, "$hasSubmenu": !!item.submenu && item.submenu.length > 0, "$beginGroup": item.beginGroup, "data-disabled": item.disabled ? "true" : undefined, onMouseDown: handleClick, onMouseEnter: (e) => !isMobile && handleMouseEnter(item, e, depth + 1), onMouseLeave: () => !isMobile && handleMouseLeave(depth + 1), title: item.tooltip, children: [_jsxs(S.MenuItemContent, { children: [item.icon && _jsx(S.IconWrapper, { children: item.icon }), _jsx(S.MenuItemName, { children: item.name })] }), item.rightIcon && item.onRightIconClick && (_jsx(S.RightIconButton, { onClick: handleRightIconClick, onMouseDown: (e) => e.stopPropagation(), "aria-label": `Action for ${item.name}`, children: item.rightIcon })), item.submenu && item.submenu.length > 0 && (_jsx(S.SubmenuIndicator, { "$isMobile": isMobile, children: isMobile ? '›' : '▸' }))] }, itemKey));
|
|
428
428
|
});
|
|
429
429
|
};
|
|
430
430
|
const currentParentName = menuState.parentNames.at(-1) || '';
|
|
@@ -226,7 +226,7 @@ export const SubmenuIndicator = styled.span `
|
|
|
226
226
|
opacity: 0.6;
|
|
227
227
|
transition: transform 0.15s ease;
|
|
228
228
|
|
|
229
|
-
${MenuItem}:hover & {
|
|
229
|
+
${MenuItem}:hover:not([data-disabled="true"]) & {
|
|
230
230
|
${props => !props.$isMobile && `
|
|
231
231
|
transform: translateX(2px);
|
|
232
232
|
opacity: 1;
|
|
@@ -59,25 +59,27 @@ const TMDataGrid = React.forwardRef((props, ref) => {
|
|
|
59
59
|
const handleContextMenu = (e) => {
|
|
60
60
|
e.preventDefault();
|
|
61
61
|
e.stopPropagation();
|
|
62
|
-
// Get the clicked row
|
|
62
|
+
// Get the clicked row (if any)
|
|
63
63
|
const target = e.target;
|
|
64
64
|
const rowElement = target.closest('.dx-data-row');
|
|
65
65
|
if (rowElement && internalRef.current) {
|
|
66
|
+
// Clicked on a row - focus that row
|
|
66
67
|
const rowIndex = Array.from(rowElement.parentElement?.children || []).indexOf(rowElement);
|
|
67
68
|
const rowKey = internalRef.current.instance().getKeyByRowIndex(rowIndex);
|
|
68
|
-
// Change focused row
|
|
69
69
|
internalRef.current.instance().option('focusedRowKey', rowKey);
|
|
70
|
-
// Show custom context menu
|
|
71
|
-
setCustomContextMenuVisible(true);
|
|
72
|
-
setCustomContextMenuPosition({ x: e.clientX, y: e.clientY });
|
|
73
70
|
setCustomContextMenuRowKey(rowKey);
|
|
74
71
|
}
|
|
72
|
+
else {
|
|
73
|
+
setCustomContextMenuRowKey(focusedRowKey);
|
|
74
|
+
}
|
|
75
|
+
setCustomContextMenuVisible(true);
|
|
76
|
+
setCustomContextMenuPosition({ x: e.clientX, y: e.clientY });
|
|
75
77
|
};
|
|
76
78
|
gridContainer.addEventListener('contextmenu', handleContextMenu);
|
|
77
79
|
return () => {
|
|
78
80
|
gridContainer.removeEventListener('contextmenu', handleContextMenu);
|
|
79
81
|
};
|
|
80
|
-
}, [customContextMenuItems]);
|
|
82
|
+
}, [customContextMenuItems, focusedRowKey]);
|
|
81
83
|
// iOS-specific: Handle touch for focused row change and long-press for context menu
|
|
82
84
|
useLongPress({
|
|
83
85
|
containerRef: gridContainerRef,
|
|
@@ -8,7 +8,7 @@ import { DeviceType, useDeviceType } from '../../base/TMDeviceProvider';
|
|
|
8
8
|
import { useDcmtOperations } from '../../../hooks/useDcmtOperations';
|
|
9
9
|
import { useRelatedDocuments } from '../../../hooks/useRelatedDocuments';
|
|
10
10
|
import { getWorkItemSetIDAsync, handleArchiveVisibility, searchResultToMetadataValues } from '../../../helper/queryHelper';
|
|
11
|
-
import { genUniqueId, IconShow, SDKUI_Localizator, updateMruTids, IconBoard, IconDcmtTypeSys, IconDetailDcmts, IconDownload, calcIsModified, IconMenuVertical, Globalization, getListMaxItems, getSystemMetadata, IconBoxArchiveIn, IconClear, IconUndo, SDKUI_Globals, IconPreview, isTaskMoreInfo, IconWorkflow, IconSearch, deepCompare, IconCheck, IconActivity, TMImageLibrary, IconStar, IconRelation, IconInfo, IconArchiveDoc, IconDelete, IconPair, IconUnpair, IconArchiveMaster, IconArchiveDetail, getExceptionMessage, isApprovalWorkflowView, getDcmtCicoStatus, IconFileDots, IconCustom } from '../../../helper';
|
|
11
|
+
import { genUniqueId, IconShow, SDKUI_Localizator, updateMruTids, IconBoard, IconDcmtTypeSys, IconDetailDcmts, IconDownload, calcIsModified, IconMenuVertical, Globalization, getListMaxItems, getSystemMetadata, IconBoxArchiveIn, IconClear, IconUndo, SDKUI_Globals, IconPreview, isTaskMoreInfo, IconWorkflow, IconSearch, deepCompare, IconCheck, IconActivity, TMImageLibrary, IconStar, IconRelation, IconInfo, IconArchiveDoc, IconDelete, IconPair, IconUnpair, IconArchiveMaster, IconArchiveDetail, getExceptionMessage, isApprovalWorkflowView, getDcmtCicoStatus, IconFileDots, IconCustom, buildWorkItemsFromWFCtrl } from '../../../helper';
|
|
12
12
|
import { hasDetailRelations, hasMasterRelations, isXMLFileExt } from '../../../helper/dcmtsHelper';
|
|
13
13
|
import { Gutters, TMColors } from '../../../utils/theme';
|
|
14
14
|
import { StyledFormButtonsContainer, StyledLoadingContainer, StyledModalContainer, StyledReferenceButton, StyledSpinner, StyledToolbarCardContainer } from '../../base/Styled';
|
|
@@ -112,6 +112,7 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
|
|
|
112
112
|
const [fetchError, setFetchError] = useState(false);
|
|
113
113
|
const [isWFDataLoading, setIsWFDataLoading] = useState(false);
|
|
114
114
|
const [workItems, setWorkItems] = useState([]);
|
|
115
|
+
const [workItemsForDiagram, setWorkItemsForDiagram] = useState([]);
|
|
115
116
|
const [workflows, setWorkflows] = useState([]);
|
|
116
117
|
const [showCommentForm, setShowCommentForm] = useState(false);
|
|
117
118
|
const [isInitialLoading, setIsInitialLoading] = useState(true);
|
|
@@ -509,7 +510,13 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
|
|
|
509
510
|
setID = await getWorkItemSetIDAsync(foundItem.tid, foundItem.did);
|
|
510
511
|
}
|
|
511
512
|
// Imposta un singolo work item con il setID caricato
|
|
512
|
-
setWorkItems([{
|
|
513
|
+
setWorkItems([{
|
|
514
|
+
wid: `${foundItem.tid}_${foundItem.did}`,
|
|
515
|
+
tid: foundItem.tid,
|
|
516
|
+
did: foundItem.did,
|
|
517
|
+
setID: setID,
|
|
518
|
+
details: []
|
|
519
|
+
}]);
|
|
513
520
|
// Carica le informazioni complete del workflow
|
|
514
521
|
await loadWorkflowInfo(foundItem.tid);
|
|
515
522
|
}
|
|
@@ -528,14 +535,26 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
|
|
|
528
535
|
else {
|
|
529
536
|
setID = await getWorkItemSetIDAsync(singleItem.tid, singleItem.did);
|
|
530
537
|
}
|
|
531
|
-
setWorkItems([{
|
|
538
|
+
setWorkItems([{
|
|
539
|
+
wid: `${singleItem.tid}_${singleItem.did}`,
|
|
540
|
+
tid: singleItem.tid,
|
|
541
|
+
did: singleItem.did,
|
|
542
|
+
setID: setID,
|
|
543
|
+
details: []
|
|
544
|
+
}]);
|
|
532
545
|
// Carica le informazioni del workflow
|
|
533
546
|
await loadWorkflowInfo(singleItem.tid);
|
|
534
547
|
}
|
|
535
548
|
else if (itemsByDID.length > 1) {
|
|
536
549
|
// SCENARIO B.2: Più item trovati per lo stesso DID
|
|
537
550
|
// Ambiguità: lo stesso documento appare in più workflow diversi
|
|
538
|
-
const finalWorkItems = itemsByDID.map((item, index) => ({
|
|
551
|
+
const finalWorkItems = itemsByDID.map((item, index) => ({
|
|
552
|
+
wid: `${item.tid}_${item.did}_${index}`,
|
|
553
|
+
tid: item.tid,
|
|
554
|
+
did: item.did,
|
|
555
|
+
setID: undefined,
|
|
556
|
+
details: []
|
|
557
|
+
}));
|
|
539
558
|
setWorkItems(finalWorkItems);
|
|
540
559
|
setWorkflows([]); // Non carichiamo il workflow in caso di ambiguità
|
|
541
560
|
}
|
|
@@ -558,6 +577,38 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
|
|
|
558
577
|
if (workItemSetIDValue !== undefined || workflowApproveData.length > 0)
|
|
559
578
|
loadAllWfData();
|
|
560
579
|
}, [hasFormData, workItemSetIDValue, workflowApproveData, getWorkItemsByDID, TID, DID, layoutMode, fromDTD?.templateTID, fromDTD?.id]);
|
|
580
|
+
// useEffect per costruire workItemsForDiagram quando l'utente è autorizzato a vedere il diagramma
|
|
581
|
+
useEffect(() => {
|
|
582
|
+
const buildWorkItemsForDiagram = async () => {
|
|
583
|
+
// Verifica se l'utente è autorizzato (ha accesso al diagramma)
|
|
584
|
+
const isAuthorized = !!workflows?.[0]?.diagram;
|
|
585
|
+
if (!isAuthorized || workItems.length === 0) {
|
|
586
|
+
setWorkItemsForDiagram([]);
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
try {
|
|
590
|
+
// Estrai i dati necessari dal primo workItem
|
|
591
|
+
const firstWorkItem = workItems[0];
|
|
592
|
+
// Costruisci WFInstanceDescriptor dai dati disponibili
|
|
593
|
+
const wfInstance = {
|
|
594
|
+
wfid: workflows[0].id,
|
|
595
|
+
tid: TID,
|
|
596
|
+
did: DID,
|
|
597
|
+
instanceId: "", // Puoi adattare questo se hai un instanceId specifico,
|
|
598
|
+
rowIndex: 0,
|
|
599
|
+
values: []
|
|
600
|
+
};
|
|
601
|
+
// Chiama buildWorkItemsFromWFCtrl per ottenere i workItems completi
|
|
602
|
+
const detailedWorkItems = await buildWorkItemsFromWFCtrl(wfInstance);
|
|
603
|
+
setWorkItemsForDiagram(detailedWorkItems);
|
|
604
|
+
}
|
|
605
|
+
catch (error) {
|
|
606
|
+
console.error('Errore durante la costruzione dei work items per il diagramma:', error);
|
|
607
|
+
setWorkItemsForDiagram([]);
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
buildWorkItemsForDiagram();
|
|
611
|
+
}, [workflows, workItems]);
|
|
561
612
|
const getSelectionDcmtInfo = useCallback(() => {
|
|
562
613
|
let dcmts = [];
|
|
563
614
|
dcmts.push({ TID: TID ?? 0, DID: DID ?? 0 });
|
|
@@ -583,7 +634,7 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
|
|
|
583
634
|
const isSysMetadataDisabled = useMemo(() => layoutMode !== LayoutModes.Update, [layoutMode]);
|
|
584
635
|
const isDetailsDisabled = useMemo(() => layoutMode !== LayoutModes.Update || !DID, [layoutMode, DID]);
|
|
585
636
|
const isMasterDisabled = useMemo(() => layoutMode !== LayoutModes.Update || !DID, [layoutMode, DID]);
|
|
586
|
-
const isWFDisabled = useMemo(() => layoutMode !== LayoutModes.Update || fetchError || workItems.length <= 0, [layoutMode, fetchError, workItems.length]);
|
|
637
|
+
const isWFDisabled = useMemo(() => layoutMode !== LayoutModes.Update || fetchError || (workItems.length <= 0 && workItemsForDiagram.length <= 0), [layoutMode, fetchError, workItems.length, workItemsForDiagram.length]);
|
|
587
638
|
const showToppyForApprove = useMemo(() => layoutMode === LayoutModes.Update && !fetchError && workItems.length > 0 && !isOpenDetails && !isOpenMaster, [layoutMode, fetchError, workItems.length, isOpenDetails, isOpenMaster]);
|
|
588
639
|
const showToppyForCompleteMoreInfo = useMemo(() => layoutMode === LayoutModes.Update && !!isTaskMoreInfo(taskMoreInfo?.name) && taskMoreInfo?.state !== Task_States.Completed, [layoutMode, taskMoreInfo?.name, taskMoreInfo?.state]);
|
|
589
640
|
const showToppyForReferences = useMemo(() => allowButtonsRefs && layoutMode === LayoutModes.Update && !!(dcmtReferences && dcmtReferences.length > 0) && !isOpenDetails && !isOpenMaster, [allowButtonsRefs, layoutMode, dcmtReferences, isOpenDetails, isOpenMaster]);
|
|
@@ -1215,7 +1266,7 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
|
|
|
1215
1266
|
const isAuthorized = !!workflows?.[0]?.diagram;
|
|
1216
1267
|
return (_jsxs("div", { style: { position: 'relative', width: '100%', height: '100%', display: 'flex', flexDirection: 'column', gap: 3 }, children: [workItems.length > 0
|
|
1217
1268
|
? (isAuthorized
|
|
1218
|
-
? _jsx(WFDiagram, { xmlDiagramString: workflows?.[0]?.diagram || '', allowEdit: false, currentSetID: workitemSetID })
|
|
1269
|
+
? _jsx(WFDiagram, { xmlDiagramString: workflows?.[0]?.diagram || '', allowEdit: false, currentSetID: workitemSetID, defaultAutoZoom: true, workitems: workItemsForDiagram })
|
|
1219
1270
|
: _jsx("div", { style: {
|
|
1220
1271
|
position: 'absolute',
|
|
1221
1272
|
top: '50%',
|
|
@@ -1259,7 +1310,7 @@ const TMDcmtForm = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTa
|
|
|
1259
1310
|
backgroundColor: 'khaki',
|
|
1260
1311
|
borderRadius: 8
|
|
1261
1312
|
}, children: SDKUI_Localizator.WorkItemTechnicalNote_SetID })] }));
|
|
1262
|
-
}, [workflows, formData, workitemSetID, workItems, isWFDataLoading]);
|
|
1313
|
+
}, [workflows, formData, workitemSetID, workItems, workItemsForDiagram, isWFDataLoading, wfError, isMobile]);
|
|
1263
1314
|
const tmDcmtTasks = useMemo(() => {
|
|
1264
1315
|
const isReady = TID && DID && getAllTasks && deleteTaskByIdsCallback && addTaskCallback && editTaskCallback;
|
|
1265
1316
|
if (!isReady) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { TaskDescriptor } from "@topconsultnpm/sdk-ts";
|
|
3
3
|
import { FormModes } from "../../../ts";
|
|
4
|
+
import { TMContextMenuItemProps } from "../../NewComponents/ContextMenu";
|
|
4
5
|
interface TMTasksAgendaProps {
|
|
5
6
|
id: string;
|
|
6
7
|
showId: boolean;
|
|
@@ -12,6 +13,7 @@ interface TMTasksAgendaProps {
|
|
|
12
13
|
setCurrentAgendaDate: React.Dispatch<React.SetStateAction<Date>>;
|
|
13
14
|
openTaskForm: (formMode: FormModes, task?: TaskDescriptor) => void;
|
|
14
15
|
handleFocusedRowChange: (row: TaskDescriptor | undefined) => void;
|
|
16
|
+
menuItems: TMContextMenuItemProps[];
|
|
15
17
|
}
|
|
16
|
-
declare const TMTasksAgenda:
|
|
18
|
+
declare const TMTasksAgenda: (props: TMTasksAgendaProps) => import("react/jsx-runtime").JSX.Element;
|
|
17
19
|
export default TMTasksAgenda;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { jsxs as _jsxs,
|
|
2
|
-
import React, { useCallback, useEffect, useState } from "react";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
3
|
import ArrayStore from "devextreme/data/array_store";
|
|
4
4
|
import Scheduler from "devextreme-react/scheduler";
|
|
5
5
|
import { calculateNumberOfDays, highlightTaskText, priorityLegend, renderTaskIcons } from "./TMTasksUtilsView";
|
|
@@ -11,14 +11,31 @@ import { FormModes } from "../../../ts";
|
|
|
11
11
|
import { SDKUI_Localizator } from "../../../helper";
|
|
12
12
|
import TMCustomSearchBar from "../../../helper/TMCustomSearchBar";
|
|
13
13
|
import TMTooltip from "../../base/TMTooltip";
|
|
14
|
-
|
|
14
|
+
import TMContextMenu from "../../NewComponents/ContextMenu/TMContextMenu";
|
|
15
|
+
const MemoizedScheduler = React.memo(({ dataSource, currentAgendaDate, appointmentRender, onAppointmentDblClick, onCurrentDateChange, onAppointmentContextMenu, onAppointmentClick }) => {
|
|
15
16
|
const views = ['agenda'];
|
|
16
|
-
|
|
17
|
+
return (_jsx(Scheduler, { id: "tasks-agenda", defaultCurrentView: "agenda", dataSource: dataSource, width: "100%", height: "100%", editing: false, views: views, currentDate: currentAgendaDate, appointmentRender: appointmentRender, onAppointmentDblClick: onAppointmentDblClick, onCurrentDateChange: onCurrentDateChange, onAppointmentContextMenu: onAppointmentContextMenu, onAppointmentClick: onAppointmentClick }));
|
|
18
|
+
});
|
|
19
|
+
const TMTasksAgenda = (props) => {
|
|
20
|
+
const { id, showId, showSearch, visualizedTasks, fromCell, toCell, currentAgendaDate, setCurrentAgendaDate, openTaskForm, handleFocusedRowChange, menuItems } = props;
|
|
17
21
|
const [schedulerData, setSchedulerData] = useState([]);
|
|
18
22
|
const [loading, setLoading] = useState(false);
|
|
19
23
|
const [searchText, setSearchText] = useState('');
|
|
24
|
+
const [contextMenuVisible, setContextMenuVisible] = useState(false);
|
|
25
|
+
const [contextMenuPosition, setContextMenuPosition] = useState({ x: 0, y: 0 });
|
|
26
|
+
const prevTasksRef = useRef({ length: 0 });
|
|
20
27
|
useEffect(() => {
|
|
21
|
-
|
|
28
|
+
const currentSignature = {
|
|
29
|
+
length: visualizedTasks.length,
|
|
30
|
+
firstId: visualizedTasks[0]?.id,
|
|
31
|
+
lastId: visualizedTasks[visualizedTasks.length - 1]?.id
|
|
32
|
+
};
|
|
33
|
+
if (prevTasksRef.current.length !== currentSignature.length ||
|
|
34
|
+
prevTasksRef.current.firstId !== currentSignature.firstId ||
|
|
35
|
+
prevTasksRef.current.lastId !== currentSignature.lastId) {
|
|
36
|
+
prevTasksRef.current = currentSignature;
|
|
37
|
+
setSchedulerData(convertToSchedulerAppointments(visualizedTasks));
|
|
38
|
+
}
|
|
22
39
|
}, [visualizedTasks]);
|
|
23
40
|
useEffect(() => {
|
|
24
41
|
let timeoutId;
|
|
@@ -74,13 +91,16 @@ const TMTasksAgenda = React.memo((props) => {
|
|
|
74
91
|
if (e === undefined || e.event === undefined || e.appointmentData.id === undefined)
|
|
75
92
|
return;
|
|
76
93
|
e.event.preventDefault();
|
|
94
|
+
e.event.stopPropagation();
|
|
77
95
|
const { id } = e.appointmentData;
|
|
78
|
-
// Update the state with the new set of selected appointments
|
|
79
96
|
const task = visualizedTasks.find(task => task.id === id);
|
|
80
97
|
if (task) {
|
|
81
98
|
handleFocusedRowChange(task);
|
|
82
99
|
}
|
|
83
|
-
|
|
100
|
+
const event = e.event;
|
|
101
|
+
setContextMenuPosition({ x: event.clientX, y: event.clientY });
|
|
102
|
+
setContextMenuVisible(true);
|
|
103
|
+
}, [visualizedTasks, handleFocusedRowChange]);
|
|
84
104
|
const onCurrentDateChange = useCallback((value) => {
|
|
85
105
|
// Exit early if it's not a valid Date
|
|
86
106
|
if (!(value instanceof Date) || isNaN(value.getTime())) {
|
|
@@ -101,7 +121,26 @@ const TMTasksAgenda = React.memo((props) => {
|
|
|
101
121
|
openTaskForm(FormModes.Update, task);
|
|
102
122
|
}
|
|
103
123
|
}, [visualizedTasks]);
|
|
124
|
+
const handleWrapperContextMenu = useCallback((e) => {
|
|
125
|
+
handleFocusedRowChange(undefined);
|
|
126
|
+
setContextMenuPosition({ x: e.clientX, y: e.clientY });
|
|
127
|
+
setContextMenuVisible(true);
|
|
128
|
+
}, [handleFocusedRowChange]);
|
|
129
|
+
const handleCloseContextMenu = useCallback(() => {
|
|
130
|
+
setContextMenuVisible(false);
|
|
131
|
+
}, []);
|
|
132
|
+
const dataSourceRef = useRef(new ArrayStore({ key: `tasks-agenda-data`, data: schedulerData }));
|
|
133
|
+
const dataLengthRef = useRef(0);
|
|
134
|
+
if (dataLengthRef.current !== schedulerData.length) {
|
|
135
|
+
dataLengthRef.current = schedulerData.length;
|
|
136
|
+
dataSourceRef.current = new ArrayStore({ key: `tasks-agenda-data`, data: schedulerData });
|
|
137
|
+
}
|
|
138
|
+
const memoizedDataSource = useMemo(() => dataSourceRef.current, [schedulerData.length]);
|
|
104
139
|
return _jsxs("div", { style: { height: "100%", width: "100%" }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '100%', height: "48px" }, children: [_jsx("div", { style: { width: showSearch ? "160px" : "0", marginLeft: '10px' }, children: showSearch && (_jsx(TMCustomSearchBar, { initialValue: searchText, onSearchChange: (value) => setSearchText(value) })) }), _jsx("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: "default" }, children: _jsxs(TMTooltip, { content: priorityLegend(), children: [" ", SDKUI_Localizator.PriorityLegend] }) })] }), _jsx("div", { style: { height: "calc(100% - 48px)", width: "100%" }, children: loading ? _jsx("div", { style: { display: "flex", justifyContent: "center", alignItems: "center", height: "100%", width: "100%" }, children: _jsx(LoadIndicator, {}) })
|
|
105
|
-
:
|
|
106
|
-
|
|
140
|
+
: _jsxs(_Fragment, { children: [_jsx(TMContextMenu, { items: menuItems, externalControl: {
|
|
141
|
+
visible: contextMenuVisible,
|
|
142
|
+
position: contextMenuPosition,
|
|
143
|
+
onClose: handleCloseContextMenu
|
|
144
|
+
} }), _jsx("div", { id: `tasks-agenda-wrapper-${id}`, style: { width: "100%", height: "100%" }, onContextMenu: handleWrapperContextMenu, children: _jsx(MemoizedScheduler, { dataSource: memoizedDataSource, currentAgendaDate: currentAgendaDate, appointmentRender: appointmentRender, onAppointmentDblClick: handleAppointmentDblClick, onCurrentDateChange: onCurrentDateChange, onAppointmentContextMenu: onAppointmentContextMenu, onAppointmentClick: handleAppointmentClick }) })] }) })] });
|
|
145
|
+
};
|
|
107
146
|
export default TMTasksAgenda;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { TaskDescriptor } from "@topconsultnpm/sdk-ts";
|
|
3
3
|
import { FormModes } from '../../../ts';
|
|
4
|
+
import { TMContextMenuItemProps } from '../../NewComponents/ContextMenu/types';
|
|
4
5
|
interface TMTasksCalendarProps {
|
|
5
6
|
id: string;
|
|
6
7
|
visualizedTasks: Array<TaskDescriptor>;
|
|
@@ -16,6 +17,7 @@ interface TMTasksCalendarProps {
|
|
|
16
17
|
setCalendarEndDate: React.Dispatch<React.SetStateAction<Date | undefined>>;
|
|
17
18
|
focusedRowKey: number | undefined;
|
|
18
19
|
handleFocusedRowChange: (row: TaskDescriptor | undefined) => void;
|
|
20
|
+
menuItems: TMContextMenuItemProps[];
|
|
19
21
|
}
|
|
20
22
|
declare const TMTasksCalendar: (props: TMTasksCalendarProps) => import("react/jsx-runtime").JSX.Element;
|
|
21
23
|
export default TMTasksCalendar;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import ArrayStore from 'devextreme/data/array_store';
|
|
3
3
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
4
4
|
import { Priorities, Task_States } from "@topconsultnpm/sdk-ts";
|
|
@@ -10,13 +10,15 @@ import { FormModes } from '../../../ts';
|
|
|
10
10
|
import { SDKUI_Localizator } from '../../../helper';
|
|
11
11
|
import TMTooltip from '../../base/TMTooltip';
|
|
12
12
|
import TMCustomSearchBar from '../../../helper/TMCustomSearchBar';
|
|
13
|
+
import TMContextMenu from '../../NewComponents/ContextMenu/TMContextMenu';
|
|
13
14
|
const views = ['month'];
|
|
14
|
-
let clickTimeout = null;
|
|
15
|
+
let clickTimeout = null;
|
|
15
16
|
let clickCount = 0; // Click counter
|
|
16
17
|
let lastClickedCell = null;
|
|
17
18
|
const TMTasksCalendar = (props) => {
|
|
18
|
-
const { id, visualizedTasks, showId, showSearch, fromCell, toCell, openTaskForm, onDeleteCallback, currentCalendarDate, setCurrentCalendarDate, focusedRowKey, handleFocusedRowChange, setCalendarStartDate, setCalendarEndDate } = props;
|
|
19
|
+
const { id, visualizedTasks, showId, showSearch, fromCell, toCell, openTaskForm, onDeleteCallback, currentCalendarDate, setCurrentCalendarDate, focusedRowKey, handleFocusedRowChange, setCalendarStartDate, setCalendarEndDate, menuItems } = props;
|
|
19
20
|
const [isMobile, setIsMobile] = useState(false);
|
|
21
|
+
const [contextMenuControl, setContextMenuControl] = useState({ visible: false, position: { x: 0, y: 0 } });
|
|
20
22
|
const mobileBreakpoint = 768;
|
|
21
23
|
const [schedulerData, setSchedulerData] = useState([]);
|
|
22
24
|
const [isRange, setIsRange] = useState(false);
|
|
@@ -228,13 +230,23 @@ const TMTasksCalendar = (props) => {
|
|
|
228
230
|
}
|
|
229
231
|
}
|
|
230
232
|
};
|
|
231
|
-
const onWrapperContextMenu = useCallback(() => {
|
|
232
|
-
handleFocusedRowChange(undefined);
|
|
233
|
-
}, []);
|
|
234
233
|
const onWrapperClick = useCallback(() => {
|
|
235
234
|
handleFocusedRowChange(undefined);
|
|
236
235
|
}, []);
|
|
236
|
+
const handleWrapperContextMenu = useCallback((e) => {
|
|
237
|
+
setContextMenuControl({
|
|
238
|
+
visible: true,
|
|
239
|
+
position: { x: e.clientX, y: e.clientY }
|
|
240
|
+
});
|
|
241
|
+
}, []);
|
|
242
|
+
const handleCloseContextMenu = useCallback(() => {
|
|
243
|
+
setContextMenuControl(prev => ({ ...prev, visible: false }));
|
|
244
|
+
}, []);
|
|
237
245
|
return (_jsxs("div", { style: { width: "100%", height: "100%" }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '100%', height: "48px", padding: 5 }, children: [_jsx("div", { style: { width: showSearch ? "160px" : "0", marginLeft: '10px' }, children: showSearch && (_jsx(TMCustomSearchBar, { initialValue: searchText, onSearchChange: (value) => setSearchText(value) })) }), _jsx("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: "default" }, children: _jsx(TMTooltip, { content: priorityLegend(), children: SDKUI_Localizator.PriorityLegend }) })] }), _jsx("div", { style: { height: "calc(100% - 48px)", width: "100%" }, children: loading ? _jsx("div", { style: { display: "flex", justifyContent: "center", alignItems: "center", height: "100%", width: "100%" }, children: _jsx(LoadIndicator, {}) })
|
|
238
|
-
:
|
|
246
|
+
: _jsxs(_Fragment, { children: [_jsx(TMContextMenu, { items: menuItems, externalControl: {
|
|
247
|
+
visible: contextMenuControl.visible,
|
|
248
|
+
position: contextMenuControl.position,
|
|
249
|
+
onClose: handleCloseContextMenu
|
|
250
|
+
} }), _jsx("div", { id: `tasks-calendar-wrapper-${id}`, style: { width: "100%", height: "100%" }, onContextMenu: handleWrapperContextMenu, onClick: onWrapperClick, children: _jsx(Scheduler, { ref: schedulerRef, id: "tasks-calendar", dataSource: new ArrayStore({ key: 'tasks-calendar-data', data: schedulerData }), views: views, defaultCurrentView: "month", adaptivityEnabled: isMobile, editing: false, width: "100%", height: "100%", currentDate: currentCalendarDate, appointmentComponent: appointmentComponent, onAppointmentFormOpening: handleAppointmentFormOpening, appointmentTooltipComponent: appointmentTooltipComponent, onAppointmentDblClick: handleAppointmentDblClick, onCurrentDateChange: onCurrentCalendarDateChange, onAppointmentContextMenu: onAppointmentContextMenu, onCellContextMenu: onCellContextMenu, onCellClick: handleCellClick, onAppointmentClick: handleAppointmentClick, onContentReady: handleContentReady, onOptionChanged: onOptionChanged, children: _jsx(Resource, { dataSource: prioritiesResourceData, fieldExpr: "priority", label: "Priority" }) }) })] }) })] }));
|
|
239
251
|
};
|
|
240
252
|
export default TMTasksCalendar;
|
|
@@ -2,7 +2,7 @@ import { Appointment } from 'devextreme/ui/scheduler';
|
|
|
2
2
|
import { ContextMenuTypes } from 'devextreme-react/context-menu';
|
|
3
3
|
import { TaskDescriptor, Task_States, PdGs, Priorities, ValidationItem } from '@topconsultnpm/sdk-ts';
|
|
4
4
|
import { FormModes, TaskContext } from '../../../ts';
|
|
5
|
-
import {
|
|
5
|
+
import { TMContextMenuItemProps } from '../../NewComponents/ContextMenu';
|
|
6
6
|
export declare const TEXT_SELECTED_COLOR = "#ff5e1a";
|
|
7
7
|
export declare const BG_COLOR_INACTIVE_WIDGET = "#fff";
|
|
8
8
|
export declare const BG_COLOR_ACTIVE_WIDGET = "#fff0b7";
|
|
@@ -100,7 +100,7 @@ export declare const gotoPDGExtendedLabel: (gotoVisible: boolean, pdg: PdGs, iD1
|
|
|
100
100
|
export declare const convertToSchedulerAppointments: (tasks: Array<TaskDescriptor>) => Array<Appointment>;
|
|
101
101
|
export declare const formatDate: (date: Date) => string;
|
|
102
102
|
export declare const areDifferentIDs: (fromID: number | undefined, userID: number | undefined) => boolean;
|
|
103
|
-
export declare const createTasksMenuItems: (taskDescriptor: TaskDescriptor | undefined, showId: boolean, setShowId: React.Dispatch<React.SetStateAction<boolean>>, showSearch: boolean, setShowSearch: React.Dispatch<React.SetStateAction<boolean>>, openTaskForm: (formMode: FormModes, task?: TaskDescriptor, isContextual?: boolean) => void, openEditTaskForm: (rowId: number | undefined) => void, openDuplicateTaskForm: (rowId: number | undefined) => void, onDeleteCallback: (rowIds: Array<number>) => void, markAsStatus: (rowIds: Array<number>, status: Task_States) => void, getAllTasks: () => Promise<void>, fromWG: boolean, showContextualWG: boolean, setShowContextualWG: React.Dispatch<React.SetStateAction<boolean>>, fromDossier: boolean, showContextualDossier: boolean, setShowContextualDossier: React.Dispatch<React.SetStateAction<boolean>>, fromDocument: boolean, showContextualDocument: boolean, setShowContextualDocument: React.Dispatch<React.SetStateAction<boolean>>, showGoToToday: boolean, handleGoToToday?: () => void, fromDatagrid?: boolean) => Array<
|
|
103
|
+
export declare const createTasksMenuItems: (taskDescriptor: TaskDescriptor | undefined, showId: boolean, setShowId: React.Dispatch<React.SetStateAction<boolean>>, showSearch: boolean, setShowSearch: React.Dispatch<React.SetStateAction<boolean>>, openTaskForm: (formMode: FormModes, task?: TaskDescriptor, isContextual?: boolean) => void, openEditTaskForm: (rowId: number | undefined) => void, openDuplicateTaskForm: (rowId: number | undefined) => void, onDeleteCallback: (rowIds: Array<number>) => void, markAsStatus: (rowIds: Array<number>, status: Task_States) => void, getAllTasks: () => Promise<void>, fromWG: boolean, showContextualWG: boolean, setShowContextualWG: React.Dispatch<React.SetStateAction<boolean>>, fromDossier: boolean, showContextualDossier: boolean, setShowContextualDossier: React.Dispatch<React.SetStateAction<boolean>>, fromDocument: boolean, showContextualDocument: boolean, setShowContextualDocument: React.Dispatch<React.SetStateAction<boolean>>, showGoToToday: boolean, handleGoToToday?: () => void, fromDatagrid?: boolean) => Array<TMContextMenuItemProps>;
|
|
104
104
|
export declare const checkIfNew: (fromId: number | undefined, isNew: number | undefined) => boolean;
|
|
105
105
|
export declare const getNewTaskCount: (tasks: Array<TaskDescriptor>) => number;
|
|
106
106
|
export declare const isTaskAssignedToAnotherUser: (task: TaskDescriptor) => boolean;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
2
|
import { Task_States, PdGs, Priorities, ValidationItem, SDK_Localizator, ResultTypes, SDK_Globals } from '@topconsultnpm/sdk-ts';
|
|
2
3
|
import { TMColors } from '../../../utils/theme';
|
|
3
4
|
import { SDKUI_Localizator } from '../../../helper';
|
|
@@ -399,59 +400,65 @@ export const areDifferentIDs = (fromID, userID) => {
|
|
|
399
400
|
export const createTasksMenuItems = (taskDescriptor, showId, setShowId, showSearch, setShowSearch, openTaskForm, openEditTaskForm, openDuplicateTaskForm, onDeleteCallback, markAsStatus, getAllTasks, fromWG, showContextualWG, setShowContextualWG, fromDossier, showContextualDossier, setShowContextualDossier, fromDocument, showContextualDocument, setShowContextualDocument, showGoToToday, handleGoToToday, fromDatagrid = true) => {
|
|
400
401
|
const isTaskDescriptorDefined = taskDescriptor !== undefined;
|
|
401
402
|
const isTaskFromAnotherUser = isTaskDescriptorDefined && areDifferentIDs(taskDescriptor.fromID, SDK_Globals.tmSession?.SessionDescr?.userID);
|
|
403
|
+
const getRowIdsAsArray = (rowIds) => {
|
|
404
|
+
if (fromDatagrid) {
|
|
405
|
+
return Array.isArray(rowIds) ? rowIds : [rowIds];
|
|
406
|
+
}
|
|
407
|
+
return taskDescriptor?.id ? [taskDescriptor.id] : [];
|
|
408
|
+
};
|
|
402
409
|
const menuItems = [
|
|
403
410
|
{
|
|
404
411
|
id: 'createContextualTask',
|
|
405
|
-
|
|
406
|
-
icon:
|
|
412
|
+
name: SDKUI_Localizator.CreateContextualTask,
|
|
413
|
+
icon: _jsx("span", { className: "dx-icon-plus" }),
|
|
407
414
|
onClick: () => { openTaskForm(FormModes.Create, undefined, true); },
|
|
408
415
|
disabled: false
|
|
409
416
|
},
|
|
410
417
|
{
|
|
411
|
-
|
|
412
|
-
icon:
|
|
418
|
+
name: SDKUI_Localizator.Create,
|
|
419
|
+
icon: _jsx("span", { className: "dx-icon-plus" }),
|
|
413
420
|
onClick: () => { openTaskForm(FormModes.Create, undefined, false); },
|
|
414
421
|
disabled: false
|
|
415
422
|
},
|
|
416
423
|
{
|
|
417
|
-
|
|
418
|
-
icon:
|
|
419
|
-
onClick: openEditTaskForm,
|
|
424
|
+
name: SDKUI_Localizator.Update,
|
|
425
|
+
icon: _jsx("span", { className: "dx-icon-edit" }),
|
|
426
|
+
onClick: (rowId) => openEditTaskForm(fromDatagrid ? rowId : taskDescriptor?.id),
|
|
420
427
|
operationType: 'singleRow',
|
|
421
428
|
disabled: fromDatagrid ? false : !isTaskDescriptorDefined
|
|
422
429
|
},
|
|
423
430
|
{
|
|
424
|
-
|
|
425
|
-
icon:
|
|
426
|
-
onClick: openDuplicateTaskForm,
|
|
431
|
+
name: SDKUI_Localizator.Duplicate,
|
|
432
|
+
icon: _jsx("span", { className: "dx-icon-copy" }),
|
|
433
|
+
onClick: (rowId) => openDuplicateTaskForm(fromDatagrid ? rowId : taskDescriptor?.id),
|
|
427
434
|
operationType: 'singleRow',
|
|
428
435
|
disabled: fromDatagrid ? isTaskFromAnotherUser : !isTaskDescriptorDefined || isTaskFromAnotherUser
|
|
429
436
|
},
|
|
430
437
|
{
|
|
431
|
-
|
|
432
|
-
icon:
|
|
433
|
-
onClick: onDeleteCallback,
|
|
438
|
+
name: SDKUI_Localizator.Delete,
|
|
439
|
+
icon: _jsx("span", { className: "dx-icon-trash" }),
|
|
440
|
+
onClick: (rowIds) => onDeleteCallback(getRowIdsAsArray(rowIds)),
|
|
434
441
|
operationType: 'multiRow',
|
|
435
442
|
disabled: fromDatagrid ? isTaskFromAnotherUser : !isTaskDescriptorDefined || isTaskFromAnotherUser
|
|
436
443
|
},
|
|
437
444
|
{
|
|
438
|
-
icon:
|
|
439
|
-
|
|
445
|
+
icon: _jsx("span", { className: "dx-icon-optionsgear" }),
|
|
446
|
+
name: SDKUI_Localizator.MarkAs,
|
|
440
447
|
id: "markAs",
|
|
441
448
|
operationType: 'multiRow',
|
|
442
449
|
disabled: fromDatagrid ? false : !isTaskDescriptorDefined,
|
|
443
|
-
|
|
444
|
-
{ icon:
|
|
445
|
-
{ icon:
|
|
446
|
-
{ icon:
|
|
447
|
-
{ icon:
|
|
448
|
-
{ icon:
|
|
450
|
+
submenu: [
|
|
451
|
+
{ icon: _jsx("span", { className: "dx-icon-product" }), name: SDKUI_Localizator.NewFemale, operationType: 'multiRow', onClick: (rowIds) => markAsStatus(getRowIdsAsArray(rowIds), Task_States.NotStarted) },
|
|
452
|
+
{ icon: _jsx("span", { className: "dx-icon-refresh" }), name: SDKUI_Localizator.InProgress, operationType: 'multiRow', onClick: (rowIds) => markAsStatus(getRowIdsAsArray(rowIds), Task_States.InProgress) },
|
|
453
|
+
{ icon: _jsx("span", { className: "dx-icon-check" }), name: SDKUI_Localizator.Completed, operationType: 'multiRow', onClick: (rowIds) => markAsStatus(getRowIdsAsArray(rowIds), Task_States.Completed) },
|
|
454
|
+
{ icon: _jsx("span", { className: "dx-icon-taskstop" }), name: SDKUI_Localizator.Pending, operationType: 'multiRow', onClick: (rowIds) => markAsStatus(getRowIdsAsArray(rowIds), Task_States.Waiting) },
|
|
455
|
+
{ icon: _jsx("span", { className: "dx-icon-clock" }), name: SDKUI_Localizator.Postponed, operationType: 'multiRow', onClick: (rowIds) => markAsStatus(getRowIdsAsArray(rowIds), Task_States.Deferred) }
|
|
449
456
|
]
|
|
450
457
|
},
|
|
451
458
|
{
|
|
452
459
|
id: 'wgContextFilter',
|
|
453
|
-
|
|
454
|
-
icon:
|
|
460
|
+
name: showContextualWG ? SDKUI_Localizator.RemoveContextualFilter : SDKUI_Localizator.ApplyContextualFilter,
|
|
461
|
+
icon: _jsx("span", { className: "dx-icon-filter" }),
|
|
455
462
|
onClick: () => { setShowContextualWG(prev => !prev); },
|
|
456
463
|
disabled: false,
|
|
457
464
|
beginGroup: true,
|
|
@@ -459,8 +466,8 @@ export const createTasksMenuItems = (taskDescriptor, showId, setShowId, showSear
|
|
|
459
466
|
},
|
|
460
467
|
{
|
|
461
468
|
id: 'dossierContextFilter',
|
|
462
|
-
|
|
463
|
-
icon:
|
|
469
|
+
name: showContextualDossier ? SDKUI_Localizator.RemoveContextualFilter : SDKUI_Localizator.ApplyContextualFilter,
|
|
470
|
+
icon: _jsx("span", { className: "dx-icon-filter" }),
|
|
464
471
|
onClick: () => { setShowContextualDossier(prev => !prev); },
|
|
465
472
|
disabled: false,
|
|
466
473
|
beginGroup: !fromWG && !fromDocument,
|
|
@@ -468,38 +475,38 @@ export const createTasksMenuItems = (taskDescriptor, showId, setShowId, showSear
|
|
|
468
475
|
},
|
|
469
476
|
{
|
|
470
477
|
id: 'documentContextFilter',
|
|
471
|
-
|
|
472
|
-
icon:
|
|
478
|
+
name: showContextualDocument ? SDKUI_Localizator.RemoveContextualFilter : SDKUI_Localizator.ApplyContextualFilter,
|
|
479
|
+
icon: _jsx("span", { className: "dx-icon-filter" }),
|
|
473
480
|
onClick: () => { setShowContextualDocument(prev => !prev); },
|
|
474
481
|
disabled: false,
|
|
475
482
|
beginGroup: !fromDossier && !fromWG,
|
|
476
483
|
visible: fromDocument
|
|
477
484
|
},
|
|
478
485
|
{
|
|
479
|
-
icon: "event",
|
|
486
|
+
icon: _jsx("span", { className: "dx-icon-event" }),
|
|
480
487
|
onClick: () => { if (handleGoToToday) {
|
|
481
488
|
handleGoToToday();
|
|
482
489
|
} },
|
|
483
|
-
|
|
490
|
+
name: SDKUI_Localizator.GoToToday,
|
|
484
491
|
disabled: false,
|
|
485
492
|
beginGroup: true,
|
|
486
493
|
},
|
|
487
494
|
{
|
|
488
495
|
beginGroup: true,
|
|
489
|
-
icon: showSearch ? "eyeclose" : "eyeopen",
|
|
496
|
+
icon: showSearch ? _jsx("span", { className: "dx-icon-eyeclose" }) : _jsx("span", { className: "dx-icon-eyeopen" }),
|
|
490
497
|
onClick: () => setShowSearch(prevShowSearch => !prevShowSearch),
|
|
491
|
-
|
|
498
|
+
name: showSearch ? SDKUI_Localizator.HideSearch : SDKUI_Localizator.ShowSearch,
|
|
492
499
|
disabled: false
|
|
493
500
|
},
|
|
494
501
|
{
|
|
495
|
-
icon: showId ? "eyeclose" : "eyeopen",
|
|
502
|
+
icon: showId ? _jsx("span", { className: "dx-icon-eyeclose" }) : _jsx("span", { className: "dx-icon-eyeopen" }),
|
|
496
503
|
onClick: () => setShowId(prevShowId => !prevShowId),
|
|
497
|
-
|
|
504
|
+
name: showId ? SDKUI_Localizator.ID_Hide : SDKUI_Localizator.ID_Show,
|
|
498
505
|
disabled: false
|
|
499
506
|
},
|
|
500
507
|
{
|
|
501
|
-
|
|
502
|
-
icon:
|
|
508
|
+
name: SDKUI_Localizator.Refresh,
|
|
509
|
+
icon: _jsx("span", { className: "dx-icon-refresh" }),
|
|
503
510
|
onClick: () => getAllTasks(),
|
|
504
511
|
disabled: false,
|
|
505
512
|
},
|
|
@@ -529,7 +536,7 @@ export const createTasksMenuItems = (taskDescriptor, showId, setShowId, showSear
|
|
|
529
536
|
item.visible === undefined);
|
|
530
537
|
}
|
|
531
538
|
if (showGoToToday === false) {
|
|
532
|
-
filteredMenuItems = filteredMenuItems.filter(item => item.
|
|
539
|
+
filteredMenuItems = filteredMenuItems.filter(item => item.name !== SDKUI_Localizator.GoToToday);
|
|
533
540
|
}
|
|
534
541
|
return filteredMenuItems;
|
|
535
542
|
};
|
|
@@ -5,7 +5,6 @@ import { TabPanel, Item } from 'devextreme-react/tab-panel';
|
|
|
5
5
|
import { Priorities, ResultTypes, SDK_Globals, Task_States } from "@topconsultnpm/sdk-ts";
|
|
6
6
|
import { calculateNumberOfDays, renderTaskIcons } from "./TMTasksUtilsView";
|
|
7
7
|
import { getPriorityLocalizatorValue } from "../tasks/TMTasksUtils";
|
|
8
|
-
import ContextMenu from 'devextreme-react/context-menu';
|
|
9
8
|
import { calcResponsiveSizes, getExceptionMessage, SDKUI_Localizator, StyledTabItem, TMCountBadge } from "../../../helper";
|
|
10
9
|
import { useDeviceType } from "../../base/TMDeviceProvider";
|
|
11
10
|
import { FormModes } from "../../../ts";
|
|
@@ -85,8 +84,9 @@ const TMTasksView = (props) => {
|
|
|
85
84
|
onDeleteCallback([focusedRowKey]); }, (rowIds, status) => { if (focusedRowKey)
|
|
86
85
|
markAsStatus([focusedRowKey], status); }, getAllTasks, taskContext?.workingGroup?.id !== undefined, showContextualWG, setShowContextualWG, taskContext?.dossier?.id !== undefined, showContextualDossier, setShowContextualDossier, taskContext?.document?.tid !== undefined && taskContext?.document?.did !== undefined, showContextualDocument, setShowContextualDocument, true, () => { setCurrentCalendarDate(new Date()); setCurrentAgendaDate(new Date()); }, false),
|
|
87
86
|
];
|
|
88
|
-
}, [
|
|
87
|
+
}, [focusedRowKey, showId, showSearch, showContextualWG, showContextualDossier, taskContext]);
|
|
89
88
|
const [menuItems, setMenuItems] = useState(agendaCalendarItems());
|
|
89
|
+
const [datagridMenu, setDatagridMenu] = useState([]);
|
|
90
90
|
const newTaskCount = getNewTaskCount(allTasks);
|
|
91
91
|
useEffect(() => {
|
|
92
92
|
setMenuItems(agendaCalendarItems());
|
|
@@ -266,6 +266,23 @@ const TMTasksView = (props) => {
|
|
|
266
266
|
}
|
|
267
267
|
});
|
|
268
268
|
}, [visualizedTasks]);
|
|
269
|
+
const listMenuItems = useCallback(() => {
|
|
270
|
+
const taskDescriptor = visualizedTasks.find(task => task.id === focusedRowKey);
|
|
271
|
+
return createTasksMenuItems(taskDescriptor, showId, setShowId, showSearch, setShowSearch, openTaskFormCallback, (rowId) => { if (rowId) {
|
|
272
|
+
const task = visualizedTasks.find(t => t.id === rowId);
|
|
273
|
+
if (task)
|
|
274
|
+
openTaskFormCallback(FormModes.Update, task);
|
|
275
|
+
} }, (rowId) => { if (rowId) {
|
|
276
|
+
const task = visualizedTasks.find(t => t.id === rowId);
|
|
277
|
+
if (task)
|
|
278
|
+
openTaskFormCallback(FormModes.Duplicate, task);
|
|
279
|
+
} }, onDeleteCallback, markAsStatus, getAllTasks, taskContext?.workingGroup?.id !== undefined, showContextualWG, setShowContextualWG, taskContext?.dossier?.id !== undefined, showContextualDossier, setShowContextualDossier, taskContext?.document?.tid !== undefined && taskContext?.document?.did !== undefined, showContextualDocument, setShowContextualDocument, false, // showGoToToday
|
|
280
|
+
undefined, true // fromDatagrid
|
|
281
|
+
);
|
|
282
|
+
}, [visualizedTasks, focusedRowKey, showId, showSearch, showContextualWG, showContextualDossier, showContextualDocument, taskContext, openTaskFormCallback, onDeleteCallback, markAsStatus, getAllTasks]);
|
|
283
|
+
useEffect(() => {
|
|
284
|
+
setDatagridMenu(listMenuItems());
|
|
285
|
+
}, [listMenuItems]);
|
|
269
286
|
const onSavedCallback = async (task) => {
|
|
270
287
|
// If task is undefined or has no ID, exit early
|
|
271
288
|
if (task === undefined || task.id === undefined)
|
|
@@ -295,22 +312,14 @@ const TMTasksView = (props) => {
|
|
|
295
312
|
}
|
|
296
313
|
setShowTaskForm(false);
|
|
297
314
|
};
|
|
298
|
-
const handleNavigateToDossiersWrapper = useCallback(async (
|
|
315
|
+
const handleNavigateToDossiersWrapper = useCallback(async (value) => {
|
|
299
316
|
setShowTaskForm(false);
|
|
300
|
-
await handleNavigateToDossiers(
|
|
317
|
+
await handleNavigateToDossiers(value);
|
|
301
318
|
}, [handleNavigateToDossiers]);
|
|
302
|
-
const handleNavigateToWGsWrapper = useCallback(async (
|
|
319
|
+
const handleNavigateToWGsWrapper = useCallback(async (value) => {
|
|
303
320
|
setShowTaskForm(false);
|
|
304
|
-
await handleNavigateToWGs(
|
|
321
|
+
await handleNavigateToWGs(value);
|
|
305
322
|
}, [handleNavigateToWGs]);
|
|
306
|
-
const onContextMenuPreparing = (e) => {
|
|
307
|
-
if (e === undefined)
|
|
308
|
-
return;
|
|
309
|
-
if (e.target === 'content') {
|
|
310
|
-
e.items = e.items || [];
|
|
311
|
-
e.items = createTasksMenuItems(e.row?.data, showId, setShowId, showSearch, setShowSearch, openTaskFormCallback, () => { openTaskFormCallback(FormModes.Update, e.row?.data); }, () => { openTaskFormCallback(FormModes.Duplicate, e.row?.data); }, onDeleteCallback, markAsStatus, getAllTasks, taskContext?.workingGroup?.id !== undefined, showContextualWG, setShowContextualWG, taskContext?.dossier?.id !== undefined, showContextualDossier, setShowContextualDossier, taskContext?.document?.tid !== undefined && taskContext?.document?.did !== undefined, showContextualDocument, setShowContextualDocument, false);
|
|
312
|
-
}
|
|
313
|
-
};
|
|
314
323
|
const RenderCustomHeader = ({ data }) => { return _jsx("p", { style: { color: TEXT_NOT_SELECTED_COLOR }, children: data.column.caption }); };
|
|
315
324
|
const cellDefaultRender = useCallback((cellData) => {
|
|
316
325
|
const data = cellData.data;
|
|
@@ -519,13 +528,13 @@ const TMTasksView = (props) => {
|
|
|
519
528
|
];
|
|
520
529
|
}, [showId]);
|
|
521
530
|
const getFromOrToDatagridElement = (fromOrToDataSource, fromCell = false, toCell = false) => {
|
|
522
|
-
return _jsx(TMDataGrid, { dataSource: fromOrToDataSource, dataColumns: getDataColumns(fromCell, toCell), selection: { mode: 'multiple', showCheckBoxesMode: "always" }, focusedRowKey: focusedRowKey, selectedRowKeys: [...selectedRowKeys], onFocusedRowChanged: onFocusedRowChanged, onSelectionChanged: onSelectionChanged, onRowDblClick: onRowDblClick,
|
|
531
|
+
return _jsx(TMDataGrid, { dataSource: fromOrToDataSource, dataColumns: getDataColumns(fromCell, toCell), selection: { mode: 'multiple', showCheckBoxesMode: "always" }, focusedRowKey: focusedRowKey, selectedRowKeys: [...selectedRowKeys], onFocusedRowChanged: onFocusedRowChanged, onSelectionChanged: onSelectionChanged, onRowDblClick: onRowDblClick, customContextMenuItems: datagridMenu, showSearchPanel: showSearch, noDataText: SDKUI_Localizator.TasksEmpty, counterConfig: { show: true }, onHasFiltersChange: (active) => setHasFilters(active) });
|
|
523
532
|
};
|
|
524
533
|
const getFromOrToAgendaElement = (fromOrToDataSource, fromCell = false, toCell = false) => {
|
|
525
|
-
return
|
|
534
|
+
return _jsx("div", { style: { width: '100%', height: '100%', display: 'flex', flexDirection: 'column', overflow: "auto" }, children: _jsx("div", { style: { width: "100%", height: "100%" }, children: _jsx(TMTasksAgenda, { id: id, showId: showId, showSearch: showSearch, visualizedTasks: fromOrToDataSource, fromCell: fromCell, toCell: toCell, currentAgendaDate: currentAgendaDate, setCurrentAgendaDate: setCurrentAgendaDate, openTaskForm: openTaskFormCallback, handleFocusedRowChange: handleFocusedRowChange, menuItems: menuItems }) }) });
|
|
526
535
|
};
|
|
527
536
|
const getFromOrToCalendarElement = (fromOrToDataSource, fromCell = false, toCell = false) => {
|
|
528
|
-
return
|
|
537
|
+
return _jsx("div", { style: { width: '100%', height: '100%', display: 'flex', flexDirection: 'column', overflow: "auto" }, children: _jsx("div", { style: { width: "100%", height: "100%" }, children: _jsx(TMTasksCalendar, { id: id, visualizedTasks: fromOrToDataSource, showId: showId, fromCell: fromCell, toCell: toCell, showSearch: showSearch, currentCalendarDate: currentCalendarDate, setCurrentCalendarDate: setCurrentCalendarDate, openTaskForm: openTaskFormCallback, onDeleteCallback: onDeleteCallback, setCalendarStartDate: setCalendarStartDate, setCalendarEndDate: setCalendarEndDate, focusedRowKey: focusedRowKey, handleFocusedRowChange: handleFocusedRowChange, menuItems: menuItems }) }) });
|
|
529
538
|
};
|
|
530
539
|
return _jsxs("div", { style: { width: '100%', height: '100%' }, onContextMenu: (e) => e.preventDefault(), children: [_jsx(TMLayoutWaitingContainer, { direction: 'vertical', showWaitPanel: showWaitPanel, showWaitPanelPrimary: showPrimary, waitPanelTitle: waitPanelTitle, waitPanelTextPrimary: waitPanelTextPrimary, waitPanelValuePrimary: waitPanelValuePrimary, waitPanelMaxValuePrimary: waitPanelMaxValuePrimary, isCancelable: true, abortController: abortController, children: _jsxs(TabPanel, { width: "100%", height: "100%", animationEnabled: false, swipeEnabled: false, loop: false, showNavButtons: true, repaintChangesOnly: true, stylingMode: "primary", iconPosition: 'start', tabsPosition: 'top', selectedIndex: activeTabIndex, onSelectedIndexChange: onSelectedIndexChange, id: "task-centered-tab-title", children: [_jsx(Item, { title: SDKUI_Localizator.AssignedToMe, icon: "user", tabRender: (params) => {
|
|
531
540
|
return _jsxs(StyledTabItem, { "$isSelected": activeTabIndex === AssignedTab.AssignedToMe, children: [_jsxs(TMTooltip, { content: SDKUI_Localizator.AssignedToMe, children: [_jsx("i", { className: `dx-icon-${params.icon}` }), "\u00A0", params.title, " ", (assignedToMeCount > 0) ? `(${assignedToMeCount})` : ''] }), newTaskCount > 0 && (_jsx(TMTooltip, { content: SDKUI_Localizator.NewAssignedActivitiesNumber + ": " + newTaskCount, children: _jsx(TMCountBadge, { children: newTaskCount }) }))] });
|
package/lib/helper/index.d.ts
CHANGED
package/lib/helper/index.js
CHANGED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { IWorkItemData, WFInstanceDescriptor } from '../ts';
|
|
2
|
+
/**
|
|
3
|
+
* Helper function per costruire IWorkItemData da un WFInstanceDescriptor
|
|
4
|
+
* Effettua le chiamate API necessarie e popola tutti i campi disponibili
|
|
5
|
+
*/
|
|
6
|
+
export declare const buildWorkItemsFromWFCtrl: (wfInstance: WFInstanceDescriptor) => Promise<IWorkItemData[]>;
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { SDK_Globals, WorkItemMetadataNames, SystemDataListIDs } from '@topconsultnpm/sdk-ts';
|
|
2
|
+
import { WorkflowCacheService, DataListCacheService, UserListCacheService, DcmtTypeListCacheService } from '@topconsultnpm/sdk-ts';
|
|
3
|
+
import { parseWfDiagramXml } from '../components/features/workflow/diagram/xmlParser';
|
|
4
|
+
/**
|
|
5
|
+
* Helper function per costruire IWorkItemData da un WFInstanceDescriptor
|
|
6
|
+
* Effettua le chiamate API necessarie e popola tutti i campi disponibili
|
|
7
|
+
*/
|
|
8
|
+
export const buildWorkItemsFromWFCtrl = async (wfInstance) => {
|
|
9
|
+
const { wfid, tid: mtid, did: mdid, instanceId } = wfInstance;
|
|
10
|
+
if (!wfid || !mtid || !mdid) {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
// Recupera il workflow descriptor
|
|
14
|
+
const workflow = await WorkflowCacheService.GetWFCtrlInfoAsync(wfid);
|
|
15
|
+
// Recupera tutti i work items per questo workflow usando WFCtrl_RetrieveAllWIsAsync
|
|
16
|
+
const workItemsResult = await SDK_Globals.tmSession?.NewWorkflowEngine().WFCtrl_RetrieveAllWIsAsync(wfid, mtid, mdid, instanceId);
|
|
17
|
+
// Se non ci sono work items, restituisci array vuoto
|
|
18
|
+
if (!workItemsResult || workItemsResult.dcmtsFound === 0 || !workItemsResult.dtdResult?.rows) {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
// Recupera la DataList degli stati del workflow
|
|
22
|
+
const dldStatus = await DataListCacheService.GetAsync(SystemDataListIDs.WIStates);
|
|
23
|
+
// Parse del diagramma del workflow per ottenere type e name dai diagramItems
|
|
24
|
+
let wfDiagram;
|
|
25
|
+
if (workflow?.diagram) {
|
|
26
|
+
try {
|
|
27
|
+
wfDiagram = parseWfDiagramXml(workflow.diagram);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.warn('Errore nel parsing del diagramma workflow:', error);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Recupera il DTD per ottenere i MID dai nomi dei metadati
|
|
34
|
+
const dtd = await DcmtTypeListCacheService.GetAsync(workItemsResult.fromTID);
|
|
35
|
+
if (!dtd?.metadata) {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
// Crea una mappa nome metadato -> MID
|
|
39
|
+
const metadataNameToMID = {};
|
|
40
|
+
for (const meta of dtd.metadata) {
|
|
41
|
+
if (meta.name) {
|
|
42
|
+
metadataNameToMID[meta.name] = meta.id;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const columns = workItemsResult.dtdResult.columns || [];
|
|
46
|
+
// Funzione helper per trovare l'indice di una colonna tramite MID
|
|
47
|
+
const findColumnIndexByMID = (mid) => {
|
|
48
|
+
if (mid === -1)
|
|
49
|
+
return -1;
|
|
50
|
+
return columns.findIndex(col => col.extendedProperties?.MID === mid.toString());
|
|
51
|
+
};
|
|
52
|
+
// Mappa degli indici delle colonne usando MID
|
|
53
|
+
const columnIndices = {
|
|
54
|
+
tid: 0, // TID è sempre il primo
|
|
55
|
+
did: 1, // DID è sempre il secondo
|
|
56
|
+
setID: findColumnIndexByMID(metadataNameToMID[WorkItemMetadataNames.WI_SetID] ?? -1),
|
|
57
|
+
creationTime: findColumnIndexByMID(metadataNameToMID[WorkItemMetadataNames.WI_CreationTime] ?? -1),
|
|
58
|
+
response: findColumnIndexByMID(metadataNameToMID[WorkItemMetadataNames.WI_Response] ?? -1),
|
|
59
|
+
completionTime: findColumnIndexByMID(metadataNameToMID[WorkItemMetadataNames.WI_CompletionTime] ?? -1),
|
|
60
|
+
from: findColumnIndexByMID(metadataNameToMID[WorkItemMetadataNames.WI_From] ?? -1),
|
|
61
|
+
to: findColumnIndexByMID(metadataNameToMID[WorkItemMetadataNames.WI_To] ?? -1),
|
|
62
|
+
or: findColumnIndexByMID(metadataNameToMID[WorkItemMetadataNames.WI_Or] ?? -1),
|
|
63
|
+
status: findColumnIndexByMID(metadataNameToMID[WorkItemMetadataNames.WI_Status] ?? -1),
|
|
64
|
+
category: findColumnIndexByMID(metadataNameToMID[WorkItemMetadataNames.WI_Category] ?? -1),
|
|
65
|
+
description: findColumnIndexByMID(metadataNameToMID[WorkItemMetadataNames.WI_Description] ?? -1),
|
|
66
|
+
setStatus: findColumnIndexByMID(metadataNameToMID[WorkItemMetadataNames.WI_SetStatus] ?? -1),
|
|
67
|
+
setRule: findColumnIndexByMID(metadataNameToMID[WorkItemMetadataNames.WI_SetRule] ?? -1),
|
|
68
|
+
};
|
|
69
|
+
// Crea i WorkItemDetail
|
|
70
|
+
const details = [];
|
|
71
|
+
for (let i = 0; i < workItemsResult.dtdResult.rows.length; i++) {
|
|
72
|
+
const row = workItemsResult.dtdResult.rows[i];
|
|
73
|
+
const tid = Number(row[columnIndices.tid]);
|
|
74
|
+
const did = Number(row[columnIndices.did]);
|
|
75
|
+
const setID = columnIndices.setID !== -1 ? row[columnIndices.setID] : '';
|
|
76
|
+
const toUserID = columnIndices.to !== -1 ? Number(row[columnIndices.to]) : undefined;
|
|
77
|
+
// Risolvi l'utente usando la cache
|
|
78
|
+
let toUser = undefined;
|
|
79
|
+
if (toUserID !== undefined) {
|
|
80
|
+
try {
|
|
81
|
+
toUser = await UserListCacheService.GetAsync(toUserID);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
console.warn(`Impossibile recuperare l'utente con ID ${toUserID}:`, error);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Calcola lo status come DataListItemDescriptor
|
|
88
|
+
let statusItem = undefined;
|
|
89
|
+
if (columnIndices.status !== -1) {
|
|
90
|
+
const rawStatusValue = row[columnIndices.status];
|
|
91
|
+
if (rawStatusValue !== undefined && rawStatusValue !== null && dldStatus?.items) {
|
|
92
|
+
statusItem = dldStatus.items.find(item => item.value === rawStatusValue);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
details.push({
|
|
96
|
+
wid: `${tid}_${did}`,
|
|
97
|
+
tid,
|
|
98
|
+
did,
|
|
99
|
+
wfid: workflow?.id ?? 0,
|
|
100
|
+
approvalVID: workflow?.approvalVID ?? 0,
|
|
101
|
+
setID,
|
|
102
|
+
creationTime: columnIndices.creationTime !== -1 && row[columnIndices.creationTime]
|
|
103
|
+
? new Date(row[columnIndices.creationTime])
|
|
104
|
+
: undefined,
|
|
105
|
+
response: columnIndices.response !== -1 ? row[columnIndices.response] : undefined,
|
|
106
|
+
completionTime: columnIndices.completionTime !== -1 && row[columnIndices.completionTime]
|
|
107
|
+
? new Date(row[columnIndices.completionTime])
|
|
108
|
+
: undefined,
|
|
109
|
+
from: columnIndices.from !== -1 ? Number(row[columnIndices.from]) : undefined,
|
|
110
|
+
to: toUserID,
|
|
111
|
+
toUser: toUser,
|
|
112
|
+
or: columnIndices.or !== -1 ? Number(row[columnIndices.or]) : undefined,
|
|
113
|
+
status: statusItem,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
// Raggruppa per setID considerando il creationTime e setStatus
|
|
117
|
+
// Ordiniamo tutti i details per creationTime (ordine cronologico)
|
|
118
|
+
const sortedAllDetails = [...details].sort((a, b) => {
|
|
119
|
+
if (!a.creationTime || !b.creationTime)
|
|
120
|
+
return 0;
|
|
121
|
+
return a.creationTime.getTime() - b.creationTime.getTime();
|
|
122
|
+
});
|
|
123
|
+
// Crea una mappa detail -> setStatus per avere accesso al setStatus di ogni detail
|
|
124
|
+
const detailSetStatusMap = new Map();
|
|
125
|
+
for (const detail of details) {
|
|
126
|
+
const row = workItemsResult.dtdResult?.rows?.find(r => Number(r[columnIndices.tid]) === detail.tid &&
|
|
127
|
+
Number(r[columnIndices.did]) === detail.did);
|
|
128
|
+
if (row && columnIndices.setStatus !== -1) {
|
|
129
|
+
const setStatusValue = row[columnIndices.setStatus];
|
|
130
|
+
detailSetStatusMap.set(detail, setStatusValue?.toString() ?? '');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Logica di raggruppamento sequenziale dei workitems:
|
|
135
|
+
*
|
|
136
|
+
* Regole:
|
|
137
|
+
* 1. Primo workitem o SetID diverso => Nuovo step
|
|
138
|
+
* - Se SetStatus = "0" (Nuovo): attiva modalità aggregazione per tutti i successivi
|
|
139
|
+
*
|
|
140
|
+
* 2. Stesso SetID del precedente:
|
|
141
|
+
* - In modalità aggregazione (SetStatus = "0"): aggrega sempre nello stesso step
|
|
142
|
+
* - SetStatus != "0": raggruppa per stesso SetStatus
|
|
143
|
+
* - Stesso SetStatus => aggrega
|
|
144
|
+
* - SetStatus diverso => nuovo step
|
|
145
|
+
* - SetStatus = "0": nuovo step e attiva modalità aggregazione
|
|
146
|
+
*/
|
|
147
|
+
const groups = [];
|
|
148
|
+
let previousSetID = undefined;
|
|
149
|
+
let previousSetStatus = undefined;
|
|
150
|
+
let isInNewStatusMode = false;
|
|
151
|
+
for (const detail of sortedAllDetails) {
|
|
152
|
+
const currentSetStatus = detailSetStatusMap.get(detail) ?? '';
|
|
153
|
+
const currentSetID = detail.setID;
|
|
154
|
+
if (previousSetID === undefined || currentSetID !== previousSetID) {
|
|
155
|
+
// Nuovo SetID: crea nuovo step
|
|
156
|
+
groups.push([detail]);
|
|
157
|
+
previousSetID = currentSetID;
|
|
158
|
+
previousSetStatus = currentSetStatus;
|
|
159
|
+
isInNewStatusMode = currentSetStatus === '0';
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
// Stesso SetID
|
|
163
|
+
if (isInNewStatusMode) {
|
|
164
|
+
// Modalità aggregazione attiva: aggrega sempre
|
|
165
|
+
groups[groups.length - 1].push(detail);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
if (currentSetStatus === '0') {
|
|
169
|
+
// SetStatus "Nuovo": nuovo step e attiva modalità aggregazione
|
|
170
|
+
groups.push([detail]);
|
|
171
|
+
isInNewStatusMode = true;
|
|
172
|
+
previousSetStatus = currentSetStatus;
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
// SetStatus diverso da "Nuovo": raggruppa per stesso SetStatus
|
|
176
|
+
if (currentSetStatus !== previousSetStatus) {
|
|
177
|
+
groups.push([detail]);
|
|
178
|
+
previousSetStatus = currentSetStatus;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
groups[groups.length - 1].push(detail);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Crea IWorkItemData per ogni gruppo con tutti i campi disponibili
|
|
188
|
+
const finalWorkItems = groups.map((groupDetails, groupIndex) => {
|
|
189
|
+
const setID = groupDetails[0].setID;
|
|
190
|
+
// Ordina per creationTime (più recente prima)
|
|
191
|
+
const sortedDetails = [...groupDetails].sort((a, b) => {
|
|
192
|
+
if (!a.creationTime || !b.creationTime)
|
|
193
|
+
return 0;
|
|
194
|
+
return b.creationTime.getTime() - a.creationTime.getTime();
|
|
195
|
+
});
|
|
196
|
+
const latest = sortedDetails[0];
|
|
197
|
+
const latestRow = workItemsResult.dtdResult?.rows?.find(row => Number(row[columnIndices.tid]) === latest.tid &&
|
|
198
|
+
Number(row[columnIndices.did]) === latest.did);
|
|
199
|
+
// Calcola il setStatus come DataListItemDescriptor
|
|
200
|
+
let setStatusItem = undefined;
|
|
201
|
+
if (latestRow && columnIndices.setStatus !== -1) {
|
|
202
|
+
const rawStatusValue = latestRow[columnIndices.setStatus];
|
|
203
|
+
if (rawStatusValue !== undefined && rawStatusValue !== null && dldStatus?.items) {
|
|
204
|
+
setStatusItem = dldStatus.items.find(item => item.value === rawStatusValue);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// Cerca il diagramItem corrispondente al setID nel workflow
|
|
208
|
+
const diagramItem = wfDiagram?.DiagramItems?.find(item => item.ID === setID);
|
|
209
|
+
return {
|
|
210
|
+
wid: `group_${setID}_${groupIndex}`,
|
|
211
|
+
setID,
|
|
212
|
+
creationTime: latest.creationTime,
|
|
213
|
+
groupIndex,
|
|
214
|
+
category: latestRow && columnIndices.category !== -1 ? latestRow[columnIndices.category] : undefined,
|
|
215
|
+
type: diagramItem?.Type,
|
|
216
|
+
name: diagramItem?.ItemName,
|
|
217
|
+
description: latestRow && columnIndices.description !== -1 ? latestRow[columnIndices.description] : undefined,
|
|
218
|
+
setStatus: setStatusItem,
|
|
219
|
+
setRule: latestRow && columnIndices.setRule !== -1 ? Number(latestRow[columnIndices.setRule]) : undefined,
|
|
220
|
+
details: sortedDetails,
|
|
221
|
+
wf: workflow,
|
|
222
|
+
};
|
|
223
|
+
});
|
|
224
|
+
// Ordina i gruppi per creationTime (più recente prima)
|
|
225
|
+
return finalWorkItems.sort((a, b) => {
|
|
226
|
+
if (!a.creationTime || !b.creationTime)
|
|
227
|
+
return 0;
|
|
228
|
+
return b.creationTime.getTime() - a.creationTime.getTime();
|
|
229
|
+
});
|
|
230
|
+
};
|
|
@@ -6,7 +6,7 @@ export declare class PlatformObjectService {
|
|
|
6
6
|
static readonly retrieveAllAdminAsync: (objClass: ObjectClasses, jobType?: JobTypes) => Promise<import("@topconsultnpm/sdk-ts").UserDescriptor[] | DcmtTypeDescriptor[] | import("@topconsultnpm/sdk-ts").AreaDescriptor[] | import("@topconsultnpm/sdk-ts").RelationDescriptor[] | import("@topconsultnpm/sdk-ts").FEDistillerJobDescriptor[] | import("@topconsultnpm/sdk-ts").DataListDescriptor[] | import("@topconsultnpm/sdk-ts").DiskDescriptor[] | import("@topconsultnpm/sdk-ts").GroupDescriptor[] | import("@topconsultnpm/sdk-ts").LDAPDescriptor[] | import("@topconsultnpm/sdk-ts").NumeratorDescriptor[] | ProcessDescriptor[] | import("@topconsultnpm/sdk-ts").SAPLoginDescriptor[] | import("@topconsultnpm/sdk-ts").SignCertDescriptor[] | import("@topconsultnpm/sdk-ts").SignServerDescriptor[] | import("@topconsultnpm/sdk-ts").TreeDescriptor[] | import("@topconsultnpm/sdk-ts").TSADescriptor[] | import("@topconsultnpm/sdk-ts").WFDescriptor[] | undefined>;
|
|
7
7
|
private static readonly loadCacheForJobAsync;
|
|
8
8
|
private static readonly retrieveAdminJobAsync;
|
|
9
|
-
static readonly retrieveAdminAsync: (objClass: ObjectClasses, jobType: JobTypes, id: number) => Promise<import("@topconsultnpm/sdk-ts").UserDescriptor | DcmtTypeDescriptor | import("@topconsultnpm/sdk-ts").MailSenderJobDescriptor | import("@topconsultnpm/sdk-ts").SavedQueryDescriptor | import("@topconsultnpm/sdk-ts").DataListDescriptor | import("@topconsultnpm/sdk-ts").AreaDescriptor | import("@topconsultnpm/sdk-ts").BasketTypeDescriptor | import("@topconsultnpm/sdk-ts").RelationDescriptor | import("@topconsultnpm/sdk-ts").TaskDescriptor | import("@topconsultnpm/sdk-ts").WorkingGroupDescriptor | import("@topconsultnpm/sdk-ts").BarcodeArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").BatchUpdaterJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoDoganaleJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoDoganalePlusJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoFiscaleQueryJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoFiscaleSenderJobDescriptor | import("@topconsultnpm/sdk-ts").CheckSequenceJobDescriptor | import("@topconsultnpm/sdk-ts").COSCheckerJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtConverterJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtDeleterJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtNoteJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtPrinterJobDescriptor | import("@topconsultnpm/sdk-ts").FEAttacherJobDescriptor | import("@topconsultnpm/sdk-ts").FECreatorTxtJobDescriptor | import("@topconsultnpm/sdk-ts").FEDetacherJobDescriptor | import("@topconsultnpm/sdk-ts").FEDistillerJobDescriptor | import("@topconsultnpm/sdk-ts").FESenderWsJobDescriptor | import("@topconsultnpm/sdk-ts").FESplitterJobDescriptor | import("@topconsultnpm/sdk-ts").FEValidatorJobDescriptor | import("@topconsultnpm/sdk-ts").FileArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").FileCheckerJobDescriptor | import("@topconsultnpm/sdk-ts").FileExecJobDescriptor | import("@topconsultnpm/sdk-ts").FileExportJobDescriptor | import("@topconsultnpm/sdk-ts").FileMoverJobDescriptor | import("@topconsultnpm/sdk-ts").LexJobDescriptor | import("@topconsultnpm/sdk-ts").LinkerJobDescriptor | import("@topconsultnpm/sdk-ts").MailArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").MailQueryJobDescriptor | import("@topconsultnpm/sdk-ts").MigrationJobDescriptor | import("@topconsultnpm/sdk-ts").PdDCreatorJobDescriptor | import("@topconsultnpm/sdk-ts").PDFArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").PdVArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").PdVQueryJobDescriptor | import("@topconsultnpm/sdk-ts").PdVSenderJobDescriptor | import("@topconsultnpm/sdk-ts").PeppolQueryJobDescriptor | import("@topconsultnpm/sdk-ts").PeppolSenderJobDescriptor | import("@topconsultnpm/sdk-ts").PostelQueryJobDescriptor | import("@topconsultnpm/sdk-ts").PostelSenderJobDescriptor | import("@topconsultnpm/sdk-ts").ReplicatorJobDescriptor | import("@topconsultnpm/sdk-ts").SAPAlignerJobDescriptor | import("@topconsultnpm/sdk-ts").SAPBarcodeJobDescriptor | import("@topconsultnpm/sdk-ts").SAPDataReaderJobDescriptor | import("@topconsultnpm/sdk-ts").SAPDataWriterJobDescriptor | import("@topconsultnpm/sdk-ts").SignerJobDescriptor | import("@topconsultnpm/sdk-ts").SpoolArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").UpdaterJobDescriptor | import("@topconsultnpm/sdk-ts").DiskDescriptor | import("@topconsultnpm/sdk-ts").GroupDescriptor | import("@topconsultnpm/sdk-ts").LDAPDescriptor | import("@topconsultnpm/sdk-ts").NumeratorDescriptor | ProcessDescriptor | import("@topconsultnpm/sdk-ts").SAPLoginDescriptor | import("@topconsultnpm/sdk-ts").SignCertDescriptor | import("@topconsultnpm/sdk-ts").SignServerDescriptor | import("@topconsultnpm/sdk-ts").TreeDescriptor | import("@topconsultnpm/sdk-ts").TSADescriptor |
|
|
9
|
+
static readonly retrieveAdminAsync: (objClass: ObjectClasses, jobType: JobTypes, id: number) => Promise<import("@topconsultnpm/sdk-ts").UserDescriptor | import("@topconsultnpm/sdk-ts").WFDescriptor | DcmtTypeDescriptor | import("@topconsultnpm/sdk-ts").MailSenderJobDescriptor | import("@topconsultnpm/sdk-ts").SavedQueryDescriptor | import("@topconsultnpm/sdk-ts").DataListDescriptor | import("@topconsultnpm/sdk-ts").AreaDescriptor | import("@topconsultnpm/sdk-ts").BasketTypeDescriptor | import("@topconsultnpm/sdk-ts").RelationDescriptor | import("@topconsultnpm/sdk-ts").TaskDescriptor | import("@topconsultnpm/sdk-ts").WorkingGroupDescriptor | import("@topconsultnpm/sdk-ts").BarcodeArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").BatchUpdaterJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoDoganaleJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoDoganalePlusJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoFiscaleQueryJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoFiscaleSenderJobDescriptor | import("@topconsultnpm/sdk-ts").CheckSequenceJobDescriptor | import("@topconsultnpm/sdk-ts").COSCheckerJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtConverterJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtDeleterJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtNoteJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtPrinterJobDescriptor | import("@topconsultnpm/sdk-ts").FEAttacherJobDescriptor | import("@topconsultnpm/sdk-ts").FECreatorTxtJobDescriptor | import("@topconsultnpm/sdk-ts").FEDetacherJobDescriptor | import("@topconsultnpm/sdk-ts").FEDistillerJobDescriptor | import("@topconsultnpm/sdk-ts").FESenderWsJobDescriptor | import("@topconsultnpm/sdk-ts").FESplitterJobDescriptor | import("@topconsultnpm/sdk-ts").FEValidatorJobDescriptor | import("@topconsultnpm/sdk-ts").FileArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").FileCheckerJobDescriptor | import("@topconsultnpm/sdk-ts").FileExecJobDescriptor | import("@topconsultnpm/sdk-ts").FileExportJobDescriptor | import("@topconsultnpm/sdk-ts").FileMoverJobDescriptor | import("@topconsultnpm/sdk-ts").LexJobDescriptor | import("@topconsultnpm/sdk-ts").LinkerJobDescriptor | import("@topconsultnpm/sdk-ts").MailArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").MailQueryJobDescriptor | import("@topconsultnpm/sdk-ts").MigrationJobDescriptor | import("@topconsultnpm/sdk-ts").PdDCreatorJobDescriptor | import("@topconsultnpm/sdk-ts").PDFArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").PdVArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").PdVQueryJobDescriptor | import("@topconsultnpm/sdk-ts").PdVSenderJobDescriptor | import("@topconsultnpm/sdk-ts").PeppolQueryJobDescriptor | import("@topconsultnpm/sdk-ts").PeppolSenderJobDescriptor | import("@topconsultnpm/sdk-ts").PostelQueryJobDescriptor | import("@topconsultnpm/sdk-ts").PostelSenderJobDescriptor | import("@topconsultnpm/sdk-ts").ReplicatorJobDescriptor | import("@topconsultnpm/sdk-ts").SAPAlignerJobDescriptor | import("@topconsultnpm/sdk-ts").SAPBarcodeJobDescriptor | import("@topconsultnpm/sdk-ts").SAPDataReaderJobDescriptor | import("@topconsultnpm/sdk-ts").SAPDataWriterJobDescriptor | import("@topconsultnpm/sdk-ts").SignerJobDescriptor | import("@topconsultnpm/sdk-ts").SpoolArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").UpdaterJobDescriptor | import("@topconsultnpm/sdk-ts").DiskDescriptor | import("@topconsultnpm/sdk-ts").GroupDescriptor | import("@topconsultnpm/sdk-ts").LDAPDescriptor | import("@topconsultnpm/sdk-ts").NumeratorDescriptor | ProcessDescriptor | import("@topconsultnpm/sdk-ts").SAPLoginDescriptor | import("@topconsultnpm/sdk-ts").SignCertDescriptor | import("@topconsultnpm/sdk-ts").SignServerDescriptor | import("@topconsultnpm/sdk-ts").TreeDescriptor | import("@topconsultnpm/sdk-ts").TSADescriptor | undefined>;
|
|
10
10
|
private static readonly updateJobAsync;
|
|
11
11
|
static readonly updateAsync: (objClass: ObjectClasses, jobType: JobTypes, d: any, ...args: any[]) => Promise<number | undefined>;
|
|
12
12
|
private static readonly createJobAsync;
|
package/lib/ts/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
|
-
import { DataListItemDescriptor, FileFormats, ITopMediaSession, MetadataDescriptor, MetadataValueDescriptor, UserDescriptor, ValidationItem } from "@topconsultnpm/sdk-ts";
|
|
2
|
+
import { DataListItemDescriptor, FileFormats, ITopMediaSession, MetadataDescriptor, MetadataValueDescriptor, UserDescriptor, ValidationItem, WFDescriptor } from "@topconsultnpm/sdk-ts";
|
|
3
3
|
import { ITMEditorBase } from "../components/base/TMEditorBase";
|
|
4
4
|
import { IColumnProps } from "devextreme-react/data-grid";
|
|
5
5
|
export declare enum FormModes {
|
|
@@ -356,14 +356,17 @@ export interface WorkItemDetail {
|
|
|
356
356
|
*/
|
|
357
357
|
export interface IWorkItemData {
|
|
358
358
|
wid: string;
|
|
359
|
+
tid?: number;
|
|
360
|
+
did?: number;
|
|
359
361
|
category?: any;
|
|
360
362
|
type?: any;
|
|
361
363
|
name?: string;
|
|
362
364
|
description?: string;
|
|
363
|
-
setID: string;
|
|
365
|
+
setID: string | undefined;
|
|
364
366
|
creationTime?: Date;
|
|
365
367
|
setStatus?: DataListItemDescriptor;
|
|
366
368
|
setRule?: number;
|
|
367
369
|
details: WorkItemDetail[];
|
|
368
370
|
groupIndex?: number;
|
|
371
|
+
wf?: WFDescriptor;
|
|
369
372
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@topconsultnpm/sdkui-react",
|
|
3
|
-
"version": "6.20.0-dev1.
|
|
3
|
+
"version": "6.20.0-dev1.80",
|
|
4
4
|
"description": "",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"lib"
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@topconsultnpm/sdk-ts": "6.20.0-dev1.
|
|
43
|
+
"@topconsultnpm/sdk-ts": "6.20.0-dev1.6",
|
|
44
44
|
"buffer": "^6.0.3",
|
|
45
45
|
"devextreme": "25.2.4",
|
|
46
46
|
"devextreme-react": "25.2.4",
|