@topconsultnpm/sdkui-react 6.22.0-dev2.48 → 6.22.0-dev2.49

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.
@@ -183,6 +183,11 @@ const TMSearch = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTask
183
183
  await setSQDAsync(sqdToRestore?.id === SYS_ALL_DCMTS_SQD_ID ? await getSysAllDcmtsSQD(tid, false) : sqdToRestore);
184
184
  // mruTIDs è tra le dipendenze perché setSQDAsync lo legge
185
185
  }, [fromDTD?.id, currentTID, currentSQD, mruTIDs]);
186
+ // Prima di ogni ricerca il pannello rilegge i metadati del tipo documento: si recepisce il descrittore
187
+ // aggiornato, così anche il resto della vista (titoli, badge, form dei metadati) lavora sulla lista corrente
188
+ const handleDcmtTypeReloaded = useCallback((dtd) => {
189
+ setFromDTD(dtd);
190
+ }, []);
186
191
  const onRefreshSearchAsyncDatagrid = async () => {
187
192
  try {
188
193
  if (lastQdSearched) {
@@ -239,10 +244,10 @@ const TMSearch = ({ allTasks = [], getAllTasks, deleteTaskByIdsCallback, addTask
239
244
  SDKUI_Globals.userSettings.searchSettings.mruTIDs = newMruTIDS;
240
245
  setMruTIDs(newMruTIDS);
241
246
  } }), [mruTIDs, currentMruTID, deviceType]);
242
- const tmSearchQueryPanelElement = useMemo(() => _jsx(TMSearchQueryPanelWrapper, { isSearchViewOnScreen: currentSearchView === TMSearchViews.Search, passToArchiveCallback: passToArchiveCallback, isExpertMode: isExpertMode, showBackToResultButton: searchResult.length > 0, fromDTD: fromDTD, SQD: currentSQD, inputMids: inputMids, maxDcmtsToBeReturned: maxDcmtsToBeReturned, onBackToResult: () => { setCurrentSearchView(TMSearchViews.Result); }, onSearchCompleted: handleSearchCompleted, onRefreshRequested: refreshSearchQueryPanelAsync, onSqdSaved: async (newSqd) => {
247
+ const tmSearchQueryPanelElement = useMemo(() => _jsx(TMSearchQueryPanelWrapper, { isSearchViewOnScreen: currentSearchView === TMSearchViews.Search, passToArchiveCallback: passToArchiveCallback, isExpertMode: isExpertMode, showBackToResultButton: searchResult.length > 0, fromDTD: fromDTD, SQD: currentSQD, inputMids: inputMids, maxDcmtsToBeReturned: maxDcmtsToBeReturned, onBackToResult: () => { setCurrentSearchView(TMSearchViews.Result); }, onSearchCompleted: handleSearchCompleted, onRefreshRequested: refreshSearchQueryPanelAsync, onDcmtTypeReloaded: handleDcmtTypeReloaded, onSqdSaved: async (newSqd) => {
243
248
  await loadDataSQDsAsync(true, newSqd.masterTID);
244
249
  await setSQDAsync(newSqd);
245
- } }), [fromDTD, showSearchResults, setShowSearchResults, currentSQD, currentSearchView, isExpertMode, mruTIDs, searchResult, passToArchiveCallback, inputMids, maxDcmtsToBeReturned, handleSearchCompleted, refreshSearchQueryPanelAsync]);
250
+ } }), [fromDTD, showSearchResults, setShowSearchResults, currentSQD, currentSearchView, isExpertMode, mruTIDs, searchResult, passToArchiveCallback, inputMids, maxDcmtsToBeReturned, handleSearchCompleted, refreshSearchQueryPanelAsync, handleDcmtTypeReloaded]);
246
251
  const tmSavedQuerySelectorElement = useMemo(() => _jsxs(TabPanel, { width: "100%", height: "100%", showNavButtons: true, repaintChangesOnly: true, selectedIndex: currentSQDMode, onSelectedIndexChange: (index) => setCurrentSQDMode(index), children: [(currentTID || currentSQD) ? _jsx(Item, { title: fromDTD?.nameLoc, children: _jsx(TMSavedQuerySelectorWrapper, { allowShowSearch: false, items: filteredByTIDSQDs, selectedId: currentSQD?.id, onRefreshData: () => { loadDataSQDsAsync(true); }, onItemClick: (sqd) => {
247
252
  onSQDItemClick(sqd, setSQDAsync);
248
253
  }, onDeleted: (sqd) => onSQDDeleted(sqd, sqd.id == currentSQD?.id ? filteredByTIDSQDs.find(o => o.id == 1) : currentSQD, setSQDAsync), refreshFavoriteSavedQueries: refreshFavoriteSavedQueries }) }) : _jsx(_Fragment, {}), _jsx(Item, { title: SDKUI_Localizator.AllFemale, children: _jsx(TMSavedQuerySelectorWrapper, { allowShowSearch: true, items: allSQDs, manageDefault: false, onItemClick: (sqd) => {
@@ -342,11 +347,11 @@ const TMRecentsManagerWrapper = ({ mruTIDs, currentMruTID, deviceType, onSelecte
342
347
  onDeletedTID?.(tid);
343
348
  } }));
344
349
  };
345
- const TMSearchQueryPanelWrapper = ({ isSearchViewOnScreen, fromDTD, SQD, isExpertMode, showBackToResultButton, onSearchCompleted, onSqdSaved, onBackToResult, passToArchiveCallback, inputMids, maxDcmtsToBeReturned, onRefreshRequested }) => {
350
+ const TMSearchQueryPanelWrapper = ({ isSearchViewOnScreen, fromDTD, SQD, isExpertMode, showBackToResultButton, onSearchCompleted, onSqdSaved, onBackToResult, passToArchiveCallback, inputMids, maxDcmtsToBeReturned, onRefreshRequested, onDcmtTypeReloaded }) => {
346
351
  const { setPanelVisibilityById, toggleMaximize, countVisibleLeafPanels } = useTMPanelManagerContext();
347
352
  const deviceType = useDeviceType();
348
353
  const isMobile = deviceType === DeviceType.MOBILE;
349
- return (_jsx(TMSearchQueryPanel, { isSearchViewOnScreen: isSearchViewOnScreen, onClosePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => setPanelVisibilityById('TMSearchQueryPanel', false) : undefined, allowMaximize: !isMobile && countVisibleLeafPanels() > 1, onMaximizePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => toggleMaximize("TMSearchQueryPanel") : undefined, isExpertMode: isExpertMode, fromDTD: fromDTD, SQD: SQD, inputMids: inputMids, onSearchCompleted: onSearchCompleted, onRefreshRequested: onRefreshRequested, onSqdSaved: onSqdSaved, showBackToResultButton: showBackToResultButton, onBackToResult: onBackToResult, passToArchiveCallback: passToArchiveCallback, maxDcmtsToBeReturned: maxDcmtsToBeReturned }));
354
+ return (_jsx(TMSearchQueryPanel, { isSearchViewOnScreen: isSearchViewOnScreen, onClosePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => setPanelVisibilityById('TMSearchQueryPanel', false) : undefined, allowMaximize: !isMobile && countVisibleLeafPanels() > 1, onMaximizePanel: (!isMobile && countVisibleLeafPanels() > 1) ? () => toggleMaximize("TMSearchQueryPanel") : undefined, isExpertMode: isExpertMode, fromDTD: fromDTD, SQD: SQD, inputMids: inputMids, onSearchCompleted: onSearchCompleted, onRefreshRequested: onRefreshRequested, onDcmtTypeReloaded: onDcmtTypeReloaded, onSqdSaved: onSqdSaved, showBackToResultButton: showBackToResultButton, onBackToResult: onBackToResult, passToArchiveCallback: passToArchiveCallback, maxDcmtsToBeReturned: maxDcmtsToBeReturned }));
350
355
  };
351
356
  const TMSavedQuerySelectorWrapper = ({ items, selectedId, allowShowSearch, manageDefault, onRefreshData, onItemClick, onDeleted, refreshFavoriteSavedQueries }) => {
352
357
  const { setPanelVisibilityById } = useTMPanelManagerContext();
@@ -23,6 +23,8 @@ interface ITMSearchQueryPanelProps {
23
23
  }>, tid?: number) => void;
24
24
  maxDcmtsToBeReturned?: number;
25
25
  onRefreshRequested?: () => Promise<void>;
26
+ /** Notifica il tipo documento riletto dal server prima di ogni ricerca, così il chiamante allinea il proprio descrittore */
27
+ onDcmtTypeReloaded?: (dtd: DcmtTypeDescriptor) => void;
26
28
  }
27
29
  declare const TMSearchQueryPanel: React.FunctionComponent<ITMSearchQueryPanelProps>;
28
30
  export default TMSearchQueryPanel;
@@ -24,7 +24,7 @@ import TMToppyMessage from '../../../helper/TMToppyMessage';
24
24
  import TMMetadataSorterForm from './TMMetadataSorterForm';
25
25
  import TMMetadataOutputForm from './TMMetadataOutputForm';
26
26
  import TMTooltip from '../../base/TMTooltip';
27
- const TMSearchQueryPanel = ({ isSearchViewOnScreen = true, fromDTD, showBackToResultButton, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, SQD, inputMids, onSearchCompleted, onSqdSaved, onBack, onClosePanel, allowMaximize = true, onMaximizePanel, onBackToResult, passToArchiveCallback, maxDcmtsToBeReturned, onRefreshRequested }) => {
27
+ const TMSearchQueryPanel = ({ isSearchViewOnScreen = true, fromDTD, showBackToResultButton, isExpertMode = SDKUI_Globals.userSettings.advancedSettings.expertMode === 1, SQD, inputMids, onSearchCompleted, onSqdSaved, onBack, onClosePanel, allowMaximize = true, onMaximizePanel, onBackToResult, passToArchiveCallback, maxDcmtsToBeReturned, onRefreshRequested, onDcmtTypeReloaded }) => {
28
28
  const [confirmQueryParams, ConfirmQueryParamsDialog] = useQueryParametersDialog();
29
29
  const [qd, setQd] = useState();
30
30
  const [lastQdParams, setLastQdParams] = useState([]);
@@ -55,6 +55,7 @@ const TMSearchQueryPanel = ({ isSearchViewOnScreen = true, fromDTD, showBackToRe
55
55
  const qdRef = useRef(undefined);
56
56
  const showAdvancedSearchRef = useRef(false);
57
57
  const searchAsyncRef = useRef();
58
+ const reloadMetadataAsyncRef = useRef();
58
59
  // Tornando dalla vista risultati il pannello dei metadati di ricerca riprende il focus,
59
60
  // così è lui quello evidenziato: prendendo il focus gli altri pannelli ricevono l'onBlur e si disattivano
60
61
  useEffect(() => {
@@ -173,10 +174,39 @@ const TMSearchQueryPanel = ({ isSearchViewOnScreen = true, fromDTD, showBackToRe
173
174
  onSearchCompleted?.(results, searchResult?.qd, append);
174
175
  }
175
176
  };
177
+ // Tra l'apertura della ricerca e il click su Ricerca la lista dei metadati del tipo documento può essere
178
+ // cambiata (metadati aggiunti o rimossi lato amministrazione): prima di cercare si rileggono dal server.
179
+ // I valori digitati restano, mentre i filtri sui metadati non più disponibili vengono scartati.
180
+ // Restituisce il qd con cui eseguire la ricerca.
181
+ const reloadMetadataAsync = async (qdInput) => {
182
+ if (!qdInput?.from?.tid)
183
+ return qdInput;
184
+ let dcmtTypes;
185
+ try {
186
+ TMSpinner.show({ description: `${SDKUI_Localizator.Loading} ...`, backgroundColor: 'transparent' });
187
+ dcmtTypes = await getDcmtTypesByQdAsync(qdInput, true);
188
+ }
189
+ finally {
190
+ TMSpinner.hide();
191
+ }
192
+ // Rilettura non riuscita: si cerca con i metadati che si hanno, senza scartare nulla
193
+ if (dcmtTypes.length <= 0)
194
+ return qdInput;
195
+ setDcmtTypesList(dcmtTypes);
196
+ const reloadedFromDTD = dcmtTypes.find(o => o.id === qdInput.from?.tid);
197
+ if (reloadedFromDTD)
198
+ onDcmtTypeReloaded?.(reloadedFromDTD);
199
+ const { qd: newQd, removedCount } = dropUnavailableMetadataFromQd(qdInput, dcmtTypes);
200
+ if (removedCount <= 0)
201
+ return qdInput;
202
+ setQd(newQd);
203
+ return newQd;
204
+ };
176
205
  // Allineati a ogni render: runSearch li legge quando esegue, non quando viene creata
177
206
  qdRef.current = qd;
178
207
  showAdvancedSearchRef.current = showAdvancedSearch;
179
208
  searchAsyncRef.current = searchAsync;
209
+ reloadMetadataAsyncRef.current = reloadMetadataAsync;
180
210
  // Unico punto di avvio della ricerca: bottone Ricerca, Ricerca e accoda e tasto Invio passano tutti da qui
181
211
  const runSearch = useCallback((append) => {
182
212
  if (isSearchingRef.current)
@@ -188,7 +218,9 @@ const TMSearchQueryPanel = ({ isSearchViewOnScreen = true, fromDTD, showBackToRe
188
218
  // Alcuni editor committano il valore in modo asincrono: si attende un tick prima di leggere il qd definitivo
189
219
  setTimeout(async () => {
190
220
  try {
191
- await searchAsyncRef.current?.(qdRef.current, showAdvancedSearchRef.current, append);
221
+ // I metadati si rileggono a ogni ricerca: si cerca sempre sulla lista aggiornata
222
+ const qdToSearch = await reloadMetadataAsyncRef.current?.(qdRef.current) ?? qdRef.current;
223
+ await searchAsyncRef.current?.(qdToSearch, showAdvancedSearchRef.current, append);
192
224
  }
193
225
  catch (ex) {
194
226
  TMExceptionBoxManager.show({ exception: ex });
@@ -418,6 +450,33 @@ const TMSearchQueryPanel = ({ isSearchViewOnScreen = true, fromDTD, showBackToRe
418
450
  } })] }));
419
451
  };
420
452
  export default TMSearchQueryPanel;
453
+ /** Scarta dal qd filtri, colonne e ordinamenti sui metadati non più esistenti o non più accessibili, in base
454
+ * alla lista dei metadati appena riletta dal server. I valori digitati su quelli ancora presenti si mantengono. */
455
+ const dropUnavailableMetadataFromQd = (qdInput, dcmtTypes) => {
456
+ const metadataOf = (tid) => dcmtTypes.find(o => o.id === tid)?.metadata;
457
+ // Un tipo documento non riletto non è verificabile: i suoi item si mantengono così come sono.
458
+ // Sui metadati di sistema si verifica solo l'esistenza: i loro permessi non li rendono inutilizzabili.
459
+ const isStillAvailable = (tid, mid, isUsable) => {
460
+ const metadata = metadataOf(tid);
461
+ if (!metadata || metadata.length <= 0 || mid == undefined)
462
+ return true;
463
+ const md = metadata.find(o => o.id === mid);
464
+ if (!md)
465
+ return false;
466
+ return md.isSystem == 1 || isUsable(md);
467
+ };
468
+ const canSearch = (md) => md.perm?.canSearch != AccessLevels.No;
469
+ const canOutput = (md) => !(md.perm?.canView == AccessLevels.No && md.perm?.canUpdate == AccessLevels.No);
470
+ const where = qdInput.where?.filter(o => isStillAvailable(o.tid, o.mid, canSearch)) ?? [];
471
+ const select = qdInput.select?.filter(o => isStillAvailable(o.tid, o.mid, canOutput)) ?? [];
472
+ const orderBy = qdInput.orderBy?.filter(o => isStillAvailable(o.tid, o.mid, canOutput)) ?? [];
473
+ const removedCount = ((qdInput.where?.length ?? 0) - where.length)
474
+ + ((qdInput.select?.length ?? 0) - select.length)
475
+ + ((qdInput.orderBy?.length ?? 0) - orderBy.length);
476
+ let qd = new QueryDescriptor();
477
+ qd.init({ ...qdInput, where: where, select: select, orderBy: orderBy });
478
+ return { qd: qd, removedCount: removedCount };
479
+ };
421
480
  const searchByQdAsync = async (qdInput, searchParams) => {
422
481
  let result;
423
482
  let qdSearch;
@@ -5,7 +5,10 @@ export type TID_Alias = {
5
5
  alias: string | undefined;
6
6
  };
7
7
  export declare const getTIDsByQd: (qd: QueryDescriptor | undefined) => TID_Alias[];
8
- export declare const getDcmtTypesByQdAsync: (qd: QueryDescriptor) => Promise<import("@topconsultnpm/sdk-ts").DcmtTypeDescriptor[]>;
8
+ /** Restituisce i tipi documento (con metadati) referenziati da qd.
9
+ * Con refreshCache = true i descrittori vengono riletti dal server, così la lista dei metadati
10
+ * recepisce quelli aggiunti o rimossi dopo il popolamento della cache. */
11
+ export declare const getDcmtTypesByQdAsync: (qd: QueryDescriptor, refreshCache?: boolean) => Promise<import("@topconsultnpm/sdk-ts").DcmtTypeDescriptor[]>;
9
12
  export declare const displayMetadataValue: (md: MetadataDescriptor | undefined, value: string | undefined, valueEmptyDescription?: string) => string;
10
13
  export declare const IsParametricQuery: (qd: QueryDescriptor | undefined) => boolean;
11
14
  export declare const addHiddenSelectItem: (select: SelectItem[], tid: number | undefined, mid: SystemMIDsAsNumber) => void;
@@ -15,8 +15,11 @@ export const getTIDsByQd = (qd) => {
15
15
  }
16
16
  return tids;
17
17
  };
18
- export const getDcmtTypesByQdAsync = async (qd) => {
19
- return await DcmtTypeListCacheService.GetFromQdAsync(qd);
18
+ /** Restituisce i tipi documento (con metadati) referenziati da qd.
19
+ * Con refreshCache = true i descrittori vengono riletti dal server, così la lista dei metadati
20
+ * recepisce quelli aggiunti o rimossi dopo il popolamento della cache. */
21
+ export const getDcmtTypesByQdAsync = async (qd, refreshCache = false) => {
22
+ return await DcmtTypeListCacheService.GetFromQdAsync(qd, undefined, false, refreshCache);
20
23
  };
21
24
  export const displayMetadataValue = (md, value, valueEmptyDescription = "") => {
22
25
  if (!value)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.22.0-dev2.48",
3
+ "version": "6.22.0-dev2.49",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",