@topconsultnpm/sdkui-react 6.22.0-dev2.16 → 6.22.0-dev2.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.
Files changed (59) hide show
  1. package/lib/components/base/TMEditorBase.d.ts +2 -0
  2. package/lib/components/base/TMTooltip.d.ts +2 -1
  3. package/lib/components/base/TMTooltip.js +23 -6
  4. package/lib/components/choosers/TMDcmtTypeChooser.js +4 -3
  5. package/lib/components/choosers/TMDistinctValues.d.ts +9 -7
  6. package/lib/components/choosers/TMDistinctValues.js +147 -195
  7. package/lib/components/choosers/TMMetadataChooser.js +1 -1
  8. package/lib/components/choosers/TMQuickSearchInfo.d.ts +12 -0
  9. package/lib/components/choosers/TMQuickSearchInfo.js +279 -0
  10. package/lib/components/choosers/TMQuickSearchSettingsForm.d.ts +16 -0
  11. package/lib/components/choosers/TMQuickSearchSettingsForm.js +94 -0
  12. package/lib/components/choosers/TMSelectedValuesSummary.d.ts +13 -0
  13. package/lib/components/choosers/TMSelectedValuesSummary.js +91 -0
  14. package/lib/components/editors/TMDropDown.d.ts +3 -0
  15. package/lib/components/editors/TMDropDown.js +197 -5
  16. package/lib/components/features/documents/TMDcmtForm.js +10 -2
  17. package/lib/components/features/documents/TMDcmtFormActionButtons.d.ts +11 -0
  18. package/lib/components/features/documents/TMDcmtFormActionButtons.js +74 -7
  19. package/lib/components/features/search/TMSearchResult.js +55 -4
  20. package/lib/components/features/workflow/TMWorkflowPopup.d.ts +10 -0
  21. package/lib/components/features/workflow/TMWorkflowPopup.js +8 -4
  22. package/lib/components/viewers/TMMidViewer.js +4 -1
  23. package/lib/components/viewers/TMTidViewer.js +25 -11
  24. package/lib/helper/SDKUI_Globals.d.ts +20 -0
  25. package/lib/helper/SDKUI_Globals.js +44 -0
  26. package/lib/helper/SDKUI_Localizator.d.ts +1 -0
  27. package/lib/helper/SDKUI_Localizator.js +10 -0
  28. package/lib/helper/dataGridSearchHelper.d.ts +28 -0
  29. package/lib/helper/dataGridSearchHelper.js +51 -0
  30. package/lib/helper/index.d.ts +1 -0
  31. package/lib/helper/index.js +1 -0
  32. package/lib/helper/queryHelper.d.ts +2 -0
  33. package/lib/helper/queryHelper.js +3 -1
  34. package/lib/hooks/tmDistinctValuesGridHelper.d.ts +16 -0
  35. package/lib/hooks/tmDistinctValuesGridHelper.js +31 -0
  36. package/lib/hooks/useCaseFlowApprove.d.ts +56 -0
  37. package/lib/hooks/useCaseFlowApprove.js +157 -0
  38. package/lib/hooks/useTMDistinctValuesMetadataDisplay.d.ts +18 -0
  39. package/lib/hooks/useTMDistinctValuesMetadataDisplay.js +103 -0
  40. package/lib/hooks/useTMDistinctValuesQuickSearch.d.ts +49 -0
  41. package/lib/hooks/useTMDistinctValuesQuickSearch.js +307 -0
  42. package/lib/hooks/useTMDistinctValuesSelection.d.ts +42 -0
  43. package/lib/hooks/useTMDistinctValuesSelection.js +103 -0
  44. package/lib/hooks/useTMDistinctValuesSource.d.ts +29 -0
  45. package/lib/hooks/useTMDistinctValuesSource.js +105 -0
  46. package/lib/index.d.ts +1 -0
  47. package/lib/index.js +1 -0
  48. package/lib/services/caseflow/CaseFlowService.d.ts +208 -0
  49. package/lib/services/caseflow/CaseFlowService.js +623 -0
  50. package/lib/services/caseflow/CaseFlowTemplateCacheService.d.ts +28 -0
  51. package/lib/services/caseflow/CaseFlowTemplateCacheService.js +121 -0
  52. package/lib/services/caseflow/caseFlowNameCache.d.ts +32 -0
  53. package/lib/services/caseflow/caseFlowNameCache.js +116 -0
  54. package/lib/services/caseflow/caseFlowWorkItemUtils.d.ts +61 -0
  55. package/lib/services/caseflow/caseFlowWorkItemUtils.js +113 -0
  56. package/lib/services/index.d.ts +4 -0
  57. package/lib/services/index.js +4 -0
  58. package/lib/services/platform_services.d.ts +1 -1
  59. package/package.json +1 -1
@@ -259,7 +259,7 @@ export const TMDcmtTypeIcon = ({ dtd }) => {
259
259
  return (_jsx(TMDcmtTypeTooltip, { dtd: dtd, children: icon }));
260
260
  };
261
261
  export const TMDcmtTypeTooltip = ({ dtd, children }) => {
262
- return (_jsx("div", { style: { pointerEvents: 'all' }, children: _jsx(TMTooltip, { content: renderDTDTooltipContent(dtd), children: children }) }));
262
+ return (_jsx("div", { style: { pointerEvents: 'all' }, children: _jsx(TMTooltip, { allowContentInteraction: true, content: renderDTDTooltipContent(dtd), children: children }) }));
263
263
  };
