@topconsultnpm/sdkui-react 6.21.0-dev3.16 → 6.21.0-dev3.18

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.
@@ -73,20 +73,20 @@ export declare const MenuButton: import("styled-components/dist/types").IStyledC
73
73
  export declare const ConfigButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never> & Partial<Pick<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>>> & string;
74
74
  export declare const ApplyButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never> & Partial<Pick<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>>> & string;
75
75
  export declare const CloseButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never> & Partial<Pick<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, never>>> & string;
76
- export declare const ContextMenuButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<Omit<import("styled-components").FastOmit<import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "$isActive"> & {
76
+ export declare const ContextMenuButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<Omit<import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "$isActive"> & {
77
77
  $isActive?: boolean;
78
78
  }, never> & Partial<Pick<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "$isActive"> & {
79
79
  $isActive?: boolean;
80
- }, never>>, "as" | "forwardedAs"> & {
80
+ }, never>> & {
81
81
  as?: import("styled-components").WebTarget | undefined;
82
82
  forwardedAs?: import("styled-components").WebTarget | undefined;
83
83
  }, "ref"> & {
84
84
  ref?: ((instance: HTMLButtonElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLButtonElement> | null | undefined;
85
- }, never> & Partial<Pick<Omit<import("styled-components").FastOmit<import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "$isActive"> & {
85
+ }, never> & Partial<Pick<Omit<import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "$isActive"> & {
86
86
  $isActive?: boolean;
87
87
  }, never> & Partial<Pick<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "$isActive"> & {
88
88
  $isActive?: boolean;
89
- }, never>>, "as" | "forwardedAs"> & {
89
+ }, never>> & {
90
90
  as?: import("styled-components").WebTarget | undefined;
91
91
  forwardedAs?: import("styled-components").WebTarget | undefined;
92
92
  }, "ref"> & {
@@ -36,6 +36,8 @@ const TMDataGrid = React.forwardRef((props, ref) => {
36
36
  const [customContextMenuPosition, setCustomContextMenuPosition] = useState({ x: 0, y: 0 });
37
37
  const [customContextMenuRowKey, setCustomContextMenuRowKey] = useState(undefined);
38
38
  const gridContainerRef = useRef(null);
39
+ // Ref per evitare focus ripetuti sulla search panel
40
+ const searchPanelFocusedRef = useRef(false);
39
41
  useEffect(() => {
40
42
  const count = getRecordCount(dataSource);
41
43
  setTotalRecordCount(count);
@@ -44,10 +46,15 @@ const TMDataGrid = React.forwardRef((props, ref) => {
44
46
  useEffect(() => {
45
47
  if (!searchPanelFocusTrigger || searchPanelFocusTrigger <= 0 || !showSearchPanel || !internalRef.current)
46
48
  return;
49
+ // Reset del flag quando cambia il trigger (per permettere un nuovo focus se richiesto)
50
+ searchPanelFocusedRef.current = false;
47
51
  setTimeout(() => {
52
+ if (searchPanelFocusedRef.current)
53
+ return;
48
54
  const searchInput = internalRef.current?.instance().element().querySelector('.dx-datagrid-search-panel input');
49
55
  if (searchInput) {
50
56
  searchInput.focus();
57
+ searchPanelFocusedRef.current = true;
51
58
  }
52
59
  }, 100);
53
60
  }, [searchPanelFocusTrigger, showSearchPanel]);
@@ -305,13 +312,16 @@ const TMDataGrid = React.forwardRef((props, ref) => {
305
312
  return;
306
313
  // Update state with the current number of visible rows in the DataGrid
307
314
  setVisibleItemsCount(internalRef.current.instance()?.getVisibleRows()?.length ?? 0);
308
- // Focusing SearchPanel on content ready
309
- if (showSearchPanel && searchPanelFocusTrigger && searchPanelFocusTrigger > 0) {
315
+ // Focusing SearchPanel on content ready - solo se non è già stato fatto
316
+ if (showSearchPanel && searchPanelFocusTrigger && searchPanelFocusTrigger > 0 && !searchPanelFocusedRef.current) {
310
317
  // Use a small delay to ensure the DOM is fully rendered before trying to focus
311
318
  setTimeout(() => {
319
+ if (searchPanelFocusedRef.current)
320
+ return;
312
321
  const searchInput = internalRef.current?.instance().element().querySelector('.dx-datagrid-search-panel input');
313
322
  if (searchInput) {
314
323
  searchInput.focus();
324
+ searchPanelFocusedRef.current = true;
315
325
  }
316
326
  }, 100);
317
327
  }
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { useState, useEffect, useRef } from 'react';
3
3
  import { Popup } from 'devextreme-react';
4
4
  import styled from 'styled-components';
5
- import TMLayoutContainer, { TMCard, TMLayoutItem } from './TMLayout';
5
+ import { TMCard } from './TMLayout';
6
6
  import { FontSize, TMColors } from '../../utils/theme';
7
7
  import { IconWindowMaximize, IconWindowMinimize, svgToString } from '../../helper';
8
8
  const StyledModal = styled.div `
@@ -110,6 +110,6 @@ const TMModal = ({ resizable = true, expandable = false, isModal = true, title =
110
110
  onClick: () => setIsFullScreen(!isFullScreen)
111
111
  }
112
112
  }
113
- ] : undefined, children: _jsxs(TMLayoutContainer, { children: [toolbar && (_jsx(TMLayoutItem, { height: "40px", children: _jsx(StyledModalToolbar, { children: toolbar }) })), _jsx(TMLayoutItem, { height: toolbar ? 'calc(100% - 40px)' : '100%', children: _jsx(TMCard, { showBorder: false, padding: false, scrollY: true, children: children }) })] }) })) : (_jsxs(StyledModal, { "$isModal": isModal, className: "temp-modal", "$fontSize": fontSize, "$width": initialWidth, "$height": initialHeight, children: [toolbar ? _jsx(StyledModalToolbar, { children: toolbar }) : _jsx(_Fragment, {}), _jsx(StyledModalContext, { children: children })] })) }));
113
+ ] : undefined, children: _jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', width: '100%' }, children: [toolbar && (_jsx(StyledModalToolbar, { children: toolbar })), _jsx("div", { style: { flex: 1, overflow: 'hidden', minHeight: 0 }, children: _jsx(TMCard, { showBorder: false, padding: false, scrollY: true, children: children }) })] }) })) : (_jsxs(StyledModal, { "$isModal": isModal, className: "temp-modal", "$fontSize": fontSize, "$width": initialWidth, "$height": initialHeight, children: [toolbar ? _jsx(StyledModalToolbar, { children: toolbar }) : _jsx(_Fragment, {}), _jsx(StyledModalContext, { children: children })] })) }));
114
114
  };
115
115
  export default TMModal;
@@ -0,0 +1,17 @@
1
+ import { MetadataDescriptor, QueryDescriptor, SelectItem } from "@topconsultnpm/sdk-ts";
2
+ interface TMMetadataOutputFormProps {
3
+ /** QueryDescriptor da cui estrarre i metadati disponibili */
4
+ qd?: QueryDescriptor;
5
+ /** Lista di SelectItem attualmente selezionati */
6
+ selectedSelectItems?: SelectItem[];
7
+ /** Consente di visualizzare i metadati di sistema (es. MID < 150) */
8
+ allowSysMetadata?: boolean;
9
+ /** Funzione predicato per filtrare i metadati (es. solo quelli con permesso canView) */
10
+ filterMetadata?: (value: MetadataDescriptor, index: number, array: MetadataDescriptor[]) => unknown;
11
+ /** Callback chiamata alla chiusura del form */
12
+ onClose: () => void;
13
+ /** Callback chiamata quando l'utente conferma la selezione dei SelectItem */
14
+ onChoose?: (selectItems: SelectItem[] | undefined) => void;
15
+ }
16
+ declare const TMMetadataOutputForm: (props: TMMetadataOutputFormProps) => import("react/jsx-runtime").JSX.Element;
17
+ export default TMMetadataOutputForm;
@@ -0,0 +1,225 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
+ import { SDK_Localizator, SelectItem, SelectItemVisibilities } from "@topconsultnpm/sdk-ts";
4
+ import { IconAddCircleOutline, IconApply, IconClear, IconDelete, IconDraggabledots, IconUndo, SDKUI_Localizator } from "../../../helper";
5
+ import TMToppyMessage from "../../../helper/TMToppyMessage";
6
+ import { ButtonNames, TMMessageBoxManager } from "../../base/TMPopUp";
7
+ import { TMColors } from "../../../utils/theme";
8
+ import { StyledToolbarForm } from "../../base/Styled";
9
+ import TMButton from "../../base/TMButton";
10
+ import TMModal from "../../base/TMModal";
11
+ import { TMMetadataChooserForm } from "../../choosers/TMMetadataChooser";
12
+ import { TMMetadataIcon } from "../../viewers/TMMidViewer";
13
+ import { loadMetadataFromQd, removeDuplicatesByTidMid, areArraysEqual } from "./metadataFormHelper";
14
+ const TMMetadataOutputForm = (props) => {
15
+ const { qd, selectedSelectItems, allowSysMetadata = true, filterMetadata, onClose, onChoose } = props;
16
+ // =============================================================================
17
+ // STATE
18
+ // =============================================================================
19
+ // Stato iniziale dei SelectItem (per confronto isModified)
20
+ const initialSelectItemsRef = useRef((selectedSelectItems ?? []).map(item => {
21
+ const newItem = new SelectItem();
22
+ newItem.tid = item.tid;
23
+ newItem.mid = item.mid;
24
+ newItem.visibility = item.visibility ?? SelectItemVisibilities.Visible;
25
+ return newItem;
26
+ }));
27
+ // Lista dei SelectItem correnti (inizializzata da selectedSelectItems)
28
+ const [selectItems, setSelectItems] = useState(() => {
29
+ // Clona i SelectItem iniziali per evitare mutazioni
30
+ return (selectedSelectItems ?? []).map(item => {
31
+ const newItem = new SelectItem();
32
+ newItem.tid = item.tid;
33
+ newItem.mid = item.mid;
34
+ newItem.visibility = item.visibility ?? SelectItemVisibilities.Visible;
35
+ return newItem;
36
+ });
37
+ });
38
+ // Calcola se ci sono modifiche rispetto allo stato iniziale
39
+ const isModified = useMemo(() => {
40
+ return !areArraysEqual(selectItems, initialSelectItemsRef.current);
41
+ }, [selectItems]);
42
+ // Lista "piatta" di tutti i metadati estratti dai DTD, con chiave univoca
43
+ const [metadataList, setMetadataList] = useState([]);
44
+ // Flag di caricamento
45
+ const [isLoading, setIsLoading] = useState(true);
46
+ // Flag per mostrare il TMMetadataChooserForm
47
+ const [showMetadataChooser, setShowMetadataChooser] = useState(false);
48
+ // Item in fase di drag
49
+ const [draggingItem, setDraggingItem] = useState(undefined);
50
+ // =============================================================================
51
+ // MEMOIZZAZIONI per evitare re-render del TMMetadataChooserForm
52
+ // =============================================================================
53
+ // Lista di TID_MID già selezionati (per escluderli dal chooser)
54
+ const selectedIDs = useMemo(() => selectItems.map(si => ({ tid: si.tid, mid: si.mid })), [selectItems]);
55
+ // Callback per chiudere il chooser
56
+ const handleCloseChooser = useCallback(() => {
57
+ setShowMetadataChooser(false);
58
+ }, []);
59
+ // =============================================================================
60
+ // EFFECT: Carica i metadati al mount
61
+ // =============================================================================
62
+ useEffect(() => {
63
+ const load = async () => {
64
+ setIsLoading(true);
65
+ try {
66
+ const { metadata } = await loadMetadataFromQd(qd, filterMetadata);
67
+ setMetadataList(metadata);
68
+ }
69
+ catch (error) {
70
+ console.error("Errore nel caricamento dei metadati:", error);
71
+ setMetadataList([]);
72
+ }
73
+ finally {
74
+ setIsLoading(false);
75
+ }
76
+ };
77
+ load();
78
+ }, [qd, filterMetadata]);
79
+ // =============================================================================
80
+ // HELPER: Trova il MetadataDescriptor per un SelectItem
81
+ // =============================================================================
82
+ const getMetadataForSelectItem = useCallback((item) => {
83
+ return metadataList.find(md => md.customData1 === item.tid && md.id === item.mid);
84
+ }, [metadataList]);
85
+ // =============================================================================
86
+ // HANDLER: Conferma la scelta dal chooser (sincronizza la lista completa)
87
+ // =============================================================================
88
+ const handleChooseFromChooser = useCallback((tid_mids) => {
89
+ // Se la lista è vuota o undefined, rimuovi tutti
90
+ if (!tid_mids || tid_mids.length === 0) {
91
+ setSelectItems([]);
92
+ setShowMetadataChooser(false);
93
+ return;
94
+ }
95
+ setSelectItems(prev => {
96
+ // Filtra quelli esistenti che sono ancora selezionati (mantenendo ordine)
97
+ const kept = prev.filter(si => tid_mids.some(tm => tm.tid === si.tid && tm.mid === si.mid));
98
+ // Trova i nuovi da aggiungere
99
+ const newItems = [];
100
+ for (const tm of tid_mids) {
101
+ const exists = prev.some(si => si.tid === tm.tid && si.mid === tm.mid);
102
+ if (!exists) {
103
+ const newItem = new SelectItem();
104
+ newItem.tid = tm.tid;
105
+ newItem.mid = tm.mid;
106
+ newItem.visibility = SelectItemVisibilities.Visible;
107
+ newItems.push(newItem);
108
+ }
109
+ }
110
+ return removeDuplicatesByTidMid([...kept, ...newItems]);
111
+ });
112
+ setShowMetadataChooser(false);
113
+ }, []);
114
+ // =============================================================================
115
+ // HANDLER: Rimuove un metadato dall'output
116
+ // =============================================================================
117
+ const handleRemoveSelectItem = useCallback((index) => {
118
+ setSelectItems(prev => prev.filter((_, i) => i !== index));
119
+ }, []);
120
+ // =============================================================================
121
+ // DRAG & DROP HANDLERS
122
+ // =============================================================================
123
+ const handleDragStart = useCallback((e, item) => {
124
+ // Previeni il drag se il target è l'icona elimina
125
+ const target = e.target;
126
+ if (target.closest('[data-no-drag="true"]')) {
127
+ e.preventDefault();
128
+ return;
129
+ }
130
+ setDraggingItem(item);
131
+ e.dataTransfer.setData('text/plain', '');
132
+ e.dataTransfer.effectAllowed = 'move';
133
+ }, []);
134
+ const handleDragEnd = useCallback(() => {
135
+ setDraggingItem(undefined);
136
+ }, []);
137
+ const handleDragOver = useCallback((e) => {
138
+ e.preventDefault();
139
+ e.dataTransfer.dropEffect = 'move';
140
+ }, []);
141
+ const handleDrop = useCallback((e, targetItem) => {
142
+ e.preventDefault();
143
+ if (!draggingItem)
144
+ return;
145
+ const currentIndex = selectItems.indexOf(draggingItem);
146
+ const targetIndex = selectItems.indexOf(targetItem);
147
+ if (currentIndex === -1 || targetIndex === -1 || currentIndex === targetIndex) {
148
+ setDraggingItem(undefined);
149
+ return;
150
+ }
151
+ const listCopy = [...selectItems];
152
+ listCopy.splice(currentIndex, 1);
153
+ listCopy.splice(targetIndex, 0, draggingItem);
154
+ setSelectItems(listCopy);
155
+ setDraggingItem(undefined);
156
+ }, [draggingItem, selectItems]);
157
+ // =============================================================================
158
+ // HANDLER: Rollback allo stato iniziale
159
+ // =============================================================================
160
+ const handleRollback = useCallback(() => {
161
+ setSelectItems(initialSelectItemsRef.current.map(item => {
162
+ const newItem = new SelectItem();
163
+ newItem.tid = item.tid;
164
+ newItem.mid = item.mid;
165
+ newItem.visibility = item.visibility;
166
+ return newItem;
167
+ }));
168
+ }, []);
169
+ // =============================================================================
170
+ // HANDLER: Chiusura con conferma se modificato
171
+ // =============================================================================
172
+ const confirmCloseContainerId = "TMMetadataOutputFormConfirmClose";
173
+ const handleClose = useCallback(() => {
174
+ if (!isModified) {
175
+ onClose();
176
+ return;
177
+ }
178
+ TMMessageBoxManager.show({
179
+ parentId: confirmCloseContainerId,
180
+ message: SDKUI_Localizator.ConfirmOnCancel,
181
+ buttons: [ButtonNames.YES, ButtonNames.NO],
182
+ onButtonClick: (buttonClicked) => {
183
+ if (buttonClicked === ButtonNames.YES) {
184
+ onClose();
185
+ }
186
+ }
187
+ });
188
+ }, [isModified, onClose]);
189
+ // =============================================================================
190
+ // HANDLER: Conferma la selezione
191
+ // =============================================================================
192
+ const handleConfirm = useCallback(() => {
193
+ onChoose?.(selectItems.length > 0 ? selectItems : undefined);
194
+ onClose();
195
+ }, [selectItems, onChoose, onClose]);
196
+ // =============================================================================
197
+ // RENDER
198
+ // =============================================================================
199
+ return (_jsxs(_Fragment, { children: [_jsxs(TMModal, { title: `${SDKUI_Localizator.Configure} - ${SDK_Localizator.QuerySelect}${selectItems.length > 0 ? ` (${selectItems.length})` : ''}`, width: "600px", height: "500px", onClose: handleClose, hidePopup: false, askClosingConfirm: isModified, children: [_jsx("div", { id: confirmCloseContainerId }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', gap: '10px' }, children: [_jsxs(StyledToolbarForm, { children: [_jsx(TMButton, { caption: SDKUI_Localizator.Confirm, icon: _jsx(IconApply, {}), btnStyle: "toolbar", color: "success", disabled: !isModified, onClick: handleConfirm }), _jsx(TMButton, { caption: SDKUI_Localizator.Undo, icon: _jsx(IconUndo, {}), btnStyle: "toolbar", color: "tertiary", disabled: !isModified, onClick: handleRollback }), _jsx(TMButton, { caption: SDKUI_Localizator.Add, icon: _jsx(IconAddCircleOutline, {}), btnStyle: "toolbar", onClick: () => setShowMetadataChooser(true) }), _jsx(TMButton, { caption: SDKUI_Localizator.Clear, icon: _jsx(IconClear, {}), btnStyle: "toolbar", disabled: selectItems.length === 0, onClick: () => setSelectItems([]) })] }), _jsxs("div", { style: {
200
+ flex: 1,
201
+ overflow: 'auto',
202
+ border: `1px solid ${TMColors.border_normal}`,
203
+ borderRadius: '4px',
204
+ padding: '5px'
205
+ }, children: [isLoading && _jsxs("p", { style: { textAlign: 'center', padding: '20px' }, children: [SDKUI_Localizator.Loading, "..."] }), !isLoading && selectItems.length === 0 && (_jsx(TMToppyMessage, { message: SDKUI_Localizator.NoOutputMetadata, titleTooltip: SDKUI_Localizator.NoOutputMetadata })), !isLoading && selectItems.length > 0 && (_jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: '2px' }, children: selectItems.map((item, index) => {
206
+ const md = getMetadataForSelectItem(item);
207
+ const isDragging = draggingItem === item;
208
+ return (_jsxs("div", { draggable: true, onDragStart: (e) => handleDragStart(e, item), onDragEnd: handleDragEnd, onDragOver: handleDragOver, onDrop: (e) => handleDrop(e, item), style: {
209
+ display: 'flex',
210
+ alignItems: 'center',
211
+ gap: '6px',
212
+ padding: '4px 8px',
213
+ backgroundColor: isDragging ? TMColors.primary_container : TMColors.default_background,
214
+ borderRadius: '3px',
215
+ border: `1px solid ${isDragging ? TMColors.primaryColor : TMColors.border_normal}`,
216
+ minHeight: '32px',
217
+ cursor: 'grab',
218
+ transition: 'all 0.2s ease',
219
+ transform: isDragging ? 'scale(1.02)' : 'scale(1)',
220
+ boxShadow: isDragging ? '0 4px 12px rgba(0,0,0,0.15)' : 'none',
221
+ opacity: isDragging ? 0.9 : 1,
222
+ }, children: [_jsx("div", { style: { display: 'flex', cursor: 'grab' }, children: _jsx(IconDraggabledots, { fontSize: 15, color: TMColors.button_icon }) }), _jsx(TMMetadataIcon, { tid: item.tid ?? 0, md: md }), _jsx("span", { style: { flex: 1, fontSize: '13px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: md?.name ?? `MID: ${item.mid}` }), _jsx("div", { "data-no-drag": "true", onMouseDown: (e) => e.stopPropagation(), children: _jsx(TMButton, { icon: _jsx(IconDelete, { color: TMColors.error }), btnStyle: "icon", onClick: () => handleRemoveSelectItem(index) }) })] }, `${item.tid}_${item.mid}_${index}`));
223
+ }) }))] })] })] }), showMetadataChooser && (_jsx(TMMetadataChooserForm, { allowMultipleSelection: true, height: "600px", width: "700px", allowSysMetadata: allowSysMetadata, filterMetadata: filterMetadata, qd: qd, selectedIDs: selectedIDs, onClose: handleCloseChooser, onChoose: handleChooseFromChooser }))] }));
224
+ };
225
+ export default TMMetadataOutputForm;
@@ -0,0 +1,17 @@
1
+ import { MetadataDescriptor, OrderByItem, QueryDescriptor } from "@topconsultnpm/sdk-ts";
2
+ interface TMMetadataSorterFormProps {
3
+ /** QueryDescriptor da cui estrarre i metadati disponibili */
4
+ qd?: QueryDescriptor;
5
+ /** Lista di OrderByItem attualmente selezionati */
6
+ selectedOrderByItems?: OrderByItem[];
7
+ /** Consente di visualizzare i metadati di sistema (es. MID < 150) */
8
+ allowSysMetadata?: boolean;
9
+ /** Funzione predicato per filtrare i metadati (es. solo quelli con permesso canView) */
10
+ filterMetadata?: (value: MetadataDescriptor, index: number, array: MetadataDescriptor[]) => unknown;
11
+ /** Callback chiamata alla chiusura del form */
12
+ onClose: () => void;
13
+ /** Callback chiamata quando l'utente conferma la selezione degli OrderByItem */
14
+ onChoose?: (orderByItems: OrderByItem[] | undefined) => void;
15
+ }
16
+ declare const TMMetadataSorterForm: (props: TMMetadataSorterFormProps) => import("react/jsx-runtime").JSX.Element;
17
+ export default TMMetadataSorterForm;
@@ -0,0 +1,243 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
+ import { OrderByItem, SDK_Localizator } from "@topconsultnpm/sdk-ts";
4
+ import { IconAddCircleOutline, IconApply, IconClear, IconDelete, IconDraggabledots, IconUndo, SDKUI_Localizator } from "../../../helper";
5
+ import TMToppyMessage from "../../../helper/TMToppyMessage";
6
+ import { ButtonNames, TMMessageBoxManager } from "../../base/TMPopUp";
7
+ import { TMColors } from "../../../utils/theme";
8
+ import { StyledToolbarForm } from "../../base/Styled";
9
+ import TMButton from "../../base/TMButton";
10
+ import TMModal from "../../base/TMModal";
11
+ import { TMMetadataChooserForm } from "../../choosers/TMMetadataChooser";
12
+ import TMDropDown from "../../editors/TMDropDown";
13
+ import { TMMetadataIcon } from "../../viewers/TMMidViewer";
14
+ import { loadMetadataFromQd, removeDuplicatesByTidMid, areArraysEqual } from "./metadataFormHelper";
15
+ const TMMetadataSorterForm = (props) => {
16
+ const { qd, selectedOrderByItems, allowSysMetadata = true, filterMetadata, onClose, onChoose } = props;
17
+ // =============================================================================
18
+ // STATE
19
+ // =============================================================================
20
+ // Stato iniziale degli OrderByItem (per confronto isModified)
21
+ const initialOrderByItemsRef = useRef((selectedOrderByItems ?? []).map(item => {
22
+ const newItem = new OrderByItem();
23
+ newItem.tid = item.tid;
24
+ newItem.mid = item.mid;
25
+ newItem.asc = item.asc ?? true;
26
+ return newItem;
27
+ }));
28
+ // Lista degli OrderByItem correnti (inizializzata da selectedOrderByItems)
29
+ const [orderByItems, setOrderByItems] = useState(() => {
30
+ // Clona gli OrderByItem iniziali per evitare mutazioni
31
+ return (selectedOrderByItems ?? []).map(item => {
32
+ const newItem = new OrderByItem();
33
+ newItem.tid = item.tid;
34
+ newItem.mid = item.mid;
35
+ newItem.asc = item.asc ?? true;
36
+ return newItem;
37
+ });
38
+ });
39
+ // Calcola se ci sono modifiche rispetto allo stato iniziale
40
+ const isModified = useMemo(() => {
41
+ return !areArraysEqual(orderByItems, initialOrderByItemsRef.current, (a, b) => a.asc === b.asc);
42
+ }, [orderByItems]);
43
+ // Lista "piatta" di tutti i metadati estratti dai DTD, con chiave univoca
44
+ const [metadataList, setMetadataList] = useState([]);
45
+ // Flag di caricamento
46
+ const [isLoading, setIsLoading] = useState(true);
47
+ // Flag per mostrare il TMMetadataChooserForm
48
+ const [showMetadataChooser, setShowMetadataChooser] = useState(false);
49
+ // Item in fase di drag
50
+ const [draggingItem, setDraggingItem] = useState(undefined);
51
+ // =============================================================================
52
+ // MEMOIZZAZIONI per evitare re-render del TMMetadataChooserForm
53
+ // =============================================================================
54
+ // Lista di TID_MID già selezionati (per escluderli dal chooser)
55
+ const selectedIDs = useMemo(() => orderByItems.map(oi => ({ tid: oi.tid, mid: oi.mid })), [orderByItems]);
56
+ // Callback per chiudere il chooser
57
+ const handleCloseChooser = useCallback(() => {
58
+ setShowMetadataChooser(false);
59
+ }, []);
60
+ // =============================================================================
61
+ // EFFECT: Carica i metadati al mount
62
+ // =============================================================================
63
+ useEffect(() => {
64
+ const load = async () => {
65
+ setIsLoading(true);
66
+ try {
67
+ const { metadata } = await loadMetadataFromQd(qd, filterMetadata);
68
+ setMetadataList(metadata);
69
+ }
70
+ catch (error) {
71
+ console.error("Errore nel caricamento dei metadati:", error);
72
+ setMetadataList([]);
73
+ }
74
+ finally {
75
+ setIsLoading(false);
76
+ }
77
+ };
78
+ load();
79
+ }, [qd, filterMetadata]);
80
+ // =============================================================================
81
+ // HELPER: Trova il MetadataDescriptor per un OrderByItem
82
+ // =============================================================================
83
+ const getMetadataForOrderByItem = useCallback((item) => {
84
+ return metadataList.find(md => md.customData1 === item.tid && md.id === item.mid);
85
+ }, [metadataList]);
86
+ // =============================================================================
87
+ // HANDLER: Conferma la scelta dal chooser (sincronizza la lista completa)
88
+ // =============================================================================
89
+ const handleChooseFromChooser = useCallback((tid_mids) => {
90
+ // Se la lista è vuota o undefined, rimuovi tutti
91
+ if (!tid_mids || tid_mids.length === 0) {
92
+ setOrderByItems([]);
93
+ setShowMetadataChooser(false);
94
+ return;
95
+ }
96
+ setOrderByItems(prev => {
97
+ // Filtra quelli esistenti che sono ancora selezionati (mantenendo ordine e impostazioni asc/desc)
98
+ const kept = prev.filter(oi => tid_mids.some(tm => tm.tid === oi.tid && tm.mid === oi.mid));
99
+ // Trova i nuovi da aggiungere
100
+ const newItems = [];
101
+ for (const tm of tid_mids) {
102
+ const exists = prev.some(oi => oi.tid === tm.tid && oi.mid === tm.mid);
103
+ if (!exists) {
104
+ const newItem = new OrderByItem();
105
+ newItem.tid = tm.tid;
106
+ newItem.mid = tm.mid;
107
+ newItem.asc = true;
108
+ newItems.push(newItem);
109
+ }
110
+ }
111
+ return removeDuplicatesByTidMid([...kept, ...newItems]);
112
+ });
113
+ setShowMetadataChooser(false);
114
+ }, []);
115
+ // =============================================================================
116
+ // HANDLER: Rimuove un ordinamento
117
+ // =============================================================================
118
+ const handleRemoveOrderBy = useCallback((index) => {
119
+ setOrderByItems(prev => prev.filter((_, i) => i !== index));
120
+ }, []);
121
+ // =============================================================================
122
+ // HANDLER: Toggle ascendente/discendente
123
+ // =============================================================================
124
+ const handleChangeAsc = useCallback((index, asc) => {
125
+ setOrderByItems(prev => prev.map((item, i) => {
126
+ if (i !== index)
127
+ return item;
128
+ const newItem = new OrderByItem();
129
+ newItem.tid = item.tid;
130
+ newItem.mid = item.mid;
131
+ newItem.asc = asc;
132
+ return newItem;
133
+ }));
134
+ }, []);
135
+ // =============================================================================
136
+ // DRAG & DROP HANDLERS
137
+ // =============================================================================
138
+ const handleDragStart = useCallback((e, item) => {
139
+ // Previeni il drag se il target è l'icona elimina o il dropdown
140
+ const target = e.target;
141
+ if (target.closest('[data-no-drag="true"]')) {
142
+ e.preventDefault();
143
+ return;
144
+ }
145
+ setDraggingItem(item);
146
+ e.dataTransfer.setData('text/plain', '');
147
+ e.dataTransfer.effectAllowed = 'move';
148
+ }, []);
149
+ const handleDragEnd = useCallback(() => {
150
+ setDraggingItem(undefined);
151
+ }, []);
152
+ const handleDragOver = useCallback((e) => {
153
+ e.preventDefault();
154
+ e.dataTransfer.dropEffect = 'move';
155
+ }, []);
156
+ const handleDrop = useCallback((e, targetItem) => {
157
+ e.preventDefault();
158
+ if (!draggingItem)
159
+ return;
160
+ const currentIndex = orderByItems.indexOf(draggingItem);
161
+ const targetIndex = orderByItems.indexOf(targetItem);
162
+ if (currentIndex === -1 || targetIndex === -1 || currentIndex === targetIndex) {
163
+ setDraggingItem(undefined);
164
+ return;
165
+ }
166
+ const listCopy = [...orderByItems];
167
+ listCopy.splice(currentIndex, 1);
168
+ listCopy.splice(targetIndex, 0, draggingItem);
169
+ setOrderByItems(listCopy);
170
+ setDraggingItem(undefined);
171
+ }, [draggingItem, orderByItems]);
172
+ // =============================================================================
173
+ // HANDLER: Rollback allo stato iniziale
174
+ // =============================================================================
175
+ const handleRollback = useCallback(() => {
176
+ setOrderByItems(initialOrderByItemsRef.current.map(item => {
177
+ const newItem = new OrderByItem();
178
+ newItem.tid = item.tid;
179
+ newItem.mid = item.mid;
180
+ newItem.asc = item.asc;
181
+ return newItem;
182
+ }));
183
+ }, []);
184
+ // =============================================================================
185
+ // HANDLER: Chiusura con conferma se modificato
186
+ // =============================================================================
187
+ const confirmCloseContainerId = "TMMetadataSorterFormConfirmClose";
188
+ const handleClose = useCallback(() => {
189
+ if (!isModified) {
190
+ onClose();
191
+ return;
192
+ }
193
+ TMMessageBoxManager.show({
194
+ parentId: confirmCloseContainerId,
195
+ message: SDKUI_Localizator.ConfirmOnCancel,
196
+ buttons: [ButtonNames.YES, ButtonNames.NO],
197
+ onButtonClick: (buttonClicked) => {
198
+ if (buttonClicked === ButtonNames.YES) {
199
+ onClose();
200
+ }
201
+ }
202
+ });
203
+ }, [isModified, onClose]);
204
+ // =============================================================================
205
+ // HANDLER: Conferma la selezione
206
+ // =============================================================================
207
+ const handleConfirm = useCallback(() => {
208
+ onChoose?.(orderByItems.length > 0 ? orderByItems : undefined);
209
+ onClose();
210
+ }, [orderByItems, onChoose, onClose]);
211
+ // =============================================================================
212
+ // RENDER
213
+ // =============================================================================
214
+ return (_jsxs(_Fragment, { children: [_jsxs(TMModal, { title: `${SDKUI_Localizator.Configure} - ${SDK_Localizator.QueryOrderBy}${orderByItems.length > 0 ? ` (${orderByItems.length})` : ''}`, width: "600px", height: "500px", onClose: handleClose, hidePopup: false, askClosingConfirm: isModified, children: [_jsx("div", { id: confirmCloseContainerId }), _jsxs("div", { style: { display: 'flex', flexDirection: 'column', height: '100%', gap: '10px' }, children: [_jsxs(StyledToolbarForm, { children: [_jsx(TMButton, { caption: SDKUI_Localizator.Confirm, icon: _jsx(IconApply, {}), btnStyle: "toolbar", color: "success", disabled: !isModified, onClick: handleConfirm }), _jsx(TMButton, { caption: SDKUI_Localizator.Undo, icon: _jsx(IconUndo, {}), btnStyle: "toolbar", color: "tertiary", disabled: !isModified, onClick: handleRollback }), _jsx(TMButton, { caption: SDKUI_Localizator.Add, icon: _jsx(IconAddCircleOutline, {}), btnStyle: "toolbar", onClick: () => setShowMetadataChooser(true) }), _jsx(TMButton, { caption: SDKUI_Localizator.Clear, icon: _jsx(IconClear, {}), btnStyle: "toolbar", disabled: orderByItems.length === 0, onClick: () => setOrderByItems([]) })] }), _jsxs("div", { style: {
215
+ flex: 1,
216
+ overflow: 'auto',
217
+ border: `1px solid ${TMColors.border_normal}`,
218
+ borderRadius: '4px',
219
+ padding: '5px'
220
+ }, children: [isLoading && _jsxs("p", { style: { textAlign: 'center', padding: '20px' }, children: [SDKUI_Localizator.Loading, "..."] }), !isLoading && orderByItems.length === 0 && (_jsx(TMToppyMessage, { message: SDKUI_Localizator.NoSortingApplied, titleTooltip: SDKUI_Localizator.NoSortingApplied })), !isLoading && orderByItems.length > 0 && (_jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: '2px' }, children: orderByItems.map((item, index) => {
221
+ const md = getMetadataForOrderByItem(item);
222
+ const isDragging = draggingItem === item;
223
+ return (_jsxs("div", { draggable: true, onDragStart: (e) => handleDragStart(e, item), onDragEnd: handleDragEnd, onDragOver: handleDragOver, onDrop: (e) => handleDrop(e, item), style: {
224
+ display: 'flex',
225
+ alignItems: 'center',
226
+ gap: '6px',
227
+ padding: '4px 8px',
228
+ backgroundColor: isDragging ? TMColors.primary_container : TMColors.default_background,
229
+ borderRadius: '3px',
230
+ border: `1px solid ${isDragging ? TMColors.primaryColor : TMColors.border_normal}`,
231
+ minHeight: '32px',
232
+ cursor: 'grab',
233
+ transition: 'all 0.2s ease',
234
+ transform: isDragging ? 'scale(1.02)' : 'scale(1)',
235
+ boxShadow: isDragging ? '0 4px 12px rgba(0,0,0,0.15)' : 'none',
236
+ opacity: isDragging ? 0.9 : 1,
237
+ }, children: [_jsx("div", { style: { display: 'flex', cursor: 'grab' }, children: _jsx(IconDraggabledots, { fontSize: 15, color: TMColors.button_icon }) }), _jsx(TMMetadataIcon, { tid: item.tid ?? 0, md: md }), _jsx("span", { style: { flex: 1, fontSize: '13px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: md?.name ?? `MID: ${item.mid}` }), _jsx("div", { "data-no-drag": "true", onMouseDown: (e) => e.stopPropagation(), children: _jsx(TMDropDown, { width: "175px", height: "28px", value: item.asc ? 'asc' : 'desc', dataSource: [
238
+ { value: 'asc', display: SDKUI_Localizator.ValueAscending },
239
+ { value: 'desc', display: SDKUI_Localizator.ValueDescending }
240
+ ], onValueChanged: (e) => handleChangeAsc(index, e.target.value === 'asc') }) }), _jsx("div", { "data-no-drag": "true", onMouseDown: (e) => e.stopPropagation(), children: _jsx(TMButton, { icon: _jsx(IconDelete, { color: TMColors.error }), btnStyle: "icon", onClick: () => handleRemoveOrderBy(index) }) })] }, `${item.tid}_${item.mid}_${index}`));
241
+ }) }))] })] })] }), showMetadataChooser && (_jsx(TMMetadataChooserForm, { allowMultipleSelection: true, height: "600px", width: "700px", allowSysMetadata: allowSysMetadata, filterMetadata: filterMetadata, qd: qd, selectedIDs: selectedIDs, onClose: handleCloseChooser, onChoose: handleChooseFromChooser }))] }));
242
+ };
243
+ export default TMMetadataSorterForm;
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
- import { PlatformObjectValidator, QueryDescriptor, WhereItem, SDK_Localizator, OrderByItem, SelectItem, SelectItemVisibilities, SDK_Globals, SavedQueryCacheService, SearchEngine, QueryOperators, AccessLevelsEx, AccessLevels } from '@topconsultnpm/sdk-ts';
3
+ import { PlatformObjectValidator, QueryDescriptor, WhereItem, SDK_Localizator, SelectItemVisibilities, SDK_Globals, SavedQueryCacheService, SearchEngine, QueryOperators, AccessLevelsEx, AccessLevels } from '@topconsultnpm/sdk-ts';
4
4
  import styled from 'styled-components';
5
5
  import TMSearchQueryEditor from './TMSearchQueryEditor';
6
- import { getDcmtTypesByQdAsync, SDKUI_Localizator, getQD, IconMenuVertical, IconAddCircleOutline, IconEdit, IconEasy, IconAdvanced, deepCompare, IconSearch, IconClear, getDefaultOperator, prepareQdForSearchAsync, IsParametricQuery, SDKUI_Globals, IconArrowRight, IconMenuCAArchive, getListMaxItems, DEFAULT_MAX_DCMTS_TO_BE_RETURNED } from '../../../helper';
6
+ import { getDcmtTypesByQdAsync, SDKUI_Localizator, getQD, IconMenuVertical, IconAddCircleOutline, IconEdit, IconEasy, IconAdvanced, deepCompare, IconSearch, IconClear, getDefaultOperator, prepareQdForSearchAsync, IsParametricQuery, SDKUI_Globals, IconArrowRight, IconMenuCAArchive, getListMaxItems, DEFAULT_MAX_DCMTS_TO_BE_RETURNED, IconSortAsc, IconSortDesc, IconFilter, IconColumns, IconSort } from '../../../helper';
7
7
  import { useQueryParametersDialog } from '../../../hooks/useQueryParametersDialog';
8
8
  import { FormModes } from '../../../ts';
9
9
  import { TMColors } from '../../../utils/theme';
@@ -21,6 +21,9 @@ import TMSavedQueryForm from './TMSavedQueryForm';
21
21
  import { ContextMenu } from '../../NewComponents/ContextMenu';
22
22
  import { AdvancedMenuButtons } from '../../editors/TMMetadataValues';
23
23
  import TMToppyMessage from '../../../helper/TMToppyMessage';
24
+ import TMMetadataSorterForm from './TMMetadataSorterForm';
25
+ import TMMetadataOutputForm from './TMMetadataOutputForm';
26
+ import TMTooltip from '../../base/TMTooltip';
24
27
  const TMSearchQueryPanel = ({ fromDTD, showBackToResultButton, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, SQD, inputMids, onSearchCompleted, onSqdSaved, onBack, onClosePanel, allowMaximize = true, onMaximizePanel, onBackToResult, passToArchiveCallback, maxDcmtsToBeReturned }) => {
25
28
  const [confirmQueryParams, ConfirmQueryParamsDialog] = useQueryParametersDialog();
26
29
  const [qd, setQd] = useState();
@@ -34,7 +37,7 @@ const TMSearchQueryPanel = ({ fromDTD, showBackToResultButton, isExpertMode = SD
34
37
  const [showAdvancedSearch, setShowAdvancedSearch] = useState(false);
35
38
  const [showFiltersConfig, setShowFiltersConfig] = useState(false);
36
39
  const [showOutputConfig, setShowOutputConfig] = useState(false);
37
- const [showOrderByConfig, setShowOrderByConfig] = useState(false);
40
+ const [showMetadataSorterForm, setShowMetadataSorterForm] = useState(false);
38
41
  const [showDistinctValuesPanel, setShowDistinctValuesPanel] = useState(false);
39
42
  const [focusedTidMid, setFocusedTidMid] = useState();
40
43
  const [modalIsOpen, setModalIsOpen] = useState(false);
@@ -162,7 +165,7 @@ const TMSearchQueryPanel = ({ fromDTD, showBackToResultButton, isExpertMode = SD
162
165
  newWi.init({ ...curItem, value1: undefined, value2: undefined });
163
166
  return newWi;
164
167
  });
165
- setQd({ ...qd, where: newWhere });
168
+ setQd({ ...qd, where: newWhere, orderBy: [] });
166
169
  };
167
170
  const searchAsync = async (qdInput, isAdvancedSearch) => {
168
171
  onSearchCompleted?.([], undefined); // reset results
@@ -266,61 +269,16 @@ const TMSearchQueryPanel = ({ fromDTD, showBackToResultButton, isExpertMode = SD
266
269
  setQd({ ...qd, where: newWhere });
267
270
  }, [qd, fromDTD?.metadata, SQD?.masterTID]);
268
271
  const handleCloseOutputConfig = useCallback(() => setShowOutputConfig(false), []);
269
- const handleChooseOutput = useCallback((tid_mids) => {
270
- if (!fromDTD?.metadata)
271
- return;
272
- if (!tid_mids)
273
- return;
274
- // copia dei SelectItems senza i rimossi
275
- let newSelect = qd?.select?.filter(item => tid_mids?.some(tm => tm.mid == item.mid)) ?? [];
276
- // aggiungiamo i nuovi
277
- for (const tm of tid_mids.filter(tm => !qd?.select?.some(item => item.mid == tm.mid))) {
278
- let md = fromDTD?.metadata.find(o => o.id == tm.mid);
279
- let si = new SelectItem();
280
- si.visibility = SelectItemVisibilities.Visible;
281
- si.tid = SQD?.masterTID;
282
- si.mid = md?.id;
283
- let indexMD = 0;
284
- for (const m of fromDTD?.metadata ?? []) {
285
- if (m.id == si.mid)
286
- break;
287
- if (newSelect.findIndex(o => o.mid == m.id && o.tid == SQD?.masterTID) < 0)
288
- continue;
289
- indexMD++;
290
- }
291
- newSelect.splice(indexMD, 0, si);
292
- }
293
- setQd({ ...qd, select: newSelect });
294
- }, [qd, fromDTD?.metadata, SQD?.masterTID]);
295
- const handleCloseOrderByConfig = useCallback(() => setShowOrderByConfig(false), []);
296
- const handleChooseOrderBy = useCallback((tid_mids) => {
297
- if (!fromDTD?.metadata)
298
- return;
299
- if (!tid_mids)
300
- return;
301
- // copia dei OrderByItems senza i rimossi
302
- let newOrderBy = qd?.orderBy?.filter(item => tid_mids?.some(tm => tm.mid == item.mid)) ?? [];
303
- // aggiungiamo i nuovi
304
- for (const tm of tid_mids.filter(tm => !qd?.orderBy?.some(item => item.mid == tm.mid))) {
305
- let md = fromDTD?.metadata.find(o => o.id == tm.mid);
306
- let oi = new OrderByItem();
307
- oi.tid = SQD?.masterTID;
308
- oi.mid = md?.id;
309
- oi.asc = true;
310
- newOrderBy.push(oi);
311
- }
312
- setQd({ ...qd, orderBy: newOrderBy });
313
- }, [qd, fromDTD?.metadata, SQD?.masterTID]);
314
272
  const contextMenuItems = useMemo(() => [
315
273
  ...(showBackToResultButton ? [{ icon: _jsx(IconArrowRight, {}), name: "Vai a risultato", onClick: () => { onBackToResult?.(); } }] : []),
316
274
  { icon: _jsx(IconAddCircleOutline, {}), name: SDKUI_Localizator.SavedQueryNew, beginGroup: showBackToResultButton, onClick: () => { openSqdForm(FormModes.Create); } },
317
275
  { icon: _jsx(IconEdit, {}), name: SDKUI_Localizator.SavedQueryUpdate, disabled: (SQD && SQD.id == 1), onClick: () => { openSqdForm(FormModes.Update); } },
318
276
  { icon: showAdvancedSearch ? _jsx(IconEasy, {}) : _jsx(IconAdvanced, {}), beginGroup: true, name: showAdvancedSearch ? SDKUI_Localizator.Search_Easy : SDKUI_Localizator.Search_Advanced, onClick: () => { changeAdvancedSearchAsync(!showAdvancedSearch); } },
319
- { icon: _jsx(IconEdit, {}), name: `${SDKUI_Localizator.Configure} - ${SDK_Localizator.QueryWhere}`, beginGroup: true, onClick: () => { setShowFiltersConfig(true); } },
320
- { icon: _jsx(IconEdit, {}), name: `${SDKUI_Localizator.Configure} - ${SDK_Localizator.QuerySelect}`, onClick: () => { setShowOutputConfig(true); } },
321
- { icon: _jsx(IconEdit, {}), name: `${SDKUI_Localizator.Configure} - ${SDK_Localizator.QueryOrderBy}`, onClick: () => { setShowOrderByConfig(true); } },
277
+ { icon: _jsx(IconFilter, {}), name: `${SDKUI_Localizator.Configure} - ${SDK_Localizator.QueryWhere}`, beginGroup: true, onClick: () => { setShowFiltersConfig(true); } },
278
+ { icon: _jsx(IconColumns, {}), name: `${SDKUI_Localizator.Configure} - ${SDK_Localizator.QuerySelect}`, onClick: () => { setShowOutputConfig(true); } },
279
+ { icon: _jsx(IconSort, {}), name: `${SDKUI_Localizator.Configure} - ${SDK_Localizator.QueryOrderBy}`, onClick: () => { setShowMetadataSorterForm(true); } },
322
280
  { icon: _jsx(IconMenuCAArchive, { viewBox: '11 11.5 26 27', fontSize: 16, strokeWidth: 2, color: 'black' }), beginGroup: true, name: SDKUI_Localizator.PassToArchive, disabled: fromDTD?.perm?.canArchive !== AccessLevelsEx.Yes && fromDTD?.perm?.canArchive !== AccessLevelsEx.Mixed, onClick: handlePassToArchive }
323
- ], [showBackToResultButton, showAdvancedSearch, SQD, onBackToResult, openSqdForm, changeAdvancedSearchAsync, setShowFiltersConfig, setShowOutputConfig, setShowOrderByConfig, handlePassToArchive, fromDTD?.perm?.canArchive]);
281
+ ], [showBackToResultButton, showAdvancedSearch, SQD, onBackToResult, openSqdForm, changeAdvancedSearchAsync, setShowFiltersConfig, setShowOutputConfig, handlePassToArchive, fromDTD?.perm?.canArchive]);
324
282
  const captionText = showAllMdWhere ? SDKUI_Localizator.ShowLess : SDKUI_Localizator.ShowAll;
325
283
  let maxItems = getListMaxItems(deviceType ?? DeviceType.DESKTOP);
326
284
  const diff = (qd?.where?.length ?? 0) - maxItems;
@@ -329,7 +287,25 @@ const TMSearchQueryPanel = ({ fromDTD, showBackToResultButton, isExpertMode = SD
329
287
  : _jsx(_Fragment, {}) }), children: [_jsx(ConfirmQueryParamsDialog, {}), SQD
330
288
  ? _jsxs("div", { onContextMenu: (e) => e.preventDefault(), style: { height: '100%', width: '100%', position: 'relative', display: showSqdForm ? 'none' : 'flex', flexDirection: 'column', gap: 5 }, children: [showAdvancedSearch
331
289
  ? _jsx(TMQueryEditor, { formMode: FormModes.Update, showToolbar: false, inputData: qd, validateSelect: true, showApply: false, onQDChanged: handleQdChanged, updateIsModalOpen: updateIsModalOpen })
332
- : _jsx(TMSearchQueryEditor, { qd: qd, dcmtTypesList: dcmtTypesList, isExpertMode: isExpertMode, showAllMdWhere: showAllMdWhere, onQdChanged: handleQdChanged, onFocusedMetadataChanged: setFocusedTidMid, onAdvancedMenuClick: handleAdvancedMenuClick, updateIsModalOpen: updateIsModalOpen }), _jsxs("div", { style: {
290
+ : _jsx(TMSearchQueryEditor, { qd: qd, dcmtTypesList: dcmtTypesList, isExpertMode: isExpertMode, showAllMdWhere: showAllMdWhere, onQdChanged: handleQdChanged, onFocusedMetadataChanged: setFocusedTidMid, onAdvancedMenuClick: handleAdvancedMenuClick, updateIsModalOpen: updateIsModalOpen }), qd?.select && qd.select.length > 0 && (_jsxs(StyledSelectBadgesContainer, { children: [_jsxs(StyledSelectLabel, { children: [SDK_Localizator.QuerySelect, ":"] }), _jsx(StyledSelectBadgesWrapper, { children: (() => {
291
+ const maxVisible = isMobile ? 1 : 4;
292
+ const visibleItems = qd.select.slice(0, maxVisible);
293
+ const hiddenCount = qd.select.length - maxVisible;
294
+ return (_jsxs(_Fragment, { children: [visibleItems.map((si, index) => {
295
+ const md = fromDTD?.metadata?.find(m => m.id === si.mid);
296
+ const mdName = md?.nameLoc ?? md?.name ?? `MID ${si.mid}`;
297
+ return (_jsxs(StyledSelectBadge, { children: [_jsx(IconColumns, { fontSize: 12 }), _jsx("span", { className: "badge-name", children: mdName })] }, `${si.tid}-${si.mid}-${index}`));
298
+ }), hiddenCount > 0 && (_jsxs(StyledSelectBadgeMore, { onClick: () => setShowOutputConfig(true), children: ["+", hiddenCount] }))] }));
299
+ })() }), _jsx(StyledSelectEditButton, { title: SDKUI_Localizator.Configure, onClick: () => setShowOutputConfig(true), children: _jsx(IconEdit, { fontSize: 16 }) })] })), qd?.orderBy && qd.orderBy.length > 0 && (_jsxs(StyledOrderByBadgesContainer, { children: [_jsxs(StyledOrderByLabel, { children: [qd.orderBy.length === 1 ? SDKUI_Localizator.SortBy : SDKUI_Localizator.SortByPlural, ":"] }), _jsx(StyledOrderByBadgesWrapper, { children: (() => {
300
+ const maxVisible = isMobile ? 1 : 4;
301
+ const visibleItems = qd.orderBy.slice(0, maxVisible);
302
+ const hiddenCount = qd.orderBy.length - maxVisible;
303
+ return (_jsxs(_Fragment, { children: [visibleItems.map((obi, index) => {
304
+ const md = fromDTD?.metadata?.find(m => m.id === obi.mid);
305
+ const mdName = md?.nameLoc ?? md?.name ?? `MID ${obi.mid}`;
306
+ return (_jsxs(StyledOrderByBadge, { children: [_jsx(TMTooltip, { content: obi.asc !== false ? SDKUI_Localizator.ValueAscending : SDKUI_Localizator.ValueDescending, children: obi.asc !== false ? (_jsx(IconSortAsc, { fontSize: 12 })) : (_jsx(IconSortDesc, { fontSize: 12 })) }), _jsx("span", { className: "badge-name", children: mdName })] }, `${obi.tid}-${obi.mid}-${index}`));
307
+ }), hiddenCount > 0 && (_jsxs(StyledOrderByBadgeMore, { onClick: () => setShowMetadataSorterForm(true), children: ["+", hiddenCount] }))] }));
308
+ })() }), _jsx(StyledOrderByEditButton, { title: SDKUI_Localizator.Configure, onClick: () => setShowMetadataSorterForm(true), children: _jsx(IconEdit, { fontSize: 16 }) })] })), _jsxs("div", { style: {
333
309
  display: 'flex',
334
310
  flexWrap: 'wrap',
335
311
  justifyContent: 'center',
@@ -338,8 +314,12 @@ const TMSearchQueryPanel = ({ fromDTD, showBackToResultButton, isExpertMode = SD
338
314
  width: '100%'
339
315
  }, children: [_jsx(TMButton, { btnStyle: 'advanced', icon: _jsx(IconSearch, {}), showTooltip: false, width: '90px', caption: SDKUI_Localizator.Search, advancedColor: '#4A96D2', onClick: handleSearchButtonClick }), _jsx(TMButton, { width: '90px', btnStyle: 'advanced', advancedType: 'primary', showTooltip: false, caption: SDKUI_Localizator.Clear, icon: _jsx(IconClear, {}), advancedColor: 'white', color: 'primaryOutline', onClick: clearFilters }), (!showAdvancedSearch && qd?.where && qd.where.length > initialMaxItems) && (_jsx(TMButton, { width: '120px', btnStyle: isMobile ? 'icon' : 'advanced', advancedColor: TMColors.button_primary, caption: captionText, showTooltip: false, icon: isMobile ? (_jsx("div", { children: _jsx("p", { children: showAllMdWhere ? `-${diff}` : `+${diff}` }) })) : (_jsx("p", { children: showAllMdWhere ? `-${diff}` : `+${diff}` })), onClick: () => setShowAllMdWhere(!showAllMdWhere) }))] }), showFiltersConfig &&
340
316
  _jsx(TMMetadataChooserForm, { allowMultipleSelection: true, height: '500px', width: '600px', allowSysMetadata: true, filterMetadata: (o => o.perm?.canSearch === AccessLevels.Yes), qd: qd, selectedIDs: qd?.where?.map((w) => ({ tid: w.tid, mid: w.mid })), onClose: handleCloseFiltersConfig, onChoose: handleChooseFilters }), showOutputConfig &&
341
- _jsx(TMMetadataChooserForm, { allowMultipleSelection: true, height: '500px', width: '600px', allowSysMetadata: true, filterMetadata: (o => o.perm?.canView === AccessLevels.Yes || o.perm?.canUpdate === AccessLevels.Yes), qd: qd, selectedIDs: qd?.select?.map((item) => ({ tid: item.tid, mid: item.mid })), onClose: handleCloseOutputConfig, onChoose: handleChooseOutput }), showOrderByConfig &&
342
- _jsx(TMMetadataChooserForm, { allowMultipleSelection: true, height: '500px', width: '600px', allowSysMetadata: true, filterMetadata: (o => o.perm?.canView === AccessLevels.Yes || o.perm?.canUpdate === AccessLevels.Yes), qd: qd, selectedIDs: qd?.orderBy?.map((item) => ({ tid: item.tid, mid: item.mid })), onClose: handleCloseOrderByConfig, onChoose: handleChooseOrderBy })] })
317
+ _jsx(TMMetadataOutputForm, { qd: qd, selectedSelectItems: qd?.select, allowSysMetadata: true, filterMetadata: (o => o.perm?.canView === AccessLevels.Yes || o.perm?.canUpdate === AccessLevels.Yes), onClose: handleCloseOutputConfig, onChoose: (selectItems) => {
318
+ setQd({ ...qd, select: selectItems });
319
+ } }), showMetadataSorterForm &&
320
+ _jsx(TMMetadataSorterForm, { qd: qd, selectedOrderByItems: qd?.orderBy, allowSysMetadata: true, filterMetadata: (o => o.perm?.canView === AccessLevels.Yes || o.perm?.canUpdate === AccessLevels.Yes), onClose: () => setShowMetadataSorterForm(false), onChoose: (orderByItems) => {
321
+ setQd({ ...qd, orderBy: orderByItems });
322
+ } })] })
343
323
  :
344
324
  _jsx(TMToppyMessage, { message: SDKUI_Localizator.DcmtTypeSelectOrQuickSearch, titleTooltip: SDKUI_Localizator.DcmtTypeSelectOrQuickSearch }), showSqdForm &&
345
325
  _jsx(StyledModalContainer, { style: { backgroundColor: `${TMColors.backgroundColorHeader}12` }, children: _jsx(TMSavedQueryForm, { height: '50%', width: '50%', id: formModeSqdForm === FormModes.Create ? -1 : SQD?.id, title: 'Ricerca rapida', formMode: formModeSqdForm, showBackButton: true, qd: qd, isAdvancedSearch: showAdvancedSearch, isModal: false, onClose: () => { setShowSqdForm(false); }, onSaved: onSqdSaved }) })] }), showDistinctValuesPanel &&
@@ -415,6 +395,174 @@ export const refreshLastSearch = async (qd) => {
415
395
  }
416
396
  return searchResults;
417
397
  };
398
+ // =============================================================================
399
+ // STYLED COMPONENTS per i badge degli ordinamenti
400
+ // =============================================================================
401
+ const StyledOrderByBadgesContainer = styled.div `
402
+ display: flex;
403
+ flex-wrap: wrap;
404
+ align-items: center;
405
+ gap: 8px;
406
+ padding: 6px 10px;
407
+ margin: 1px 0;
408
+ background: linear-gradient(135deg, rgba(74, 150, 210, 0.08) 0%, rgba(37, 89, 165, 0.08) 100%);
409
+ border-radius: 8px;
410
+ border: 1px solid rgba(74, 150, 210, 0.2);
411
+ `;
412
+ const StyledOrderByLabel = styled.span `
413
+ font-size: 0.82rem;
414
+ font-weight: 600;
415
+ color: #4A96D2;
416
+ white-space: nowrap;
417
+ `;
418
+ const StyledOrderByBadgesWrapper = styled.div `
419
+ display: flex;
420
+ flex-wrap: wrap;
421
+ gap: 6px;
422
+ align-items: center;
423
+ flex: 1;
424
+ `;
425
+ const StyledOrderByBadge = styled.div `
426
+ display: inline-flex;
427
+ align-items: center;
428
+ gap: 4px;
429
+ padding: 3px 8px;
430
+ background: white;
431
+ border: 1px solid #d1d9e6;
432
+ border-radius: 16px;
433
+ font-size: 0.82rem;
434
+ color: #333;
435
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
436
+
437
+ .badge-name {
438
+ max-width: 120px;
439
+ overflow: hidden;
440
+ text-overflow: ellipsis;
441
+ white-space: nowrap;
442
+
443
+ @media (max-width: 600px) {
444
+ max-width: 80px;
445
+ }
446
+ }
447
+ `;
448
+ const StyledOrderByBadgeMore = styled.div `
449
+ display: inline-flex;
450
+ align-items: center;
451
+ justify-content: center;
452
+ padding: 3px 10px;
453
+ background: linear-gradient(135deg, #4A96D2 0%, #2559A5 100%);
454
+ border: none;
455
+ border-radius: 16px;
456
+ font-size: 0.82rem;
457
+ font-weight: 600;
458
+ color: white;
459
+ cursor: pointer;
460
+ transition: all 0.2s ease;
461
+
462
+ &:hover {
463
+ transform: scale(1.05);
464
+ box-shadow: 0 2px 6px rgba(74, 150, 210, 0.4);
465
+ }
466
+ `;
467
+ const StyledOrderByEditButton = styled.div `
468
+ display: flex;
469
+ align-items: center;
470
+ justify-content: center;
471
+ width: 28px;
472
+ height: 28px;
473
+ border-radius: 4px;
474
+ color: #4A96D2;
475
+ cursor: pointer;
476
+ transition: all 0.2s ease;
477
+
478
+ &:hover {
479
+ background-color: rgba(74, 150, 210, 0.15);
480
+ }
481
+ `;
482
+ // =============================================================================
483
+ // STYLED COMPONENTS per i badge degli output (select) - colore verde/teal
484
+ // =============================================================================
485
+ const StyledSelectBadgesContainer = styled.div `
486
+ display: flex;
487
+ flex-wrap: wrap;
488
+ align-items: center;
489
+ gap: 8px;
490
+ padding: 6px 10px;
491
+ margin: 1px 0;
492
+ background: linear-gradient(135deg, rgba(46, 125, 50, 0.08) 0%, rgba(27, 94, 32, 0.08) 100%);
493
+ border-radius: 8px;
494
+ border: 1px solid rgba(46, 125, 50, 0.2);
495
+ `;
496
+ const StyledSelectLabel = styled.span `
497
+ font-size: 0.82rem;
498
+ font-weight: 600;
499
+ color: #2E7D32;
500
+ white-space: nowrap;
501
+ `;
502
+ const StyledSelectBadgesWrapper = styled.div `
503
+ display: flex;
504
+ flex-wrap: wrap;
505
+ gap: 6px;
506
+ align-items: center;
507
+ flex: 1;
508
+ `;
509
+ const StyledSelectBadge = styled.div `
510
+ display: inline-flex;
511
+ align-items: center;
512
+ gap: 4px;
513
+ padding: 3px 8px;
514
+ background: white;
515
+ border: 1px solid #c8e6c9;
516
+ border-radius: 16px;
517
+ font-size: 0.82rem;
518
+ color: #333;
519
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
520
+
521
+ .badge-name {
522
+ max-width: 120px;
523
+ overflow: hidden;
524
+ text-overflow: ellipsis;
525
+ white-space: nowrap;
526
+
527
+ @media (max-width: 600px) {
528
+ max-width: 80px;
529
+ }
530
+ }
531
+ `;
532
+ const StyledSelectBadgeMore = styled.div `
533
+ display: inline-flex;
534
+ align-items: center;
535
+ justify-content: center;
536
+ padding: 3px 10px;
537
+ background: linear-gradient(135deg, #43A047 0%, #2E7D32 100%);
538
+ border: none;
539
+ border-radius: 16px;
540
+ font-size: 0.82rem;
541
+ font-weight: 600;
542
+ color: white;
543
+ cursor: pointer;
544
+ transition: all 0.2s ease;
545
+
546
+ &:hover {
547
+ transform: scale(1.05);
548
+ box-shadow: 0 2px 6px rgba(46, 125, 50, 0.4);
549
+ }
550
+ `;
551
+ const StyledSelectEditButton = styled.div `
552
+ display: flex;
553
+ align-items: center;
554
+ justify-content: center;
555
+ width: 28px;
556
+ height: 28px;
557
+ border-radius: 4px;
558
+ color: #2E7D32;
559
+ cursor: pointer;
560
+ transition: all 0.2s ease;
561
+
562
+ &:hover {
563
+ background-color: rgba(46, 125, 50, 0.15);
564
+ }
565
+ `;
418
566
  export const StyledToppyTextContainer = styled.div `
419
567
  padding: 22px 8px;
420
568
  width: 100%;
@@ -433,11 +581,13 @@ export const StyledToppyText = styled.p `
433
581
  font-size: 1rem;
434
582
  user-select: none;
435
583
  -webkit-touch-callout: none;
436
- -webkit-user-select: none;
584
+ -webkit-user-select: none;
585
+ -moz-user-select: none;
586
+ -ms-user-select: none;
437
587
  margin: 0;
438
588
  display: -webkit-box;
439
589
  -webkit-box-orient: vertical;
440
- -webkit-line-clamp: 3; /* non è una proprietà standard ma è così diffusa e ben supportata che è considerata una "best practice pragmatica" */
590
+ -webkit-line-clamp: 3;
441
591
  overflow: hidden;
442
592
  text-overflow: ellipsis;
443
593
  white-space: normal;
@@ -0,0 +1,16 @@
1
+ import { DcmtTypeDescriptor, MetadataDescriptor, QueryDescriptor } from "@topconsultnpm/sdk-ts";
2
+ export type MetadataDescriptorWithKey = MetadataDescriptor & {
3
+ uniqueKey: string;
4
+ };
5
+ export declare function removeDuplicatesByTidMid<T extends {
6
+ tid?: number;
7
+ mid?: number;
8
+ }>(items: T[]): T[];
9
+ export declare function loadMetadataFromQd(qd: QueryDescriptor | undefined, filterMetadata?: (value: MetadataDescriptor, index: number, array: MetadataDescriptor[]) => unknown): Promise<{
10
+ metadata: MetadataDescriptorWithKey[];
11
+ dcmtTypes: DcmtTypeDescriptor[];
12
+ }>;
13
+ export declare function areArraysEqual<T extends {
14
+ tid?: number;
15
+ mid?: number;
16
+ }>(arr1: T[], arr2: T[], additionalCompare?: (a: T, b: T) => boolean): boolean;
@@ -0,0 +1,77 @@
1
+ import { DcmtTypeDescriptor, DcmtTypeListCacheService, SDK_Localizator } from "@topconsultnpm/sdk-ts";
2
+ import { getTIDsByQd } from "../../../helper/queryHelper";
3
+ import { SDKUI_Localizator } from "../../../helper";
4
+ import TMSpinner from "../../base/TMSpinner";
5
+ // =============================================================================
6
+ // HELPER: Rimuove duplicati dalla lista (basato su tid + mid)
7
+ // =============================================================================
8
+ export function removeDuplicatesByTidMid(items) {
9
+ const seen = new Set();
10
+ return items.filter(item => {
11
+ const key = `${item.tid}_${item.mid}`;
12
+ if (seen.has(key))
13
+ return false;
14
+ seen.add(key);
15
+ return true;
16
+ });
17
+ }
18
+ // =============================================================================
19
+ // FUNZIONE PRINCIPALE: Estrae i metadati dal QueryDescriptor
20
+ // =============================================================================
21
+ export async function loadMetadataFromQd(qd, filterMetadata) {
22
+ if (!qd)
23
+ return { metadata: [], dcmtTypes: [] };
24
+ const dtdList = [];
25
+ const metadata = [];
26
+ try {
27
+ const tidsFromQd = getTIDsByQd(qd);
28
+ const inputTIDs = tidsFromQd.map((item) => item.tid);
29
+ if (inputTIDs.length === 0)
30
+ return { metadata: [], dcmtTypes: [] };
31
+ TMSpinner.show({ description: `${SDKUI_Localizator.Loading} - ${SDK_Localizator.DcmtType} ...` });
32
+ const dtds = await DcmtTypeListCacheService.GetFromTIDsAsync(inputTIDs, true, undefined, false, false);
33
+ for (let i = 0; i < dtds.length; i++) {
34
+ const dtd = new DcmtTypeDescriptor();
35
+ dtd.init({ ...dtds[i] });
36
+ const alias = tidsFromQd?.[i]?.alias ?? '';
37
+ dtd.customData2 = alias;
38
+ dtd.metadata?.forEach((md) => {
39
+ const mdWithKey = md;
40
+ mdWithKey.customData1 = dtd.id;
41
+ mdWithKey.customData2 = alias;
42
+ mdWithKey.uniqueKey = `${dtd.id}_${md.id}_${alias}`;
43
+ });
44
+ const filteredMetadata = filterMetadata
45
+ ? dtd.metadata?.filter(filterMetadata)
46
+ : dtd.metadata;
47
+ dtdList.push({ ...dtd, metadata: filteredMetadata });
48
+ }
49
+ for (const dtd of dtdList) {
50
+ if (!dtd.metadata)
51
+ continue;
52
+ for (const md of dtd.metadata) {
53
+ metadata.push(md);
54
+ }
55
+ }
56
+ return { metadata, dcmtTypes: dtdList };
57
+ }
58
+ finally {
59
+ TMSpinner.hide();
60
+ }
61
+ }
62
+ // =============================================================================
63
+ // HELPER: Confronta due array per determinare se sono stati modificati
64
+ // =============================================================================
65
+ export function areArraysEqual(arr1, arr2, additionalCompare) {
66
+ if (arr1.length !== arr2.length)
67
+ return false;
68
+ for (let i = 0; i < arr1.length; i++) {
69
+ const a = arr1[i];
70
+ const b = arr2[i];
71
+ if (a.tid !== b.tid || a.mid !== b.mid)
72
+ return false;
73
+ if (additionalCompare && !additionalCompare(a, b))
74
+ return false;
75
+ }
76
+ return true;
77
+ }
@@ -487,6 +487,8 @@ export declare class SDKUI_Localizator {
487
487
  static get NoDataToDisplay(): "Keine Daten zum Anzeigen" | "No data to display" | "No hay datos para mostrar" | "Aucune donnée à afficher" | "Sem dados para exibir" | "Nessun dato da visualizzare";
488
488
  static get NoDcmtFound(): "Kein Dokument gefunden" | "No documents found" | "Ningún documento encontrado" | "Pas de documents trouvés" | "Nenhum documento encontrado" | "Nessun documento trovato";
489
489
  static get NoDcmtSelected(): string;
490
+ static get NoSortingApplied(): string;
491
+ static get NoOutputMetadata(): string;
490
492
  static get NoDetailDocumentFoundForArchiving(): "Kein Detaildokument zur Archivierung gefunden." | "No detail document found for archiving." | "No se encontró ningún documento de detalle para archivar." | "Aucun document détail trouvé pour l'archivage." | "Nenhum documento de detalhe encontrado para arquivamento." | "Nessun documento di dettaglio trovato per l'archiviazione.";
491
493
  static get NoDocumentMatchFound(): "Kein zugeordnetes Dokument gefunden." | "No document match found." | "No se encontró ningún documento emparejado." | "Aucun document associé trouvé." | "Nenhum documento correspondente encontrado." | "Nessun documento abbinato trovato.";
492
494
  static get NoDocumentSelectedForManyToManyMatching(): "Kein Dokument für die Mehrfach-Zuordnung ausgewählt." | "No document selected for many-to-many matching." | "Ningún documento seleccionado para el emparejamiento de muchos a muchos." | "Aucun document sélectionné pour l'association plusieurs à plusieurs." | "Nenhum documento selecionado para correspondência de muitos para muitos." | "Nessun documento selezionato per l'abbinamento molti a molti.";
@@ -738,6 +740,7 @@ export declare class SDKUI_Localizator {
738
740
  static get SignatureType(): string;
739
741
  static get Size(): "Größe" | "Size" | "Dimensión" | "Dimension" | "Tamanho" | "Dimensione";
740
742
  static get SortBy(): "Sortieren nach" | "Sort by" | "Ordenar por" | "Trier par" | "Ordinamento";
743
+ static get SortByPlural(): "Sortierungen" | "Sortings" | "Ordenaciones" | "Tris" | "Ordenações" | "Ordinamenti";
741
744
  static get Source(): "Ursprung" | "Source" | "Origen" | "Origem" | "Origine";
742
745
  static get SpecialOperators(): "Spezielle Operatoren" | "Special operators" | "Operadores especiales" | "Opérateurs spéciaux" | "Os operadores especiais" | "Operatori speciali";
743
746
  static get StandardMode(): "Standardmodus" | "Standard mode" | "Modo estándar" | "Mode standard" | "Modo padrão" | "Modalità standard";
@@ -4830,6 +4830,26 @@ export class SDKUI_Localizator {
4830
4830
  default: return "Nessun documento selezionato";
4831
4831
  }
4832
4832
  }
4833
+ static get NoSortingApplied() {
4834
+ switch (this._cultureID) {
4835
+ case CultureIDs.De_DE: return "Keine Sortierung angewendet";
4836
+ case CultureIDs.En_US: return "No sorting applied";
4837
+ case CultureIDs.Es_ES: return "Ningún ordenamiento aplicado";
4838
+ case CultureIDs.Fr_FR: return "Aucun tri appliqué";
4839
+ case CultureIDs.Pt_PT: return "Nenhuma ordenação aplicada";
4840
+ default: return "Nessun ordinamento applicato";
4841
+ }
4842
+ }
4843
+ static get NoOutputMetadata() {
4844
+ switch (this._cultureID) {
4845
+ case CultureIDs.De_DE: return "Keine Ausgabemetadaten ausgewählt";
4846
+ case CultureIDs.En_US: return "No output metadata selected";
4847
+ case CultureIDs.Es_ES: return "Ningún metadato de salida seleccionado";
4848
+ case CultureIDs.Fr_FR: return "Aucune métadonnée de sortie sélectionnée";
4849
+ case CultureIDs.Pt_PT: return "Nenhum metadado de saída selecionado";
4850
+ default: return "Nessun metadato di output selezionato";
4851
+ }
4852
+ }
4833
4853
  static get NoDetailDocumentFoundForArchiving() {
4834
4854
  switch (this._cultureID) {
4835
4855
  case CultureIDs.De_DE: return "Kein Detaildokument zur Archivierung gefunden.";
@@ -7360,6 +7380,16 @@ export class SDKUI_Localizator {
7360
7380
  default: return "Ordinamento";
7361
7381
  }
7362
7382
  }
7383
+ static get SortByPlural() {
7384
+ switch (this._cultureID) {
7385
+ case CultureIDs.De_DE: return "Sortierungen";
7386
+ case CultureIDs.En_US: return "Sortings";
7387
+ case CultureIDs.Es_ES: return "Ordenaciones";
7388
+ case CultureIDs.Fr_FR: return "Tris";
7389
+ case CultureIDs.Pt_PT: return "Ordenações";
7390
+ default: return "Ordinamenti";
7391
+ }
7392
+ }
7363
7393
  static get Source() {
7364
7394
  switch (this._cultureID) {
7365
7395
  case CultureIDs.De_DE: return "Ursprung";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.21.0-dev3.16",
3
+ "version": "6.21.0-dev3.18",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",