@topconsultnpm/sdkui-react 6.22.0-dev2.21 → 6.22.0-dev2.22

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.
@@ -46,13 +46,14 @@ export interface ArchiveRow {
46
46
  * stringhe, quindi il `value` generico di DevExtreme si restringe
47
47
  */
48
48
  export type ArchiveRowCell = Omit<DataGridTypes.ColumnCellTemplateData<ArchiveRow, number>, 'value'> & {
49
- readonly value?: string;
49
+ readonly value?: string | number;
50
50
  };
51
51
  /**
52
52
  * Modifiche di una riga in arrivo dalla griglia (mid -> nuovo valore): in modifica diretta ci sono
53
- * solo i metadati testuali (vedi isInlineEditableMetadata) e l'editor svuotato restituisce null
53
+ * i metadati testuali e numerici (vedi isInlineEditableMetadata), quindi stringhe e numeri,
54
+ * e l'editor svuotato restituisce null
54
55
  */
55
- export type ArchiveRowChanges = Record<string, string | null | undefined>;
56
+ export type ArchiveRowChanges = Record<string, string | number | null | undefined>;
56
57
  /** Aggiornamento di una riga della griglia, con le sole modifiche possibili in linea */
57
58
  export type ArchiveRowUpdatingEvent = Omit<DataGridTypes.RowUpdatingEvent<ArchiveRow, number>, 'newData'> & {
58
59
  newData: ArchiveRowChanges;
@@ -70,10 +71,15 @@ export declare const canArchive: (dtd?: DcmtTypeDescriptor) => boolean;
70
71
  */
71
72
  export declare const INLINE_EDITABLE_CELL_CLASS = "tm-cell-inline-editable";
72
73
  /**
73
- * Modifica diretta in griglia: solo il testo libero. Liste dati, calcolati, numeratori e speciali
74
- * hanno editor e vincoli propri, date e numeri una formattazione dedicata: restano al form
74
+ * Modifica diretta in griglia: testo libero e numeri. Liste dati, calcolati, numeratori e speciali
75
+ * hanno editor e vincoli propri, le date una formattazione dedicata: restano al form
75
76
  */
76
77
  export declare const isInlineEditableMetadata: (md: MetadataDescriptor) => boolean;
78
+ /**
79
+ * Valore di una cella numerica: l'editor della griglia vuole un numero, non la stringa che
80
+ * la riga porta in `__values` per l'archiviazione. Vuoto o non numerico: cella vuota
81
+ */
82
+ export declare const toGridNumber: (value: unknown) => number | undefined;
77
83
  /** Colonne della griglia di riepilogo dai metadati (utente) del tipo documento */
78
84
  export declare const buildColumnsFromDtd: (dtd: DcmtTypeDescriptor | undefined, renderDataListCell: (value: string | Date | number | undefined, dataListID: number, viewMode: DataListViewModes) => React.ReactElement) => Array<IColumnProps>;
79
85
  export declare const getDetailDtdAsync: (detailTID: number | undefined) => Promise<DcmtTypeDescriptor | undefined>;
@@ -27,12 +27,22 @@ export const canArchive = (dtd) => dtd?.perm?.canArchive === AccessLevelsEx.Yes
27
27
  */
28
28
  export const INLINE_EDITABLE_CELL_CLASS = 'tm-cell-inline-editable';
29
29
  /**
30
- * Modifica diretta in griglia: solo il testo libero. Liste dati, calcolati, numeratori e speciali
31
- * hanno editor e vincoli propri, date e numeri una formattazione dedicata: restano al form
30
+ * Modifica diretta in griglia: testo libero e numeri. Liste dati, calcolati, numeratori e speciali
31
+ * hanno editor e vincoli propri, le date una formattazione dedicata: restano al form
32
32
  */
33
- export const isInlineEditableMetadata = (md) => md.dataType === MetadataDataTypes.Varchar
33
+ export const isInlineEditableMetadata = (md) => (md.dataType === MetadataDataTypes.Varchar || md.dataType === MetadataDataTypes.Number)
34
34
  && (md.dataDomain === undefined || md.dataDomain === MetadataDataDomains.None)
35
35
  && md.isSystem !== 1 && md.isSystemDerived !== 1;
36
+ /**
37
+ * Valore di una cella numerica: l'editor della griglia vuole un numero, non la stringa che
38
+ * la riga porta in `__values` per l'archiviazione. Vuoto o non numerico: cella vuota
39
+ */
40
+ export const toGridNumber = (value) => {
41
+ if (value === undefined || value === null || value === '')
42
+ return undefined;
43
+ const parsed = typeof value === 'number' ? value : Number(value);
44
+ return Number.isFinite(parsed) ? parsed : undefined;
45
+ };
36
46
  /** Colonne della griglia di riepilogo dai metadati (utente) del tipo documento */
37
47
  export const buildColumnsFromDtd = (dtd, renderDataListCell) => getUserMetadataSorted(dtd).map(md => {
38
48
  const dataListID = md.dataListID ?? 0;
@@ -41,21 +51,25 @@ export const buildColumnsFromDtd = (dtd, renderDataListCell) => getUserMetadataS
41
51
  const dataType = md.dataType;
42
52
  const format = md.format?.format;
43
53
  const formatCulture = md.format?.formatCulture;
44
- // Date e numeri usano la formattazione scalare; le liste dati il render comune
45
- const needsScalarFormat = !isDataList && (dataType === MetadataDataTypes.DateTime || dataType === MetadataDataTypes.Number);
46
54
  const isInlineEditable = isInlineEditableMetadata(md);
55
+ const isNumber = dataType === MetadataDataTypes.Number;
56
+ // Date e numeri usano la formattazione scalare; le liste dati il render comune. La cella
57
+ // modificabile mostra sempre l'editor, quindi non ha un proprio render
58
+ const needsScalarFormat = !isDataList && !isInlineEditable && (dataType === MetadataDataTypes.DateTime || isNumber);
47
59
  return {
48
60
  dataField: String(md.id),
49
61
  caption: (SDK_Globals.useLocalizedName ? md.nameLoc : md.name) ?? md.name ?? '',
50
62
  // La colonna modificabile dichiara il tipo: senza valori DevExtreme non saprebbe che editor usare
51
63
  ...(isInlineEditable
52
64
  ? {
53
- dataType: 'string',
65
+ // I numeri arrivano in cella già come numeri (vedi buildArchiveRow): l'editor è la casella numerica
66
+ dataType: isNumber ? 'number' : 'string',
54
67
  allowEditing: true,
55
68
  showEditorAlways: true,
56
69
  cssClass: INLINE_EDITABLE_CELL_CLASS,
57
- // Lunghezza e obbligatorietà del metadato valgono anche in griglia
58
- editorOptions: md.length ? { maxLength: md.length } : undefined,
70
+ // Lunghezza e obbligatorietà del metadato valgono anche in griglia; sui numeri
71
+ // i limiti restano all'API, in cella basta che sia un numero
72
+ editorOptions: !isNumber && md.length ? { maxLength: md.length } : undefined,
59
73
  validationRules: String(md.isRequired) === '1' ? [{ type: 'required', message: SDKUI_Localizator.RequiredField }] : undefined,
60
74
  }
61
75
  : { allowEditing: false }),
@@ -8,7 +8,7 @@ import TMSpinner from '../components/base/TMSpinner';
8
8
  import ShowAlert from '../components/base/TMAlert';
9
9
  import { TMResultManager } from '../components/forms/TMResultDialog';
10
10
  import { useDataListItem } from './useDataListItem';
11
- import { buildColumnsFromDtd, canArchive, canUpdateMasterCallback, getDetailDtdAsync } from '../components/features/documents/TMMultiMasterDetailDcmtsUtils';
11
+ import { buildColumnsFromDtd, canArchive, canUpdateMasterCallback, getDetailDtdAsync, toGridNumber } from '../components/features/documents/TMMultiMasterDetailDcmtsUtils';
12
12
  /** Fasi del flusso di archiviazione multipla dei dettagli */
13
13
  export var MultiDetailArchivePhase;
14
14
  (function (MultiDetailArchivePhase) {
@@ -44,6 +44,8 @@ export const useMultiMasterDetailDcmts = ({ dtd, masterDcmt, onClose }) => {
44
44
  // Struttura del tipo documento selezionato
45
45
  const [detailColumns, setDetailColumns] = useState([]);
46
46
  const [detailSupportsFile, setDetailSupportsFile] = useState(false);
47
+ // Mid numerici del tipo di dettaglio: in griglia le loro celle portano il numero (vedi buildArchiveRow)
48
+ const numericMidsRef = useRef(new Set());
47
49
  // Dettagli già archiviati del tipo selezionato, collegati al master
48
50
  const [archivedDetailResults, setArchivedDetailResults] = useState([]);
49
51
  const [isLoadingArchivedDetails, setIsLoadingArchivedDetails] = useState(false);
@@ -146,6 +148,7 @@ export const useMultiMasterDetailDcmts = ({ dtd, masterDcmt, onClose }) => {
146
148
  if (!selectedRelation?.detailTID) {
147
149
  setDetailColumns([]);
148
150
  setDetailSupportsFile(false);
151
+ numericMidsRef.current = new Set();
149
152
  return;
150
153
  }
151
154
  try {
@@ -153,16 +156,21 @@ export const useMultiMasterDetailDcmts = ({ dtd, masterDcmt, onClose }) => {
153
156
  setDetailSupportsFile(detailDtd?.archiveConstraint !== ArchiveConstraints.OnlyMetadata);
154
157
  // Liste dati referenziate dai metadati, servono al render delle celle
155
158
  const dataListIDs = new Set();
159
+ const numericMids = new Set();
156
160
  (detailDtd?.metadata ?? []).forEach(md => {
157
161
  if (md.dataDomain === MetadataDataDomains.DataList && md.dataListID)
158
162
  dataListIDs.add(md.dataListID);
163
+ if (md.dataType === MetadataDataTypes.Number && md.id !== undefined)
164
+ numericMids.add(md.id);
159
165
  });
166
+ numericMidsRef.current = numericMids;
160
167
  await loadDataListsAsync(dataListIDs);
161
168
  setDetailColumns(buildColumnsFromDtd(detailDtd, renderDataListCell));
162
169
  }
163
170
  catch {
164
171
  setDetailColumns([]);
165
172
  setDetailSupportsFile(false);
173
+ numericMidsRef.current = new Set();
166
174
  }
167
175
  };
168
176
  loadDetailStructureAsync();
@@ -315,11 +323,13 @@ export const useMultiMasterDetailDcmts = ({ dtd, masterDcmt, onClose }) => {
315
323
  },
316
324
  });
317
325
  }, []);
326
+ // I valori del form sono stringhe: le celle numeriche vogliono il numero, richiesto dal loro editor
318
327
  const buildArchiveRow = useCallback((id, tid, values, file) => {
319
328
  const row = { id, __tid: tid, __values: values, __file: file };
320
329
  for (const v of values) {
321
- if (v.mid !== undefined)
322
- row[String(v.mid)] = v.value ?? '';
330
+ if (v.mid === undefined)
331
+ continue;
332
+ row[String(v.mid)] = numericMidsRef.current.has(v.mid) ? toGridNumber(v.value) : (v.value ?? '');
323
333
  }
324
334
  return row;
325
335
  }, []);
@@ -338,7 +348,7 @@ export const useMultiMasterDetailDcmts = ({ dtd, masterDcmt, onClose }) => {
338
348
  closeAddForm();
339
349
  };
340
350
  /**
341
- * Modifica diretta in griglia di uno o più metadati testuali (changes: mid -> valore).
351
+ * Modifica diretta in griglia di uno o più metadati testuali o numerici (changes: mid -> valore).
342
352
  * La riga e i suoi __values sono ricreati: il duplicato, che condivide __values per
343
353
  * riferimento, resta invariato
344
354
  */
@@ -346,9 +356,10 @@ export const useMultiMasterDetailDcmts = ({ dtd, masterDcmt, onClose }) => {
346
356
  const changedMids = Object.keys(changes);
347
357
  if (changedMids.length === 0)
348
358
  return;
349
- // La griglia restituisce null sull'editor svuotato: a sistema il metadato va vuoto, non nullo
359
+ // I __values vanno a sistema come stringhe, anche quelli che in griglia sono numeri. La griglia
360
+ // restituisce null sull'editor svuotato: a sistema il metadato va vuoto, non nullo
350
361
  const normalized = {};
351
- changedMids.forEach(mid => { normalized[mid] = changes[mid] ?? ''; });
362
+ changedMids.forEach(mid => { normalized[mid] = changes[mid] === null || changes[mid] === undefined ? '' : String(changes[mid]); });
352
363
  setArchiveRows(prev => prev.map(r => {
353
364
  if (r.id !== rowId)
354
365
  return r;
@@ -364,7 +375,8 @@ export const useMultiMasterDetailDcmts = ({ dtd, masterDcmt, onClose }) => {
364
375
  values.push(added);
365
376
  });
366
377
  const updated = { ...r, __values: values };
367
- changedMids.forEach(mid => { updated[mid] = normalized[mid]; });
378
+ // In cella il numero resta un numero, come lo vuole il suo editor
379
+ changedMids.forEach(mid => { updated[mid] = numericMidsRef.current.has(Number(mid)) ? toGridNumber(normalized[mid]) : normalized[mid]; });
368
380
  return updated;
369
381
  }));
370
382
  }, []);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@topconsultnpm/sdkui-react",
3
- "version": "6.22.0-dev2.21",
3
+ "version": "6.22.0-dev2.22",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1",