264
264
  const TMTidViewer = ({ tmSession, tid, did, showIcon = false, color, showId = false, noneSelectionText = `<${SDKUI_Localizator.NoneSelection}>` }) => {
265
265
  const [dtd, setDtd] = useState();
@@ -297,29 +297,43 @@ const TMTidViewer = ({ tmSession, tid, did, showIcon = false, color, showId = fa
297
297
  textOverflow: 'ellipsis'
298
298
  }, children: [showIcon && dtd && _jsx(TMDcmtTypeIcon, { dtd: dtd }), _jsx("p", { title: displayName(), style: {
299
299
  textAlign: 'left',
300
+ margin: 0,
300
301
  marginLeft: showIcon ? '5px' : '',
301
- color: color ?? (dtd?.isView ? 'red' : TMColors.primary),
302
+ color: dtd?.isView ? 'red' : (color ?? TMColors.primary),
302
303
  whiteSpace: 'nowrap',
303
304
  overflow: 'hidden',
304
305
  textOverflow: 'ellipsis',
305
306
  // paddingRight: '10px'
306
- }, children: displayName() }), showId && _jsx("p", { style: { padding: '0px 3px' }, children: `(TID: ${tid})` })] }));
307
+ }, children: displayName() }), showId && _jsx("p", { style: { padding: '0px 3px', margin: 0 }, children: `(TID: ${tid})` })] }));
307
308
  };
308
309
  export default TMTidViewer;
309
310
  export const cellRenderTID = (data, noneSelectionText) => {
310
311
  return (_jsx(TMTidViewer, { tid: data.value, noneSelectionText: noneSelectionText }));
311
312
  };
312
- /** Componente per mostrare il metodo di visualizzazione del nome documento (carica i metadati dalla cache se necessario) */
313
+ /** Metodi di visualizzazione già richiesti, per non ricaricare i metadati ad ogni riapertura del tooltip */
314
+ const displayNameMethodCache = new Map();
313
315
  const TMDisplayNameMethodItem = ({ dtd }) => {
314
- const [displayNameMethod, setDisplayNameMethod] = useState('...');
315
- useEffect(() => {
316
- const fetchDisplayNameMethod = async () => {
316
+ const [displayNameMethod, setDisplayNameMethod] = useState(() => dtd.id ? displayNameMethodCache.get(dtd.id) : undefined);
317
+ const [isLoading, setIsLoading] = useState(false);
318
+ const onShowClick = async (e) => {
319
+ /* Un click qualsiasi chiude il tooltip: senza questo il risultato non sarebbe mai visibile */
320
+ e.stopPropagation();
321
+ if (isLoading || displayNameMethod)
322
+ return;
323
+ setIsLoading(true);
324
+ try {
317
325
  const method = await getDTDDisplayNameInfo(dtd);
326
+ if (dtd.id)
327
+ displayNameMethodCache.set(dtd.id, method);
318
328
  setDisplayNameMethod(method);
319
- };
320
- fetchDisplayNameMethod();
321
- }, [dtd]);
322
- return _jsx(StyledTooltipItem, { children: `${SDKUI_Localizator.DisplayNameMethod}: ${displayNameMethod}` });
329
+ }
330
+ finally {
331
+ setIsLoading(false);
332
+ }
333
+ };
334
+ return (_jsxs(StyledTooltipItem, { children: [`${SDKUI_Localizator.DisplayNameMethod}: `, displayNameMethod ?? (isLoading
335
+ ? `${SDKUI_Localizator.Loading} ...`
336
+ : _jsx("span", { style: { color: TMColors.primary, cursor: 'pointer', textDecoration: 'underline' }, onClick: onShowClick, children: SDKUI_Localizator.Details }))] }));
323
337
  };
