@topconsultnpm/sdkui-react 6.22.0-dev2.17 → 6.22.0-dev2.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/base/TMEditorBase.d.ts +2 -0
- package/lib/components/base/TMTooltip.d.ts +2 -1
- package/lib/components/base/TMTooltip.js +23 -6
- package/lib/components/choosers/TMDcmtTypeChooser.js +4 -3
- package/lib/components/choosers/TMDistinctValues.d.ts +9 -7
- package/lib/components/choosers/TMDistinctValues.js +147 -195
- package/lib/components/choosers/TMMetadataChooser.js +1 -1
- package/lib/components/choosers/TMQuickSearchInfo.d.ts +12 -0
- package/lib/components/choosers/TMQuickSearchInfo.js +279 -0
- package/lib/components/choosers/TMQuickSearchSettingsForm.d.ts +16 -0
- package/lib/components/choosers/TMQuickSearchSettingsForm.js +94 -0
- package/lib/components/choosers/TMSelectedValuesSummary.d.ts +13 -0
- package/lib/components/choosers/TMSelectedValuesSummary.js +91 -0
- package/lib/components/editors/TMDropDown.d.ts +3 -0
- package/lib/components/editors/TMDropDown.js +197 -5
- package/lib/components/features/search/TMSearchResult.js +55 -4
- package/lib/components/viewers/TMMidViewer.js +4 -1
- package/lib/components/viewers/TMTidViewer.js +25 -11
- package/lib/helper/SDKUI_Globals.d.ts +20 -0
- package/lib/helper/SDKUI_Globals.js +44 -0
- package/lib/helper/SDKUI_Localizator.d.ts +1 -0
- package/lib/helper/SDKUI_Localizator.js +10 -0
- package/lib/helper/dataGridSearchHelper.d.ts +28 -0
- package/lib/helper/dataGridSearchHelper.js +51 -0
- package/lib/helper/index.d.ts +1 -0
- package/lib/helper/index.js +1 -0
- package/lib/helper/queryHelper.d.ts +2 -0
- package/lib/helper/queryHelper.js +3 -1
- package/lib/hooks/tmDistinctValuesGridHelper.d.ts +16 -0
- package/lib/hooks/tmDistinctValuesGridHelper.js +31 -0
- package/lib/hooks/useTMDistinctValuesMetadataDisplay.d.ts +18 -0
- package/lib/hooks/useTMDistinctValuesMetadataDisplay.js +103 -0
- package/lib/hooks/useTMDistinctValuesQuickSearch.d.ts +49 -0
- package/lib/hooks/useTMDistinctValuesQuickSearch.js +307 -0
- package/lib/hooks/useTMDistinctValuesSelection.d.ts +42 -0
- package/lib/hooks/useTMDistinctValuesSelection.js +103 -0
- package/lib/hooks/useTMDistinctValuesSource.d.ts +29 -0
- package/lib/hooks/useTMDistinctValuesSource.js +105 -0
- package/lib/services/caseflow/CaseFlowService.d.ts +28 -0
- package/lib/services/caseflow/CaseFlowService.js +70 -0
- package/lib/services/platform_services.d.ts +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
2
|
+
import { AccessLevels, LayoutModes, MetadataDataDomains, MetadataDataTypes } from '@topconsultnpm/sdk-ts';
|
|
3
|
+
import { formatDateTimeByMetadataFormat, stringIsNullOrEmpty } from '../helper';
|
|
4
|
+
/**
|
|
5
|
+
* Selezione di TMDistinctValues: la riga focalizzata nella griglia diventa il valore del campo del form,
|
|
6
|
+
* in sostituzione di quello precedente oppure, in modalità Accoda, in aggiunta ai valori già scelti.
|
|
7
|
+
*
|
|
8
|
+
* Vale per entrambe le sorgenti del pannello: cosa leggere dalla riga viene deciso da chi lo usa.
|
|
9
|
+
*/
|
|
10
|
+
export const useTMDistinctValuesSelection = ({ tid, mid, md, layoutMode, allowAppendMode, separator, selectedValueMd, getRowValue, getMetadataDisplayValue, onSelectionChanged }) => {
|
|
11
|
+
const [focusedItem, setFocusedItem] = useState();
|
|
12
|
+
const [isAppendMode, setIsAppendMode] = useState(false);
|
|
13
|
+
const [appendedValues, setAppendedValues] = useState(new Set());
|
|
14
|
+
// Cambiando metadato la selezione fatta sul precedente non ha più senso
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
setIsAppendMode(false);
|
|
17
|
+
setFocusedItem(undefined);
|
|
18
|
+
setAppendedValues(new Set());
|
|
19
|
+
}, [md]);
|
|
20
|
+
// Sul metadato serve il permesso adeguato alla modalità corrente: senza, la riga focalizzata non produce alcun valore
|
|
21
|
+
const canPickValue = useMemo(() => {
|
|
22
|
+
if (!md)
|
|
23
|
+
return false;
|
|
24
|
+
if ((layoutMode === LayoutModes.Ark || layoutMode === LayoutModes.Update) && md.dataDomain === MetadataDataDomains.Computed)
|
|
25
|
+
return false;
|
|
26
|
+
switch (layoutMode) {
|
|
27
|
+
case LayoutModes.Ark: return md.perm?.canArchive === AccessLevels.Yes;
|
|
28
|
+
case LayoutModes.Update: return md.perm?.canUpdate === AccessLevels.Yes;
|
|
29
|
+
case LayoutModes.None: return md.perm?.canSearch === AccessLevels.Yes;
|
|
30
|
+
// Le altre modalità non hanno un permesso da verificare
|
|
31
|
+
default: return true;
|
|
32
|
+
}
|
|
33
|
+
}, [md, layoutMode]);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (!focusedItem || !canPickValue)
|
|
36
|
+
return;
|
|
37
|
+
const focusedValue = getRowValue(focusedItem);
|
|
38
|
+
if (stringIsNullOrEmpty(focusedValue)) {
|
|
39
|
+
// In accodamento una riga con valore vuoto non ha nulla da aggiungere: la selezione già fatta va conservata
|
|
40
|
+
if (isAppendMode)
|
|
41
|
+
return;
|
|
42
|
+
emitSelection(new Set());
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const value = md?.dataType === MetadataDataTypes.Number ? parseFloat(focusedValue.replace(',', '.')).toString() : focusedValue;
|
|
46
|
+
// Fuori dalla modalità Accoda la selezione sostituisce sempre il valore precedente
|
|
47
|
+
emitSelection(new Set(isAppendMode ? [...appendedValues, value] : [value]));
|
|
48
|
+
}, [focusedItem]);
|
|
49
|
+
// Unico punto da cui la selezione viene aggiornata e notificata al campo del form
|
|
50
|
+
const emitSelection = (values) => {
|
|
51
|
+
setAppendedValues(values);
|
|
52
|
+
onSelectionChanged?.({ tid: tid, mid: mid, newValue: values.size > 0 ? Array.from(values).join(separator) : undefined, isAppendMode: isAppendMode });
|
|
53
|
+
};
|
|
54
|
+
// Il riepilogo agisce sugli stessi valori della griglia: rimuovendone uno il campo del form va riallineato
|
|
55
|
+
const updateSelectionFromSummary = (values) => {
|
|
56
|
+
// Il prossimo click sulla riga appena rimossa deve poter riportare il valore nella selezione: senza azzerare
|
|
57
|
+
// il focus la griglia non rinotifica la riga già focalizzata
|
|
58
|
+
setFocusedItem(undefined);
|
|
59
|
+
emitSelection(values);
|
|
60
|
+
};
|
|
61
|
+
const onRemoveSelectedValue = (value) => {
|
|
62
|
+
const newAppendedValues = new Set(appendedValues);
|
|
63
|
+
newAppendedValues.delete(value);
|
|
64
|
+
updateSelectionFromSummary(newAppendedValues);
|
|
65
|
+
};
|
|
66
|
+
const onClearSelectedValues = () => updateSelectionFromSummary(new Set());
|
|
67
|
+
const onAppendModeChanged = () => {
|
|
68
|
+
const newIsAppendMode = !isAppendMode;
|
|
69
|
+
// Disattivando l'accodamento si riparte da zero: il prossimo click sostituirà il valore
|
|
70
|
+
if (!newIsAppendMode)
|
|
71
|
+
setAppendedValues(new Set());
|
|
72
|
+
setIsAppendMode(newIsAppendMode);
|
|
73
|
+
};
|
|
74
|
+
const onFocusedRowChanged = useCallback((e) => {
|
|
75
|
+
setFocusedItem(e.row?.data);
|
|
76
|
+
}, []);
|
|
77
|
+
/** L'accodamento non è proponibile dove il campo del form accetta un solo valore */
|
|
78
|
+
const isAppendVisible = useMemo(() => {
|
|
79
|
+
if (!allowAppendMode)
|
|
80
|
+
return false;
|
|
81
|
+
if (layoutMode !== LayoutModes.Ark && layoutMode !== LayoutModes.Update)
|
|
82
|
+
return true;
|
|
83
|
+
if (!md)
|
|
84
|
+
return true;
|
|
85
|
+
if (md.dataType === MetadataDataTypes.DateTime)
|
|
86
|
+
return false;
|
|
87
|
+
if (md.dataType === MetadataDataTypes.Number)
|
|
88
|
+
return false;
|
|
89
|
+
return md.dataDomain === undefined || md.dataDomain === MetadataDataDomains.None;
|
|
90
|
+
}, [allowAppendMode, layoutMode, md]);
|
|
91
|
+
/** Valori selezionati con la descrizione con cui vanno mostrati nel riepilogo */
|
|
92
|
+
const selectedValues = useMemo(() => Array.from(appendedValues).map((value) => {
|
|
93
|
+
if (selectedValueMd?.dataType === MetadataDataTypes.DateTime) {
|
|
94
|
+
const date = new Date(value);
|
|
95
|
+
return { value: value, display: Number.isNaN(date.getTime()) ? value : formatDateTimeByMetadataFormat(date, selectedValueMd?.format?.format, selectedValueMd?.format?.formatCulture) };
|
|
96
|
+
}
|
|
97
|
+
return { value: value, display: getMetadataDisplayValue(selectedValueMd, value) ?? value };
|
|
98
|
+
}), [appendedValues, selectedValueMd, getMetadataDisplayValue]);
|
|
99
|
+
return {
|
|
100
|
+
focusedItem, setFocusedItem, isAppendMode, isAppendVisible, selectedValues,
|
|
101
|
+
onFocusedRowChanged, onAppendModeChanged, onRemoveSelectedValue, onClearSelectedValues
|
|
102
|
+
};
|
|
103
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { MetadataDescriptor } from '@topconsultnpm/sdk-ts';
|
|
2
|
+
import { IColumnProps } from 'devextreme-react/data-grid';
|
|
3
|
+
import { TMDistinctValuesMetadataDisplay } from './useTMDistinctValuesMetadataDisplay';
|
|
4
|
+
/** Righe restituite e righe totali: il caricamento è limitato, il contatore mostra il rapporto */
|
|
5
|
+
export type TMDistinctValuesCounts = {
|
|
6
|
+
returned: number;
|
|
7
|
+
found: number;
|
|
8
|
+
};
|
|
9
|
+
interface ITMDistinctValuesSourceParams {
|
|
10
|
+
tid: number | undefined;
|
|
11
|
+
mid: number | undefined;
|
|
12
|
+
display: TMDistinctValuesMetadataDisplay;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Sorgente "valori distinti" di TMDistinctValues: carica i valori del metadato con il relativo numero di
|
|
16
|
+
* documenti e ne espone righe, colonne e conteggi già pronti per la griglia.
|
|
17
|
+
*
|
|
18
|
+
* È anche la sorgente da cui viene il descrittore del metadato (`md`), usato dal pannello per permessi,
|
|
19
|
+
* titolo e visibilità dell'accodamento: per questo viene caricata anche quando è attiva la ricerca rapida.
|
|
20
|
+
*/
|
|
21
|
+
export declare const useTMDistinctValuesSource: ({ tid, mid, display }: ITMDistinctValuesSourceParams) => {
|
|
22
|
+
md: MetadataDescriptor | undefined;
|
|
23
|
+
dataSource: any[] | undefined;
|
|
24
|
+
counts: TMDistinctValuesCounts | undefined;
|
|
25
|
+
columns: IColumnProps[];
|
|
26
|
+
customizeColumns: (columns: Array<any>) => void;
|
|
27
|
+
loadAsync: () => Promise<void>;
|
|
28
|
+
};
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
2
|
+
import { DataColumnTypes, DcmtTypeListCacheService, MetadataDataTypes, SDK_Globals } from '@topconsultnpm/sdk-ts';
|
|
3
|
+
import { TMExceptionBoxManager } from '../components/base/TMPopUp';
|
|
4
|
+
import TMSpinner from '../components/base/TMSpinner';
|
|
5
|
+
import { customizeSearchByDisplayText, getDateDisplayText } from '../helper';
|
|
6
|
+
import { getDateDisplayFormat, withRowIndex } from './tmDistinctValuesGridHelper';
|
|
7
|
+
import { needsDisplayValue } from './useTMDistinctValuesMetadataDisplay';
|
|
8
|
+
/** Nel risultato dei valori distinti la prima colonna è il valore, la seconda il numero di documenti che lo contengono */
|
|
9
|
+
const COUNT_COL_INDEX = 1;
|
|
10
|
+
/** Numero massimo di valori distinti richiesti al server: il conteggio dice quanti ne sono arrivati sul totale */
|
|
11
|
+
const MAX_DISTINCT_VALUES = 10000;
|
|
12
|
+
/**
|
|
13
|
+
* Sorgente "valori distinti" di TMDistinctValues: carica i valori del metadato con il relativo numero di
|
|
14
|
+
* documenti e ne espone righe, colonne e conteggi già pronti per la griglia.
|
|
15
|
+
*
|
|
16
|
+
* È anche la sorgente da cui viene il descrittore del metadato (`md`), usato dal pannello per permessi,
|
|
17
|
+
* titolo e visibilità dell'accodamento: per questo viene caricata anche quando è attiva la ricerca rapida.
|
|
18
|
+
*/
|
|
19
|
+
export const useTMDistinctValuesSource = ({ tid, mid, display }) => {
|
|
20
|
+
const { loadDisplayCachesAsync, displayValueColumnProps, getMetadataDisplayValue } = display;
|
|
21
|
+
const [md, setMd] = useState();
|
|
22
|
+
const [dataSource, setDataSource] = useState([]);
|
|
23
|
+
const [counts, setCounts] = useState();
|
|
24
|
+
// Identifica la richiesta corrente: dopo ogni await le risposte delle richieste obsolete vengono scartate
|
|
25
|
+
const requestIdRef = useRef(0);
|
|
26
|
+
// Cambiando campo i valori distinti vanno ricaricati: sono la sorgente su cui si torna cambiando
|
|
27
|
+
// modalità e quella da cui viene il metadato del campo
|
|
28
|
+
useEffect(() => { loadAsync(); }, [tid, mid]);
|
|
29
|
+
const loadAsync = async () => {
|
|
30
|
+
if (!tid)
|
|
31
|
+
return;
|
|
32
|
+
const requestId = ++requestIdRef.current;
|
|
33
|
+
const isStale = () => requestId !== requestIdRef.current;
|
|
34
|
+
// Svuota subito la griglia: evita di mostrare i valori del tid/mid precedente durante il caricamento
|
|
35
|
+
setDataSource([]);
|
|
36
|
+
setCounts(undefined);
|
|
37
|
+
try {
|
|
38
|
+
TMSpinner.show({ description: 'Caricamento dei valori distinti...' });
|
|
39
|
+
const dtd = await DcmtTypeListCacheService.GetAsync(tid, true);
|
|
40
|
+
const currentMd = dtd?.metadata?.find(o => o.id === mid);
|
|
41
|
+
const result = await SDK_Globals.tmSession?.NewSearchEngine().GetDistinctValuesAsync(tid, mid, MAX_DISTINCT_VALUES);
|
|
42
|
+
if (isStale())
|
|
43
|
+
return;
|
|
44
|
+
// La prima colonna del risultato è quella dei valori distinti
|
|
45
|
+
await loadDisplayCachesAsync([currentMd], result?.dtdResult?.rows);
|
|
46
|
+
if (isStale())
|
|
47
|
+
return;
|
|
48
|
+
setMd(currentMd);
|
|
49
|
+
setDataSource(convertDataTableToObject(result?.dtdResult));
|
|
50
|
+
setCounts({ returned: result?.dcmtsReturned ?? 0, found: result?.dcmtsFound ?? 0 });
|
|
51
|
+
}
|
|
52
|
+
catch (e) {
|
|
53
|
+
if (isStale())
|
|
54
|
+
return;
|
|
55
|
+
TMExceptionBoxManager.show({ exception: e });
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
TMSpinner.hide();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const columns = useMemo(() => {
|
|
62
|
+
const isDateColumn = md?.dataType === MetadataDataTypes.DateTime;
|
|
63
|
+
return ([
|
|
64
|
+
{
|
|
65
|
+
dataField: 'value', dataType: isDateColumn ? 'date' : 'string', caption: md?.nameLoc,
|
|
66
|
+
...(isDateColumn && { format: getDateDisplayFormat(md?.format?.format, md?.format?.formatCulture) }),
|
|
67
|
+
...displayValueColumnProps(md, 'value')
|
|
68
|
+
},
|
|
69
|
+
{ dataField: 'Count', dataType: 'number', caption: 'N°' }
|
|
70
|
+
]);
|
|
71
|
+
}, [md, displayValueColumnProps]);
|
|
72
|
+
// La colonna del valore mostra la data formattata o la descrizione: la ricerca va fatta su quel testo
|
|
73
|
+
const searchTextGetters = useMemo(() => {
|
|
74
|
+
const getters = new Map();
|
|
75
|
+
if (md?.dataType === MetadataDataTypes.DateTime) {
|
|
76
|
+
getters.set('value', (rowData) => getDateDisplayText(rowData?.value, md?.format?.format, md?.format?.formatCulture));
|
|
77
|
+
}
|
|
78
|
+
else if (needsDisplayValue(md)) {
|
|
79
|
+
getters.set('value', (rowData) => String(getMetadataDisplayValue(md, rowData?.value) ?? ''));
|
|
80
|
+
}
|
|
81
|
+
return getters;
|
|
82
|
+
}, [md, getMetadataDisplayValue]);
|
|
83
|
+
const customizeColumns = useMemo(() => customizeSearchByDisplayText(searchTextGetters), [searchTextGetters]);
|
|
84
|
+
return { md, dataSource, counts, columns, customizeColumns, loadAsync };
|
|
85
|
+
};
|
|
86
|
+
const convertDataTableToObject = (dtdResult) => {
|
|
87
|
+
if (!dtdResult?.columns?.length || !dtdResult?.rows?.length)
|
|
88
|
+
return [];
|
|
89
|
+
// Descrittori di colonna calcolati una sola volta invece che per ogni riga
|
|
90
|
+
const columns = [];
|
|
91
|
+
dtdResult.columns.forEach((col, colIndex) => {
|
|
92
|
+
if (col?.caption) {
|
|
93
|
+
columns.push({ index: colIndex, key: colIndex === 0 ? "value" : col.caption, isNumber: col.dataType === DataColumnTypes.Number });
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
// I valori più frequenti in testa: il conteggio è nella seconda colonna del risultato
|
|
97
|
+
const sortedRows = dtdResult.rows.slice().sort((a, b) => (Number(b?.[COUNT_COL_INDEX]) || 0) - (Number(a?.[COUNT_COL_INDEX]) || 0));
|
|
98
|
+
return withRowIndex(sortedRows.map((row) => {
|
|
99
|
+
const rowObject = {};
|
|
100
|
+
columns.forEach((col) => {
|
|
101
|
+
rowObject[col.key] = col.isNumber ? row?.[col.index]?.replace('.', ',') : row?.[col.index] ?? null;
|
|
102
|
+
});
|
|
103
|
+
return rowObject;
|
|
104
|
+
}));
|
|
105
|
+
};
|
|
@@ -164,6 +164,34 @@ export declare class CaseFlowService {
|
|
|
164
164
|
* cftid quando non passato (come per la bacheca).
|
|
165
165
|
*/
|
|
166
166
|
private static participantsAddOrRemove;
|
|
167
|
+
/** Istanze marcate come preferite dall'utente corrente. */
|
|
168
|
+
static getFavorites(): Promise<CaseFlowInstanceDescriptor[]>;
|
|
169
|
+
/**
|
|
170
|
+
* Aggiunge o rimuove l'istanza dai preferiti dell'utente corrente tramite
|
|
171
|
+
* FavoritesAddOrRemoveAsync(cftid, id, remove).
|
|
172
|
+
*/
|
|
173
|
+
static setFavorite(caseFlowId: number, favorite: boolean, cftid?: number): Promise<void>;
|
|
174
|
+
/**
|
|
175
|
+
* Inizia o smette di seguire l'istanza tramite
|
|
176
|
+
* FollowAddOrRemoveAsync(cftid, id, remove).
|
|
177
|
+
*/
|
|
178
|
+
static setFollow(caseFlowId: number, follow: boolean, cftid?: number): Promise<void>;
|
|
179
|
+
/**
|
|
180
|
+
* Stato "l'utente corrente segue questa pratica" letto dal descrittore.
|
|
181
|
+
*
|
|
182
|
+
* Restituisce `undefined` quando il descrittore non porta l'informazione —
|
|
183
|
+
* cioè SEMPRE, finché il backend non aggiunge `IsFollow` in output a
|
|
184
|
+
* `usp_Cfi_RetrieveAll`/`usp_Cfi_Retrieve` e la relativa proprietà al
|
|
185
|
+
* contratto. Il tipo è tollerante perché la colonna è un BIT/NUMBER e può
|
|
186
|
+
* arrivare come booleano, come 0/1 o come stringa.
|
|
187
|
+
*
|
|
188
|
+
* Da NON dedurre dalla bacheca Home come fanno pratiche-dossier e gruppi di
|
|
189
|
+
* lavoro (filtro su `HomeBlogPost.classID`): quella query prende `TOP 30`
|
|
190
|
+
* righe e il solo ultimo post non di sistema per oggetto, quindi chi segue
|
|
191
|
+
* un oggetto senza post risulta "non seguace"; per le istanze di CaseFlow,
|
|
192
|
+
* poi, non esiste nemmeno un ramo nella UNION.
|
|
193
|
+
*/
|
|
194
|
+
static readFollowFlag(cf: CaseFlowInstanceDescriptor): boolean | undefined;
|
|
167
195
|
/** Completa (approva) un workitem. La nota facoltativa viene pubblicata in bacheca dal backend. */
|
|
168
196
|
static completeWorkItem(caseFlowId: number, workItemId: number, response?: string, cftid?: number): Promise<void>;
|
|
169
197
|
/**
|
|
@@ -415,6 +415,76 @@ export class CaseFlowService {
|
|
|
415
415
|
throw new Error(`Impossibile risolvere il template (cftid) per l'istanza id=${caseFlowId}.`);
|
|
416
416
|
await engine.ParticipantsAddOrRemoveAsync(resolvedCftid, caseFlowId, participant, remove);
|
|
417
417
|
}
|
|
418
|
+
// ----- Azioni personali dell'utente (Preferiti / Segui) -------------------
|
|
419
|
+
//
|
|
420
|
+
// Riguardano la relazione fra UTENTE e istanza, non il ciclo di vita della
|
|
421
|
+
// pratica. Come per documenti e partecipanti, l'engine espone un'unica API
|
|
422
|
+
// add-or-remove per ciascuna delle due.
|
|
423
|
+
//
|
|
424
|
+
// ATTENZIONE all'asimmetria: dei Preferiti si può leggere l'elenco
|
|
425
|
+
// (FavoritesRetrieveAllAsync), del Segui NO. Nessuna API dice se l'utente
|
|
426
|
+
// corrente segue una pratica: le `FollowAddOrRemove` sono di sola scrittura,
|
|
427
|
+
// qui come per pratiche-dossier e gruppi di lavoro. Finché il backend non
|
|
428
|
+
// esporrà `IsFollow` sul descrittore d'istanza, lo stato del comando Segui
|
|
429
|
+
// resta a carico del chiamante.
|
|
430
|
+
/** Istanze marcate come preferite dall'utente corrente. */
|
|
431
|
+
static async getFavorites() {
|
|
432
|
+
const engine = SDK_Globals.tmSession?.NewCaseFlowInstanceEngine();
|
|
433
|
+
if (!engine)
|
|
434
|
+
throw new Error('Motore delle istanze CaseFlow non disponibile.');
|
|
435
|
+
return await engine.FavoritesRetrieveAllAsync() ?? [];
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Aggiunge o rimuove l'istanza dai preferiti dell'utente corrente tramite
|
|
439
|
+
* FavoritesAddOrRemoveAsync(cftid, id, remove).
|
|
440
|
+
*/
|
|
441
|
+
static async setFavorite(caseFlowId, favorite, cftid) {
|
|
442
|
+
const engine = SDK_Globals.tmSession?.NewCaseFlowInstanceEngine();
|
|
443
|
+
if (!engine)
|
|
444
|
+
throw new Error('Motore delle istanze CaseFlow non disponibile.');
|
|
445
|
+
const resolvedCftid = cftid ?? (await this.getCaseflow(caseFlowId))?.cftid;
|
|
446
|
+
if (resolvedCftid == null)
|
|
447
|
+
throw new Error(`Impossibile risolvere il template (cftid) per l'istanza id=${caseFlowId}.`);
|
|
448
|
+
await engine.FavoritesAddOrRemoveAsync(resolvedCftid, caseFlowId, !favorite);
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Inizia o smette di seguire l'istanza tramite
|
|
452
|
+
* FollowAddOrRemoveAsync(cftid, id, remove).
|
|
453
|
+
*/
|
|
454
|
+
static async setFollow(caseFlowId, follow, cftid) {
|
|
455
|
+
const engine = SDK_Globals.tmSession?.NewCaseFlowInstanceEngine();
|
|
456
|
+
if (!engine)
|
|
457
|
+
throw new Error('Motore delle istanze CaseFlow non disponibile.');
|
|
458
|
+
const resolvedCftid = cftid ?? (await this.getCaseflow(caseFlowId))?.cftid;
|
|
459
|
+
if (resolvedCftid == null)
|
|
460
|
+
throw new Error(`Impossibile risolvere il template (cftid) per l'istanza id=${caseFlowId}.`);
|
|
461
|
+
await engine.FollowAddOrRemoveAsync(resolvedCftid, caseFlowId, !follow);
|
|
462
|
+
}
|
|
463
|
+
/**
|
|
464
|
+
* Stato "l'utente corrente segue questa pratica" letto dal descrittore.
|
|
465
|
+
*
|
|
466
|
+
* Restituisce `undefined` quando il descrittore non porta l'informazione —
|
|
467
|
+
* cioè SEMPRE, finché il backend non aggiunge `IsFollow` in output a
|
|
468
|
+
* `usp_Cfi_RetrieveAll`/`usp_Cfi_Retrieve` e la relativa proprietà al
|
|
469
|
+
* contratto. Il tipo è tollerante perché la colonna è un BIT/NUMBER e può
|
|
470
|
+
* arrivare come booleano, come 0/1 o come stringa.
|
|
471
|
+
*
|
|
472
|
+
* Da NON dedurre dalla bacheca Home come fanno pratiche-dossier e gruppi di
|
|
473
|
+
* lavoro (filtro su `HomeBlogPost.classID`): quella query prende `TOP 30`
|
|
474
|
+
* righe e il solo ultimo post non di sistema per oggetto, quindi chi segue
|
|
475
|
+
* un oggetto senza post risulta "non seguace"; per le istanze di CaseFlow,
|
|
476
|
+
* poi, non esiste nemmeno un ramo nella UNION.
|
|
477
|
+
*/
|
|
478
|
+
static readFollowFlag(cf) {
|
|
479
|
+
const raw = cf.isFollow;
|
|
480
|
+
if (typeof raw === 'boolean')
|
|
481
|
+
return raw;
|
|
482
|
+
if (typeof raw === 'number')
|
|
483
|
+
return raw !== 0;
|
|
484
|
+
if (raw === '0' || raw === '1')
|
|
485
|
+
return raw === '1';
|
|
486
|
+
return undefined;
|
|
487
|
+
}
|
|
418
488
|
// ----- Workitem: movimentazione del flusso -------------------------------
|
|
419
489
|
//
|
|
420
490
|
// L'engine espone UNA sola API per la movimentazione dei workitem,
|
|
@@ -6,7 +6,7 @@ export declare class PlatformObjectService {
|
|
|
6
6
|
static readonly retrieveAllAdminAsync: (objClass: ObjectClasses, jobType?: JobTypes) => Promise<import("@topconsultnpm/sdk-ts").UserDescriptor[] | DcmtTypeDescriptor[] | import("@topconsultnpm/sdk-ts").RelationDescriptor[] | import("@topconsultnpm/sdk-ts").GroupDescriptor[] | import("@topconsultnpm/sdk-ts").AreaDescriptor[] | import("@topconsultnpm/sdk-ts").FEDistillerJobDescriptor[] | import("@topconsultnpm/sdk-ts").DataListDescriptor[] | import("@topconsultnpm/sdk-ts").DiskDescriptor[] | import("@topconsultnpm/sdk-ts").LDAPDescriptor[] | import("@topconsultnpm/sdk-ts").NumeratorDescriptor[] | ProcessDescriptor[] | import("@topconsultnpm/sdk-ts").SAPLoginDescriptor[] | import("@topconsultnpm/sdk-ts").SignCertDescriptor[] | import("@topconsultnpm/sdk-ts").SignServerDescriptor[] | import("@topconsultnpm/sdk-ts").TreeDescriptor[] | import("@topconsultnpm/sdk-ts").TSADescriptor[] | import("@topconsultnpm/sdk-ts").WFDescriptor[] | undefined>;
|
|
7
7
|
private static readonly loadCacheForJobAsync;
|
|
8
8
|
private static readonly retrieveAdminJobAsync;
|
|
9
|
-
static readonly retrieveAdminAsync: (objClass: ObjectClasses, jobType: JobTypes, id: number) => Promise<import("@topconsultnpm/sdk-ts").UserDescriptor | import("@topconsultnpm/sdk-ts").WFDescriptor | DcmtTypeDescriptor | import("@topconsultnpm/sdk-ts").DataListDescriptor | import("@topconsultnpm/sdk-ts").RelationDescriptor | import("@topconsultnpm/sdk-ts").GroupDescriptor | import("@topconsultnpm/sdk-ts").SavedQueryDescriptor | import("@topconsultnpm/sdk-ts").AreaDescriptor | import("@topconsultnpm/sdk-ts").BasketTypeDescriptor | import("@topconsultnpm/sdk-ts").TaskDescriptor | import("@topconsultnpm/sdk-ts").WorkingGroupDescriptor | import("@topconsultnpm/sdk-ts").BarcodeArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").BatchUpdaterJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoDoganaleJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoDoganalePlusJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoDoganaleDistillerJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoFiscaleQueryJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoFiscaleSenderJobDescriptor | import("@topconsultnpm/sdk-ts").CheckSequenceJobDescriptor | import("@topconsultnpm/sdk-ts").COSCheckerJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtConverterJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtCreatorJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtDeleterJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtNoteJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtPrinterJobDescriptor | import("@topconsultnpm/sdk-ts").FEAttacherJobDescriptor | import("@topconsultnpm/sdk-ts").FECreatorTxtJobDescriptor | import("@topconsultnpm/sdk-ts").FEDetacherJobDescriptor | import("@topconsultnpm/sdk-ts").FEDistillerJobDescriptor | import("@topconsultnpm/sdk-ts").FESenderWsJobDescriptor | import("@topconsultnpm/sdk-ts").FESplitterJobDescriptor | import("@topconsultnpm/sdk-ts").FEValidatorJobDescriptor | import("@topconsultnpm/sdk-ts").FileArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").FileCheckerJobDescriptor | import("@topconsultnpm/sdk-ts").FileExecJobDescriptor | import("@topconsultnpm/sdk-ts").FileExportJobDescriptor | import("@topconsultnpm/sdk-ts").FileMoverJobDescriptor | import("@topconsultnpm/sdk-ts").LexJobDescriptor | import("@topconsultnpm/sdk-ts").LinkerJobDescriptor | import("@topconsultnpm/sdk-ts").MailArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").MailQueryJobDescriptor | import("@topconsultnpm/sdk-ts").
|
|
9
|
+
static readonly retrieveAdminAsync: (objClass: ObjectClasses, jobType: JobTypes, id: number) => Promise<import("@topconsultnpm/sdk-ts").UserDescriptor | import("@topconsultnpm/sdk-ts").WFDescriptor | DcmtTypeDescriptor | import("@topconsultnpm/sdk-ts").DataListDescriptor | import("@topconsultnpm/sdk-ts").RelationDescriptor | import("@topconsultnpm/sdk-ts").GroupDescriptor | import("@topconsultnpm/sdk-ts").SavedQueryDescriptor | import("@topconsultnpm/sdk-ts").MailSenderJobDescriptor | import("@topconsultnpm/sdk-ts").AreaDescriptor | import("@topconsultnpm/sdk-ts").BasketTypeDescriptor | import("@topconsultnpm/sdk-ts").TaskDescriptor | import("@topconsultnpm/sdk-ts").WorkingGroupDescriptor | import("@topconsultnpm/sdk-ts").BarcodeArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").BatchUpdaterJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoDoganaleJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoDoganalePlusJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoDoganaleDistillerJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoFiscaleQueryJobDescriptor | import("@topconsultnpm/sdk-ts").CassettoFiscaleSenderJobDescriptor | import("@topconsultnpm/sdk-ts").CheckSequenceJobDescriptor | import("@topconsultnpm/sdk-ts").COSCheckerJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtConverterJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtCreatorJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtDeleterJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtNoteJobDescriptor | import("@topconsultnpm/sdk-ts").DcmtPrinterJobDescriptor | import("@topconsultnpm/sdk-ts").FEAttacherJobDescriptor | import("@topconsultnpm/sdk-ts").FECreatorTxtJobDescriptor | import("@topconsultnpm/sdk-ts").FEDetacherJobDescriptor | import("@topconsultnpm/sdk-ts").FEDistillerJobDescriptor | import("@topconsultnpm/sdk-ts").FESenderWsJobDescriptor | import("@topconsultnpm/sdk-ts").FESplitterJobDescriptor | import("@topconsultnpm/sdk-ts").FEValidatorJobDescriptor | import("@topconsultnpm/sdk-ts").FileArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").FileCheckerJobDescriptor | import("@topconsultnpm/sdk-ts").FileExecJobDescriptor | import("@topconsultnpm/sdk-ts").FileExportJobDescriptor | import("@topconsultnpm/sdk-ts").FileMoverJobDescriptor | import("@topconsultnpm/sdk-ts").LexJobDescriptor | import("@topconsultnpm/sdk-ts").LinkerJobDescriptor | import("@topconsultnpm/sdk-ts").MailArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").MailQueryJobDescriptor | import("@topconsultnpm/sdk-ts").MigrationJobDescriptor | import("@topconsultnpm/sdk-ts").OcrSixJobDescriptor | import("@topconsultnpm/sdk-ts").PdDCreatorJobDescriptor | import("@topconsultnpm/sdk-ts").PDFArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").PdVArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").PdVQueryJobDescriptor | import("@topconsultnpm/sdk-ts").PdVSenderJobDescriptor | import("@topconsultnpm/sdk-ts").PeppolQueryJobDescriptor | import("@topconsultnpm/sdk-ts").PeppolSenderJobDescriptor | import("@topconsultnpm/sdk-ts").PostelQueryJobDescriptor | import("@topconsultnpm/sdk-ts").PostelSenderJobDescriptor | import("@topconsultnpm/sdk-ts").ReplicatorJobDescriptor | import("@topconsultnpm/sdk-ts").SAPAlignerJobDescriptor | import("@topconsultnpm/sdk-ts").SAPBarcodeJobDescriptor | import("@topconsultnpm/sdk-ts").SAPDataReaderJobDescriptor | import("@topconsultnpm/sdk-ts").SAPDataWriterJobDescriptor | import("@topconsultnpm/sdk-ts").SignerJobDescriptor | import("@topconsultnpm/sdk-ts").SpoolArchiverJobDescriptor | import("@topconsultnpm/sdk-ts").UpdaterJobDescriptor | import("@topconsultnpm/sdk-ts").DiskDescriptor | import("@topconsultnpm/sdk-ts").LDAPDescriptor | import("@topconsultnpm/sdk-ts").NumeratorDescriptor | ProcessDescriptor | import("@topconsultnpm/sdk-ts").SAPLoginDescriptor | import("@topconsultnpm/sdk-ts").SignCertDescriptor | import("@topconsultnpm/sdk-ts").SignServerDescriptor | import("@topconsultnpm/sdk-ts").TreeDescriptor | import("@topconsultnpm/sdk-ts").TSADescriptor | undefined>;
|
|
10
10
|
private static readonly updateJobAsync;
|
|
11
11
|
static readonly updateAsync: (objClass: ObjectClasses, jobType: JobTypes, d: any, ...args: any[]) => Promise<number | undefined>;
|
|
12
12
|
private static readonly createJobAsync;
|