324
338
  export const renderDTDTooltipContent = (dtd) => {
325
339
  const mapAccessLevelToLocalizedString = (level) => {
@@ -67,6 +67,18 @@ export declare class ThemeSettings {
67
67
  export declare const DEFAULT_PREVIEW_THRESHOLD = 500;
68
68
  export declare const DEFAULT_PAGE_SIZE = 100;
69
69
  export declare const DEFAULT_MAX_DCMTS_TO_BE_RETURNED = 200;
70
+ export declare const DEFAULT_QUICK_SEARCH_MAX_DCMTS = 1000;
71
+ /** Ricerca rapida configurata come sorgente alternativa dei valori distinti di un campo */
72
+ export declare class DistinctValuesQuickSearchSettings {
73
+ /** Tipo documento su cui viene eseguita la ricerca rapida */
74
+ tid: number | undefined;
75
+ /** ID della ricerca salvata (SavedQueryDescriptor) da eseguire; SYS_ALL_DCMTS_SQD_ID per la ricerca di sistema con tutti i documenti del tipo documento */
76
+ sqdId: number | undefined;
77
+ /** Metadato del risultato da cui viene prelevato il valore */
78
+ mid: number | undefined;
79
+ /** Numero massimo di documenti restituiti dalla ricerca rapida */
80
+ maxDcmtsToBeReturned: number;
81
+ }
70
82
  export declare class SearchSettings {
71
83
  autoFindReferences: ObjectClasses[];
72
84
  invoiceRetrieveFormat: InvoiceRetrieveFormats;
@@ -86,7 +98,15 @@ export declare class SearchSettings {
86
98
  };
87
99
  relationExpandLevel: number;
88
100
  relationShowZeroDcmts: boolean;
101
+ /** Ricerche rapide configurate per i valori distinti: una per ogni campo, con chiave "tid_mid" */
102
+ distinctValuesQuickSearches: {
103
+ [fieldKey: string]: DistinctValuesQuickSearchSettings;
104
+ };
89
105
  }
106
+ /** Ricerca rapida configurata per il campo, se presente */
107
+ export declare const getDistinctValuesQuickSearch: (tid: number | undefined, mid: number | undefined) => DistinctValuesQuickSearchSettings | undefined;
108
+ export declare const saveDistinctValuesQuickSearch: (tid: number | undefined, mid: number | undefined, settings: DistinctValuesQuickSearchSettings) => void;
109
+ export declare const removeDistinctValuesQuickSearch: (tid: number | undefined, mid: number | undefined) => void;
90
110
  export declare class FloatingMenuBarSettings {
91
111
  orientation?: 'horizontal' | 'vertical';
92
112
  itemIds?: string[];
@@ -130,6 +130,20 @@ export class ThemeSettings {
130
130
  export const DEFAULT_PREVIEW_THRESHOLD = 500; // KB
131
131
  export const DEFAULT_PAGE_SIZE = 100;
132
132
  export const DEFAULT_MAX_DCMTS_TO_BE_RETURNED = 200;
133
+ export const DEFAULT_QUICK_SEARCH_MAX_DCMTS = 1000;
134
+ /** Ricerca rapida configurata come sorgente alternativa dei valori distinti di un campo */
135
+ export class DistinctValuesQuickSearchSettings {
136
+ constructor() {
137
+ /** Tipo documento su cui viene eseguita la ricerca rapida */
138
+ this.tid = undefined;
139
+ /** ID della ricerca salvata (SavedQueryDescriptor) da eseguire; SYS_ALL_DCMTS_SQD_ID per la ricerca di sistema con tutti i documenti del tipo documento */
140
+ this.sqdId = undefined;
141
+ /** Metadato del risultato da cui viene prelevato il valore */
142
+ this.mid = undefined;
143
+ /** Numero massimo di documenti restituiti dalla ricerca rapida */
144
+ this.maxDcmtsToBeReturned = DEFAULT_QUICK_SEARCH_MAX_DCMTS;
145
+ }
146
+ }
133
147
  export class SearchSettings {
134
148
  constructor() {
135
149
  this.autoFindReferences = [];
@@ -144,8 +158,38 @@ export class SearchSettings {
144
158
  this.panelLayout = {};
145
159
  this.relationExpandLevel = 4; // Livello di espansione predefinito per le correlazioni
146
160
  this.relationShowZeroDcmts = false;
161
+ /** Ricerche rapide configurate per i valori distinti: una per ogni campo, con chiave "tid_mid" */
162
+ this.distinctValuesQuickSearches = {};
147
163
  }
148
164
  }
165
+ /** Il campo da cui viene aperto il pannello dei valori distinti è identificato dalla coppia (tid, mid) */
166
+ const distinctValuesFieldKey = (tid, mid) => `${tid}_${mid}`;
167
+ /** Ricerca rapida configurata per il campo, se presente */
168
+ export const getDistinctValuesQuickSearch = (tid, mid) => {
169
+ if (!tid || !mid)
170
+ return undefined;
171
+ // Le impostazioni salvate da versioni precedenti non hanno la mappa: va gestita l'assenza
172
+ return SDKUI_Globals.userSettings.searchSettings.distinctValuesQuickSearches?.[distinctValuesFieldKey(tid, mid)];
173
+ };
174
+ export const saveDistinctValuesQuickSearch = (tid, mid, settings) => {
175
+ if (!tid || !mid)
176
+ return;
177
+ // Il proxy delle impostazioni persiste solo intercettando l'assegnazione di una proprietà: la mappa va riassegnata per intero
178
+ SDKUI_Globals.userSettings.searchSettings.distinctValuesQuickSearches = {
179
+ ...SDKUI_Globals.userSettings.searchSettings.distinctValuesQuickSearches,
180
+ [distinctValuesFieldKey(tid, mid)]: settings,
181
+ };
182
+ };
183
+ export const removeDistinctValuesQuickSearch = (tid, mid) => {
184
+ if (!tid || !mid)
185
+ return;
186
+ const fieldKey = distinctValuesFieldKey(tid, mid);
187
+ const quickSearches = SDKUI_Globals.userSettings.searchSettings.distinctValuesQuickSearches;
188
+ if (!quickSearches?.[fieldKey])
189
+ return;
190
+ const { [fieldKey]: removedSettings, ...remainingQuickSearches } = quickSearches;
191
+ SDKUI_Globals.userSettings.searchSettings.distinctValuesQuickSearches = remainingQuickSearches;
192
+ };
149
193
  export class FloatingMenuBarSettings {
150
194
  }
151
195
  export class ArchivingSettings {
@@ -657,6 +657,7 @@ export declare class SDKUI_Localizator {
657
657
  static get QueryDefine(): "Abfrage definieren" | "Query define" | "Definir consulta" | "Défine query" | "Definir query" | "Definisci query";
658
658
  static get Query_EnterAlias(): "Geben Sie einen Alias ​​ein" | "Enter an alias" | "Introducir un alias" | "Entrez un alias" | "Digite um nome de alias" | "Inserire un alias";
659
659
  static get QueryParamBind(): "Query-Parameter erweitern" | "Fill query parameters" | "Valorizar parámetros consulta" | "Ajoute la valeur à les paramètres de la query" | "Melhora parâmetros de query" | "Valorizza parametri query";
660
+ static get QuickSearchSettings_DeleteConfirmFor1(): "Schnellsuche-Konfiguration für '{{0}}' löschen?" | "Delete the quick search setup for '{{0}}'?" | "¿Eliminar la configuración de la búsqueda rápida de '{{0}}'?" | "Supprimer la configuration de la recherche rapide de '{{0}}' ?" | "Eliminar a configuração da pesquisa rápida de '{{0}}'?" | "Eliminare la configurazione della ricerca rapida di '{{0}}'?";
660
661
  static get ReadOnly(): "Nur Lesen" | "Read only" | "Solo lectura" | "En lecture seule" | "Somente leitura" | "Solo lettura";
661
662
  static get Reassign(): "Neu zuweisen" | "Reassign" | "Reasignar" | "Réaffecter" | "Reatribuir" | "Riassegna";
662
663
  static get RefersTo(): string;
@@ -6542,6 +6542,16 @@ export class SDKUI_Localizator {
6542
6542
  default: return "Valorizza parametri query";
6543
6543
  }
6544
6544
  }
6545
+ static get QuickSearchSettings_DeleteConfirmFor1() {
6546
+ switch (this._cultureID) {
6547
+ case CultureIDs.De_DE: return "Schnellsuche-Konfiguration für '{{0}}' löschen?";
6548
+ case CultureIDs.En_US: return "Delete the quick search setup for '{{0}}'?";
6549
+ case CultureIDs.Es_ES: return "¿Eliminar la configuración de la búsqueda rápida de '{{0}}'?";
6550
+ case CultureIDs.Fr_FR: return "Supprimer la configuration de la recherche rapide de '{{0}}' ?";
6551
+ case CultureIDs.Pt_PT: return "Eliminar a configuração da pesquisa rápida de '{{0}}'?";
6552
+ default: return "Eliminare la configurazione della ricerca rapida di '{{0}}'?";
6553
+ }
6554
+ }
6545
6555
  static get ReadOnly() {
6546
6556
  switch (this._cultureID) {
6547
6557
  case CultureIDs.De_DE: return "Nur Lesen";
@@ -0,0 +1,28 @@
1
+ import { MetadataFormats } from '@topconsultnpm/sdk-ts';
2
+ /** Testo mostrato in una colonna per una riga: è quello su cui va cercato ciò che l'utente digita */
3
+ export type SearchTextGetter = (rowData: any) => string;
4
+ /** Testo con cui una data viene mostrata nella griglia: è quello che l'utente vede e quindi quello che cerca */
5
+ export declare const getDateDisplayText: (value: any, format: MetadataFormats | undefined, formatCulture: string | undefined | null) => string;
6
+ /** Testo con cui un numero viene mostrato nella griglia (separatore delle migliaia, valuta, decimali) */
7
+ export declare const getNumberDisplayText: (value: any, format: MetadataFormats | undefined, formatCulture: string) => string;
8
+ /**
9
+ * Dirotta la ricerca della griglia sul testo mostrato, per le colonne indicate (chiave: il `dataField`).
10
+ *
11
+ * La ricerca di DevExtreme lavora sul valore archiviato, quindi non trova nulla dove il testo mostrato è
12
+ * diverso:
13
+ * - **date**, che nei dati sono stringhe ISO: DevExtreme prova a interpretare il testo digitato con il
14
+ * formato della colonna, non riesce (il formato è un formatter personalizzato, non un pattern) e scarta
15
+ * la colonna dalla ricerca — cercando `29/01/2023` non trova nulla;
16
+ * - **numeri formattati**, per lo stesso motivo (separatore delle migliaia, simbolo di valuta);
17
+ * - **liste dati e utenti**, dove viene confrontata la chiave archiviata invece della descrizione
18
+ * visualizzata — cercando `FATTURA` non trova nulla, cercando `TD01` sì.
19
+ *
20
+ * Da passare a `customizeColumns` della griglia. Va fatto lì perché solo lì è disponibile la
21
+ * `calculateFilterExpression` predefinita di DevExtreme, che resta in uso per il filtro di intestazione e
22
+ * per il generatore di filtri: quelli funzionano già correttamente e vanno lasciati intatti.
23
+ *
24
+ * @example
25
+ * const searchTextGetters = useMemo(() => new Map([['TM_1_2', (row) => getDateDisplayText(row?.TM_1_2, format, culture)]]), [...]);
26
+ * const customizeColumns = useMemo(() => customizeSearchByDisplayText(searchTextGetters), [searchTextGetters]);
27
+ */
28
+ export declare const customizeSearchByDisplayText: (searchTextGetters: Map<string, SearchTextGetter>) => (columns: Array<any>) => void;
@@ -0,0 +1,51 @@
1
+ import { formatDateTimeByMetadataFormat, formatNumberByMetadataFormat } from './TMUtils';
2
+ /** Testo con cui una data viene mostrata nella griglia: è quello che l'utente vede e quindi quello che cerca */
3
+ export const getDateDisplayText = (value, format, formatCulture) => {
4
+ if (value === undefined || value === null || value === '')
5
+ return '';
6
+ const date = value instanceof Date ? value : new Date(value);
7
+ return Number.isNaN(date.getTime()) ? '' : formatDateTimeByMetadataFormat(date, format, formatCulture);
8
+ };
9
+ /** Testo con cui un numero viene mostrato nella griglia (separatore delle migliaia, valuta, decimali) */
10
+ export const getNumberDisplayText = (value, format, formatCulture) => {
11
+ if (value === undefined || value === null || value === '')
12
+ return '';
13
+ return formatNumberByMetadataFormat(value, format, formatCulture);
14
+ };
15
+ /**
16
+ * Dirotta la ricerca della griglia sul testo mostrato, per le colonne indicate (chiave: il `dataField`).
17
+ *
18
+ * La ricerca di DevExtreme lavora sul valore archiviato, quindi non trova nulla dove il testo mostrato è
19
+ * diverso:
20
+ * - **date**, che nei dati sono stringhe ISO: DevExtreme prova a interpretare il testo digitato con il
21
+ * formato della colonna, non riesce (il formato è un formatter personalizzato, non un pattern) e scarta
22
+ * la colonna dalla ricerca — cercando `29/01/2023` non trova nulla;
23
+ * - **numeri formattati**, per lo stesso motivo (separatore delle migliaia, simbolo di valuta);
24
+ * - **liste dati e utenti**, dove viene confrontata la chiave archiviata invece della descrizione
25
+ * visualizzata — cercando `FATTURA` non trova nulla, cercando `TD01` sì.
26
+ *
27
+ * Da passare a `customizeColumns` della griglia. Va fatto lì perché solo lì è disponibile la
28
+ * `calculateFilterExpression` predefinita di DevExtreme, che resta in uso per il filtro di intestazione e
29
+ * per il generatore di filtri: quelli funzionano già correttamente e vanno lasciati intatti.
30
+ *
31
+ * @example
32
+ * const searchTextGetters = useMemo(() => new Map([['TM_1_2', (row) => getDateDisplayText(row?.TM_1_2, format, culture)]]), [...]);
33
+ * const customizeColumns = useMemo(() => customizeSearchByDisplayText(searchTextGetters), [searchTextGetters]);
34
+ */
35
+ export const customizeSearchByDisplayText = (searchTextGetters) => (columns) => {
36
+ columns.forEach((column) => {
37
+ const getSearchText = column?.dataField ? searchTextGetters.get(column.dataField) : undefined;
38
+ // customizeColumns viene richiamata a ogni aggiornamento delle colonne: senza il marcatore i wrapper si anniderebbero
39
+ if (!getSearchText || column.tmSearchByDisplayText)
40
+ return;
41
+ const defaultCalculateFilterExpression = column.calculateFilterExpression;
42
+ // Senza questo DevExtreme prova a convertire il testo digitato nel tipo della colonna e, non riuscendo, la scarta
43
+ column.parseValue = (text) => text;
44
+ column.calculateFilterExpression = function (filterValue, selectedFilterOperation, target) {
45
+ if (target === 'search')
46
+ return [getSearchText, 'contains', filterValue];
47
+ return defaultCalculateFilterExpression?.apply(this, arguments);
48
+ };
49
+ column.tmSearchByDisplayText = true;
50
+ });
51
+ };
@@ -5,6 +5,7 @@ export * from './Globalization';
5
5
  export * from './TMIcons';
6
6
  export * from './TMImageLibrary';
7
7
  export * from './helpers';
8
+ export * from './dataGridSearchHelper';
8
9
  export * from './queryHelper';
9
10
  export * from './TMUtils';
10
11
  export * from './TMCommandsContextMenu';
@@ -5,6 +5,7 @@ export * from './Globalization';
5
5
  export * from './TMIcons';
6
6
  export * from './TMImageLibrary';
7
7
  export * from './helpers';
8
+ export * from './dataGridSearchHelper';
8
9
  export * from './queryHelper';
9
10
  export * from './TMUtils';
10
11
  export * from './TMCommandsContextMenu';
@@ -14,6 +14,8 @@ export declare function addWhereClausesForConnect(qd: QueryDescriptor): void;
14
14
  export declare function getDefaultOperator(dataDomain: MetadataDataDomains | undefined, dataType: MetadataDataTypes | undefined): QueryOperators.Equal | QueryOperators.Contain | QueryOperators.In;
15
15
  export declare const getQD: (tid: number | undefined, easyOr: boolean, newMaxDcmtsToBeReturned: number) => Promise<QueryDescriptor | undefined>;
16
16
  export declare const getWorkItemSetIDAsync: (vid: number, did: number) => Promise<string | undefined>;
17
+ /** Id assegnato alla ricerca di sistema con tutti i documenti: non è in cache, va ricostruita a runtime con getSysAllDcmtsSQD */
18
+ export declare const SYS_ALL_DCMTS_SQD_ID = 1;
17
19
  export declare const getSysAllDcmtsSQD: (tid: number | undefined, easyOr: boolean) => Promise<SavedQueryDescriptor>;
18
20
  export declare const searchResultToMetadataValues: (tid: number | undefined, dtd: DataTableDescriptor | undefined, rows: string[], mids: number[], metadata: MetadataDescriptor[], layoutMode: LayoutModes, isReadOnlyOrigin?: boolean) => MetadataValueDescriptorEx[];
19
21
  export declare const handleArchiveVisibility: (md: MetadataDescriptor) => boolean;
@@ -251,9 +251,11 @@ export const getWorkItemSetIDAsync = async (vid, did) => {
251
251
  let result = await SDK_Globals.tmSession?.NewSearchEngine().SearchByIDAsync(qd);
252
252
  return result?.dtdResult?.rows?.[0]?.[0];
253
253
  };
254
+ /** Id assegnato alla ricerca di sistema con tutti i documenti: non è in cache, va ricostruita a runtime con getSysAllDcmtsSQD */
255
+ export const SYS_ALL_DCMTS_SQD_ID = 1;
254
256
  export const getSysAllDcmtsSQD = async (tid, easyOr) => {
255
257
  let sqd = new SavedQueryDescriptor();
256
- sqd.id = 1;
258
+ sqd.id = SYS_ALL_DCMTS_SQD_ID;
257
259
  sqd.masterTID = tid;
258
260
  sqd.isEasyWhere = 1;
259
261
  sqd.name = SDKUI_Localizator.AllDcmts;
@@ -0,0 +1,16 @@
1
+ import { DataColumnDescriptor, DataColumnTypes, MetadataDescriptor, MetadataFormats } from '@topconsultnpm/sdk-ts';
2
+ /**
3
+ * Funzioni condivise dalle due sorgenti di TMDistinctValues (valori distinti e ricerca rapida):
4
+ * stanno fuori dagli hook perché non dipendono da alcuno stato.
5
+ */
6
+ export declare const withRowIndex: <T>(rows: Array<T>) => T[];
7
+ export declare const toGridDataType: (dataType: DataColumnTypes | undefined) => "string" | "number" | "datetime" | "boolean";
8
+ export declare const getMetadataName: (columnMd: MetadataDescriptor | undefined) => string | undefined;
9
+ export declare const getDateDisplayFormat: (format: MetadataFormats | undefined, formatCulture: string | undefined | null) => {
10
+ formatter: (value: string | number | Date) => string;
11
+ };
12
+ /**
13
+ * Risolve il MID della colonna di un risultato di ricerca: la proprietà estesa è la fonte principale,
14
+ * in mancanza resta l'allineamento posizionale tra selectMIDs e colonne del risultato.
15
+ */
16
+ export declare const getColumnMid: (column: DataColumnDescriptor | undefined, selectMIDs: number[] | undefined, columnIndex: number) => number;
@@ -0,0 +1,31 @@
1
+ import { DataColumnTypes, SDK_Globals } from '@topconsultnpm/sdk-ts';
2
+ import { formatDateTimeByMetadataFormat } from '../helper';
3
+ /**
4
+ * Funzioni condivise dalle due sorgenti di TMDistinctValues (valori distinti e ricerca rapida):
5
+ * stanno fuori dagli hook perché non dipendono da alcuno stato.
6
+ */
7
+ // rowIndex è la chiave delle griglie di TMDistinctValues: va riallineato all'ordine finale delle righe
8
+ export const withRowIndex = (rows) => {
9
+ rows.forEach((row, index) => { row.rowIndex = index; });
10
+ return rows;
11
+ };
12
+ export const toGridDataType = (dataType) => {
13
+ switch (dataType) {
14
+ case DataColumnTypes.DateTime: return 'datetime';
15
+ case DataColumnTypes.Bool: return 'boolean';
16
+ case DataColumnTypes.Number: return 'number';
17
+ default: return 'string';
18
+ }
19
+ };
20
+ // Nome del metadato con cui viene intestata la colonna, nella lingua scelta dall'utente
21
+ export const getMetadataName = (columnMd) => (SDK_Globals.useLocalizedName ? columnMd?.nameLoc : columnMd?.name) ?? columnMd?.name ?? columnMd?.nameLoc ?? undefined;
22
+ // Le date vanno mostrate con il formato definito sul metadato, come nel risultato di ricerca
23
+ export const getDateDisplayFormat = (format, formatCulture) => ({
24
+ // La griglia passa al formatter un oggetto Date già istanziato, ma il valore può arrivare anche come stringa
25
+ formatter: (value) => formatDateTimeByMetadataFormat(value instanceof Date ? value : new Date(value), format, formatCulture)
26
+ });
27
+ /**
28
+ * Risolve il MID della colonna di un risultato di ricerca: la proprietà estesa è la fonte principale,
29
+ * in mancanza resta l'allineamento posizionale tra selectMIDs e colonne del risultato.
30
+ */
31
+ export const getColumnMid = (column, selectMIDs, columnIndex) => Number(column?.extendedProperties?.['MID'] ?? 0) || (selectMIDs?.[columnIndex] ?? 0);
@@ -0,0 +1,56 @@
1
+ import { CaseFlowInstanceDescriptor, CaseFlowWorkItem } from '@topconsultnpm/sdk-ts';
2
+ /**
3
+ * Attività (workitem) delle PRATICHE assegnate all'utente, con il documento su
4
+ * cui lavorano già risolto.
5
+ *
6
+ * Gemello di `useWorkflowApprove` per il modulo CaseFlow: i dati stanno in una
7
+ * cache di modulo e le istanze del hook si sincronizzano con un evento, così il
8
+ * form del documento — da qualunque punto venga aperto — sa che su quel TID/DID
9
+ * c'è una firma da fare o un'approvazione da dare, senza che il chiamante debba
10
+ * passargli nulla.
11
+ */
12
+ /** Workitem di pratica già risolto sul documento cui si riferisce. */
13
+ export interface CaseFlowDcmtWorkItem {
14
+ caseflow: CaseFlowInstanceDescriptor;
15
+ workItem: CaseFlowWorkItem;
16
+ tid: number;
17
+ did: number;
18
+ }
19
+ /**
20
+ * Ricarica i workitem di pratica dell'utente. Con `force` ignora la finestra
21
+ * anti-raffica (da usare dopo un'operazione che li ha modificati).
22
+ */
23
+ export declare const refreshCaseFlowApproveData: (force?: boolean) => Promise<void>;
24
+ /**
25
+ * Workitem di pratica pendenti su quel documento (lettura sincrona dalla cache).
26
+ *
27
+ * TID/DID vanno NORMALIZZATI: pur essendo tipati `number`, arrivano come stringhe
28
+ * quando il documento è aperto da una griglia (righe di datagrid) — per lo stesso
29
+ * motivo il resto della libreria fa `Number(TID)`/`Number(DID)` in ogni confronto.
30
+ * Senza normalizzazione il confronto stretto falliva, e l'attività risultava
31
+ * assente aprendo il documento dalla ricerca mentre compariva dal widget "Per te".
32
+ */
33
+ export declare const getCaseFlowWorkItemsByDcmt: (tid?: number | string, did?: number | string) => CaseFlowDcmtWorkItem[];
34
+ /** Svuota la cache (logout / cambio archivio). */
35
+ export declare const clearCaseFlowApproveData: () => void;
36
+ /** Completa il workitem di pratica e ricarica la cache. */
37
+ export declare const completeCaseFlowWorkItem: (item: CaseFlowDcmtWorkItem, comment?: string) => Promise<void>;
38
+ /** Rifiuta il workitem di pratica (motivo obbligatorio) e ricarica la cache. */
39
+ export declare const rejectCaseFlowWorkItem: (item: CaseFlowDcmtWorkItem, reason: string) => Promise<void>;
40
+ /**
41
+ * Completa l'attività di FIRMA di una pratica sul documento indicato, se esiste.
42
+ * La chiama il viewer di firma quando la firma è riuscita: è il gemello di quanto
43
+ * già avviene per i workitem del workflow legacy.
44
+ * @returns true se un'attività è stata completata.
45
+ */
46
+ export declare const completeCaseFlowSignatureForDcmt: (tid: number | string, did: number | string, comment?: string) => Promise<boolean>;
47
+ /**
48
+ * Attività di pratica sul documento indicato. Senza sessione o senza attività
49
+ * l'elenco è vuoto e nulla cambia nella UI.
50
+ */
51
+ export declare const useCaseFlowApprove: (tid?: number | string, did?: number | string) => {
52
+ caseFlowWorkItems: CaseFlowDcmtWorkItem[];
53
+ refreshCaseFlowApprove: (force?: boolean) => Promise<void>;
54
+ completeCaseFlowWorkItem: (item: CaseFlowDcmtWorkItem, comment?: string) => Promise<void>;
55
+ rejectCaseFlowWorkItem: (item: CaseFlowDcmtWorkItem, reason: string) => Promise<void>;
56
+ };
@@ -0,0 +1,157 @@
1
+ import { useCallback, useEffect, useState } from 'react';
2
+ import { SDK_Globals } from '@topconsultnpm/sdk-ts';
3
+ import { CaseFlowService } from '../services/caseflow/CaseFlowService';
4
+ import { getWorkItemTargetDoc, isMoreInfoWorkItem, isSignatureWorkItem } from '../services/caseflow/caseFlowWorkItemUtils';
5
+ const CASEFLOW_APPROVE_CHANGED_EVENT = 'onCaseFlowApproveChange';
6
+ let cache = [];
7
+ let inFlight;
8
+ let lastLoadedAt = 0;
9
+ /**
10
+ * Finestra minima fra due ricariche: il form del documento chiede un refresh a
11
+ * ogni apertura e la lista è una scansione delle istanze, non una query puntuale.
12
+ */
13
+ const MIN_RELOAD_INTERVAL_MS = 15000;
14
+ const notifyChanged = () => {
15
+ if (typeof window === 'undefined')
16
+ return;
17
+ window.dispatchEvent(new CustomEvent(CASEFLOW_APPROVE_CHANGED_EVENT));
18
+ };
19
+ /**
20
+ * Ricarica la cache: i workitem pendenti dell'utente, risolti sul documento su
21
+ * cui lavorano. Le richieste di informazioni sono escluse (si rispondono nella
22
+ * pratica, non sul documento) come i workitem senza documento.
23
+ */
24
+ const reload = async () => {
25
+ const userId = SDK_Globals.tmSession?.SessionDescr?.userID;
26
+ if (userId == null) {
27
+ cache = [];
28
+ return;
29
+ }
30
+ const groups = await CaseFlowService.getMyPendingWorkItems(userId);
31
+ const resolved = [];
32
+ for (const { caseflow, workItems } of groups) {
33
+ // Le richieste di informazioni si rispondono nella pratica, non sul documento.
34
+ const relevant = workItems.filter(wi => !isMoreInfoWorkItem(wi));
35
+ if (relevant.length === 0)
36
+ continue;
37
+ // Il TID dell'azione è autorato sul TEMPLATE e non materializzato
38
+ // sull'istanza: senza template risolto il documento non è calcolabile.
39
+ if (caseflow.cftid != null) {
40
+ await CaseFlowService.getTemplate(caseflow.cftid);
41
+ }
42
+ // I DOCUMENTI AGGANCIATI non arrivano dalla RetrieveAll (che porta solo i
43
+ // dati delle card): serve la Retrieve completa, altrimenti `dcmts` è vuoto
44
+ // e nessun workitem risulterebbe associato a un documento.
45
+ let instance = caseflow;
46
+ if ((instance.dcmts?.length ?? 0) === 0 && instance.id != null) {
47
+ instance = (await CaseFlowService.getCaseflow(instance.id, instance.cftid)) ?? instance;
48
+ }
49
+ for (const wi of relevant) {
50
+ const target = getWorkItemTargetDoc(instance, wi);
51
+ if (!target)
52
+ continue;
53
+ resolved.push({ caseflow: instance, workItem: wi, tid: target.tid, did: target.did });
54
+ }
55
+ }
56
+ cache = resolved;
57
+ lastLoadedAt = Date.now();
58
+ // Diagnostica del bring-up: se il Toppy non compare, qui si vede a che punto
59
+ // la catena si interrompe (nessun workitem / nessun documento risolto).
60
+ // Rimuovibile una volta stabilizzato il flusso.
61
+ console.debug('[CaseFlow] attività su documenti:', {
62
+ istanzeConPendenti: groups.length,
63
+ workItemPendenti: groups.reduce((n, g) => n + g.workItems.length, 0),
64
+ risolteSuDocumento: resolved.length,
65
+ documenti: resolved.map(r => `${r.tid}/${r.did}`),
66
+ });
67
+ };
68
+ /**
69
+ * Ricarica i workitem di pratica dell'utente. Con `force` ignora la finestra
70
+ * anti-raffica (da usare dopo un'operazione che li ha modificati).
71
+ */
72
+ export const refreshCaseFlowApproveData = async (force = false) => {
73
+ if (inFlight)
74
+ return inFlight;
75
+ if (!force && lastLoadedAt > 0 && Date.now() - lastLoadedAt < MIN_RELOAD_INTERVAL_MS)
76
+ return;
77
+ inFlight = reload()
78
+ .catch(error => { console.error('Errore nel caricare le attività di pratica sui documenti', error); })
79
+ .finally(() => { inFlight = undefined; notifyChanged(); });
80
+ return inFlight;
81
+ };
82
+ /**
83
+ * Workitem di pratica pendenti su quel documento (lettura sincrona dalla cache).
84
+ *
85
+ * TID/DID vanno NORMALIZZATI: pur essendo tipati `number`, arrivano come stringhe
86
+ * quando il documento è aperto da una griglia (righe di datagrid) — per lo stesso
87
+ * motivo il resto della libreria fa `Number(TID)`/`Number(DID)` in ogni confronto.
88
+ * Senza normalizzazione il confronto stretto falliva, e l'attività risultava
89
+ * assente aprendo il documento dalla ricerca mentre compariva dal widget "Per te".
90
+ */
91
+ export const getCaseFlowWorkItemsByDcmt = (tid, did) => {
92
+ const t = Number(tid);
93
+ const d = Number(did);
94
+ if (!Number.isFinite(t) || !Number.isFinite(d))
95
+ return [];
96
+ return cache.filter(r => Number(r.tid) === t && Number(r.did) === d);
97
+ };
98
+ /** Svuota la cache (logout / cambio archivio). */
99
+ export const clearCaseFlowApproveData = () => {
100
+ cache = [];
101
+ lastLoadedAt = 0;
102
+ notifyChanged();
103
+ };
104
+ /** Completa il workitem di pratica e ricarica la cache. */
105
+ export const completeCaseFlowWorkItem = async (item, comment) => {
106
+ if (item.caseflow.id == null || item.workItem.id == null)
107
+ return;
108
+ await CaseFlowService.completeWorkItem(item.caseflow.id, item.workItem.id, comment?.trim() || undefined);
109
+ await refreshCaseFlowApproveData(true);
110
+ };
111
+ /** Rifiuta il workitem di pratica (motivo obbligatorio) e ricarica la cache. */
112
+ export const rejectCaseFlowWorkItem = async (item, reason) => {
113
+ if (item.caseflow.id == null || item.workItem.id == null)
114
+ return;
115
+ await CaseFlowService.rejectWorkItem(item.caseflow.id, item.workItem.id, reason);
116
+ await refreshCaseFlowApproveData(true);
117
+ };
118
+ /**
119
+ * Completa l'attività di FIRMA di una pratica sul documento indicato, se esiste.
120
+ * La chiama il viewer di firma quando la firma è riuscita: è il gemello di quanto
121
+ * già avviene per i workitem del workflow legacy.
122
+ * @returns true se un'attività è stata completata.
123
+ */
124
+ export const completeCaseFlowSignatureForDcmt = async (tid, did, comment) => {
125
+ const target = getCaseFlowWorkItemsByDcmt(tid, did).find(r => isSignatureWorkItem(r.workItem));
126
+ if (!target)
127
+ return false;
128
+ await completeCaseFlowWorkItem(target, comment);
129
+ return true;
130
+ };
131
+ /**
132
+ * Attività di pratica sul documento indicato. Senza sessione o senza attività
133
+ * l'elenco è vuoto e nulla cambia nella UI.
134
+ */
135
+ export const useCaseFlowApprove = (tid, did) => {
136
+ const readItems = useCallback(() => getCaseFlowWorkItemsByDcmt(tid, did), [tid, did]);
137
+ const [caseFlowWorkItems, setCaseFlowWorkItems] = useState(readItems);
138
+ useEffect(() => { setCaseFlowWorkItems(readItems()); }, [readItems]);
139
+ useEffect(() => {
140
+ const handleChange = () => setCaseFlowWorkItems(readItems());
141
+ window.addEventListener(CASEFLOW_APPROVE_CHANGED_EVENT, handleChange);
142
+ return () => window.removeEventListener(CASEFLOW_APPROVE_CHANGED_EVENT, handleChange);
143
+ }, [readItems]);
144
+ // All'apertura di un documento la cache può essere vecchia (attività assegnate
145
+ // dopo l'ultimo caricamento) o non ancora popolata.
146
+ useEffect(() => {
147
+ if (tid == null || did == null)
148
+ return;
149
+ void refreshCaseFlowApproveData();
150
+ }, [tid, did]);
151
+ return {
152
+ caseFlowWorkItems,
153
+ refreshCaseFlowApprove: refreshCaseFlowApproveData,
154
+ completeCaseFlowWorkItem,
155
+ rejectCaseFlowWorkItem,
156
+ };
157
+ };
@@ -0,0 +1,18 @@
1
+ import { MetadataDescriptor } from '@topconsultnpm/sdk-ts';
2
+ import { IColumnProps } from 'devextreme-react/data-grid';
3
+ export declare const needsDisplayValue: (columnMd: MetadataDescriptor | undefined) => boolean;
4
+ /**
5
+ * Resa dei valori nelle griglie di TMDistinctValues: al posto della chiave archiviata mostra la descrizione
6
+ * presa dalle cache di liste dati e utenti, tenendole allineate alle colonne effettivamente visualizzate.
7
+ *
8
+ * Vale per entrambe le sorgenti del pannello (valori distinti e ricerca rapida, che può essere su un altro
9
+ * tipo documento): le chiavi delle due sorgenti vengono accumulate e ricaricate sempre insieme, altrimenti
10
+ * un caricamento farebbe perdere le descrizioni dell'altra sorgente.
11
+ */
12
+ export declare const useTMDistinctValuesMetadataDisplay: () => {
13
+ loadDisplayCachesAsync: (columnsMd: Array<MetadataDescriptor | undefined>, rows: string[][] | undefined) => Promise<void>;
14
+ getMetadataDisplayValue: (columnMd: MetadataDescriptor | undefined, value: any) => any;
15
+ displayValueColumnProps: (columnMd: MetadataDescriptor | undefined, dataField: string) => Partial<IColumnProps>;
16
+ };
17
+ /** Tipo di ritorno dell'hook: le sorgenti di TMDistinctValues lo ricevono come dipendenza */
18
+ export type TMDistinctValuesMetadataDisplay = ReturnType<typeof useTMDistinctValuesMetadataDisplay>;