@fto-consult/expo-ui 2.34.1 → 2.34.3

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/appConfig.txt CHANGED
@@ -15,5 +15,6 @@
15
15
  sprintfSelectors : {
16
16
  "&libele&" : selectLabel,
17
17
  }
18
- getTableData : {function(tableName)=>table} retourne l'ojet table data
18
+ getTableData : {function(tableName)=>table} retourne l'ojet table data,
19
+ swrRefreshTimeout : {number} le délai d'inactivité auquel, une fois l'application active, les données de type listData sont rafraichies
19
20
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fto-consult/expo-ui",
3
- "version": "2.34.1",
3
+ "version": "2.34.3",
4
4
  "description": "Bibliothèque de composants UI Expo,react-native",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -61,7 +61,7 @@
61
61
  "@emotion/native": "^11.10.0",
62
62
  "@expo/html-elements": "^0.2.0",
63
63
  "@expo/vector-icons": "^13.0.0",
64
- "@fto-consult/common": "^1.26.0",
64
+ "@fto-consult/common": "^2.1.2",
65
65
  "@gorhom/portal": "^1.0.14",
66
66
  "@react-native-async-storage/async-storage": "~1.17.3",
67
67
  "@react-native-community/datetimepicker": "6.5.2",
package/src/App.js CHANGED
@@ -30,25 +30,37 @@ import appConfig from "$capp/config";
30
30
  import {showPrompt} from "$components/Dialog/confirm";
31
31
  import { AppState } from 'react-native'
32
32
  import {canFetchOffline} from "$capi/utils";
33
+ import {defaultNumber} from "$utils";
34
+ import { timeout as SWR_REFRESH_TIMEOUT} from '$ecomponents/Datagrid/SWRDatagrid';
33
35
 
34
36
  import * as Utils from "$utils";
35
37
  Object.map(Utils,(v,i)=>{
36
38
  if(typeof v =='function' && typeof window !='undefined' && window && !window[i]){
37
39
  window[i] = v;
38
40
  }
39
- })
40
-
41
+ });
41
42
  export default function getIndex(options){
42
43
  const {App,onMount,onUnmount,preferences:appPreferences} = defaultObj(options);
43
44
  return function MainIndexComponent() {
44
45
  const isScreenFocusedRef = React.useRef(true);
46
+ ///garde pour chaque écran sa date de dernière activité
47
+ const screensRef = React.useRef({});//la liste des écrans actifs
48
+ const activeScreenRef = React.useRef('');
49
+ const prevActiveScreenRef = React.useRef('');
50
+ const appStateRef = React.useRef({});
45
51
  React.useEffect(()=>{
46
52
  ///la fonction de rappel lorsque le composant est monté
47
53
  let cb = typeof onMount =='function'? onMount() : null;
48
- const onScreenFocus = ()=>{
54
+ const onScreenFocus = ({sanitizedName})=>{
55
+ prevActiveScreenRef.current = activeScreenRef.current;
56
+ if(activeScreenRef.current){
57
+ screensRef.current[activeScreenRef.current] = null;
58
+ }
59
+ screensRef.current[sanitizedName] = new Date();
60
+ activeScreenRef.current = sanitizedName;
49
61
  isScreenFocusedRef.current = true;
50
62
  }, onScreenBlur = ()=>{
51
- isScreenFocusedRef.current = false;
63
+ isScreenFocusedRef.current = false;
52
64
  }
53
65
  APP.on(APP.EVENTS.SCREEN_FOCUS,onScreenFocus);
54
66
  APP.on(APP.EVENTS.SCREEN_BLUR,onScreenBlur);
@@ -86,18 +98,28 @@ export default function getIndex(options){
86
98
  return APP.isOnline();
87
99
  },
88
100
  isVisible() {
89
- /* Customize the visibility state detector */
90
- return false;
91
- return isScreenFocusedRef.current;
101
+ const screen = activeScreenRef.current;
102
+ if(!screen) return false;
103
+ if(!screensRef.current[screen]){
104
+ screensRef.current[screen] = new Date();
105
+ return false;
106
+ }
107
+ const date = screensRef.current[screen];
108
+ const diff = new Date().getTime() - date.getTime();
109
+ const timeout = defaultNumber(appConfig.get("swrRefreshTimeout"),SWR_REFRESH_TIMEOUT)
110
+ screensRef.current[screen] = new Date();
111
+ return diff >= timeout ? true : false;
92
112
  },
93
113
  initFocus(callback) {
94
114
  let appState = AppState.currentState
95
115
  const onAppStateChange = (nextAppState) => {
96
116
  /* If it's resuming from background or inactive mode to active one */
97
- if (appState.match(/inactive|background/) && nextAppState === 'active') {
117
+ const active = appState.match(/inactive|background/) && nextAppState === 'active';
118
+ if (active) {
98
119
  callback()
99
120
  }
100
- appState = nextAppState
121
+ appState = nextAppState;
122
+ appStateRef.current = !!active;
101
123
  }
102
124
  // Subscribe to the app state change events
103
125
  const subscription = AppState.addEventListener('change', onAppStateChange);
@@ -13,7 +13,7 @@ import Image from "$ecomponents/Image";
13
13
  import Icon,{COPY_ICON} from "$ecomponents/Icon";
14
14
  import filterUtils from "$cfilters";
15
15
  import Hashtag from "$ecomponents/Hashtag";
16
- import {sortBy,isDecimal,extendObj,isObjOrArray,isObj,defaultNumber,defaultStr,isFunction,defaultBool,defaultArray,defaultObj,isNonNullString,defaultDecimal} from "$utils";
16
+ import {sortBy,isDecimal,defaultVal,extendObj,isObjOrArray,isObj,defaultNumber,defaultStr,isFunction,defaultBool,defaultArray,defaultObj,isNonNullString,defaultDecimal} from "$utils";
17
17
  import {Datagrid as DatagridContentLoader} from "$ecomponents/ContentLoader";
18
18
  import React from "$react";
19
19
  import DateLib from "$lib/date";
@@ -1063,7 +1063,7 @@ export default class CommonDatagridComponent extends AppComponent {
1063
1063
  this.isUpdating = false;
1064
1064
  this.setSessionData({showFilters});
1065
1065
  })
1066
- },100);
1066
+ },100);
1067
1067
  }
1068
1068
  showFilters(){
1069
1069
  return this.toggleFilters(true);
@@ -1096,7 +1096,7 @@ export default class CommonDatagridComponent extends AppComponent {
1096
1096
  this.isUpdating = false;
1097
1097
  this.setSessionData({showFooters:showOrHide})
1098
1098
  })
1099
- },200)
1099
+ },0)
1100
1100
  }
1101
1101
  showFooters(){
1102
1102
  return this.toggleFooters(true);
@@ -1143,8 +1143,11 @@ export default class CommonDatagridComponent extends AppComponent {
1143
1143
  if(isObj(footers[field])){
1144
1144
  footers[field].visible = columns[field].visible;
1145
1145
  }
1146
- this.prepareColumns({columns});
1147
- this.setState({columns});
1146
+ this.setIsLoading(true,()=>{
1147
+ this.prepareColumns({columns});
1148
+ this.setState({columns});
1149
+ this.setIsLoading(false,false);
1150
+ })
1148
1151
  }
1149
1152
  /****le nombre maximum de courbes supportées */
1150
1153
  getMaxSeriesSize(){
@@ -1236,26 +1239,24 @@ export default class CommonDatagridComponent extends AppComponent {
1236
1239
  } else {
1237
1240
  sectionListColumns[columnName] = {field:columnName};
1238
1241
  }
1239
- setTimeout(() => {
1240
- const {sectionListColumns:pSListColumns} = this.prepareColumns({sectionListColumns});
1241
- this.setIsLoading(true,()=>{
1242
- this.prepareData({data:this.INITIAL_STATE.data,sectionListColumns:pSListColumns},(state)=>{
1243
- this.setState({...state,sectionListColumns:pSListColumns},()=>{
1244
- this.setIsLoading(false,false);
1245
- this.setSessionData("sectionListColumns",Object.keys(pSListColumns));
1246
- });
1242
+ const {sectionListColumns:pSListColumns} = this.prepareColumns({sectionListColumns});
1243
+ this.setIsLoading(true,()=>{
1244
+ this.prepareData({data:this.INITIAL_STATE.data,sectionListColumns:pSListColumns},(state)=>{
1245
+ this.setState({...state,sectionListColumns:pSListColumns},()=>{
1246
+ this.setIsLoading(false,false);
1247
+ this.setSessionData("sectionListColumns",Object.keys(pSListColumns));
1247
1248
  });
1248
- },true);
1249
- }, 100);
1249
+ });
1250
+ },true);
1250
1251
  }
1251
1252
  removeAllColumnsInSectionList(){
1252
1253
  const {sectionListColumns} = this.prepareColumns({sectionListColumns:{}});
1253
1254
  this.setIsLoading(true,()=>{
1254
1255
  this.prepareData({data:this.INITIAL_STATE.data,sectionListColumns},(state)=>{
1255
1256
  this.setState({...state,sectionListColumns,displayOnlySectionListHeaders:false},()=>{
1256
- this.setIsLoading(false,false);
1257
1257
  this.setSessionData("sectionListColumns",null);
1258
1258
  this.setSessionData("displayOnlySectionListHeaders",false);
1259
+ this.setIsLoading(false,false);
1259
1260
  });
1260
1261
  });
1261
1262
  },true);
@@ -1348,16 +1349,14 @@ export default class CommonDatagridComponent extends AppComponent {
1348
1349
  }
1349
1350
  toggleActiveAggregatorFunction(ag){
1350
1351
  if(!isValidAggregator(ag) || ag.code == this.state.aggregatorFunction) return null;
1351
- setTimeout(()=>{
1352
- this.setIsLoading(true,()=>{
1353
- this.prepareData({data:this.INITIAL_STATE.data,aggregatorFunction:ag.code},(state)=>{
1354
- this.setState(state,()=>{
1355
- this.setSessionData("aggregatorFunction",ag.code);
1356
- this.setIsLoading(false,false);
1357
- })
1352
+ this.setIsLoading(true,()=>{
1353
+ this.prepareData({data:this.INITIAL_STATE.data,aggregatorFunction:ag.code},(state)=>{
1354
+ this.setState(state,()=>{
1355
+ this.setSessionData("aggregatorFunction",ag.code);
1356
+ this.setIsLoading(false,false);
1358
1357
  })
1359
- },true);
1360
- },200);
1358
+ })
1359
+ },true);
1361
1360
  }
1362
1361
  renderAggregatorFunctionsMenu(){
1363
1362
  const m = this.getAggregatorFunctionsMenuItems(false,false);
@@ -1440,12 +1439,17 @@ export default class CommonDatagridComponent extends AppComponent {
1440
1439
  },
1441
1440
  dataLabels : {
1442
1441
  type : 'switch',
1443
- label : "Affich les valeurs",
1442
+ label : "Affich les etiquettes de valeurs",
1444
1443
  checkedTooltip : "Les étiquettes de valeurs seront affichées sur le graphe",
1445
1444
  checkedValue : true,
1446
1445
  uncheckedValue : false,
1447
1446
  defaultValue : this.isDashboard()? true : false,
1448
1447
  },
1448
+ abreviateValues : {
1449
+ type : "switch",
1450
+ label : "Abréger les valeurs numériques",
1451
+ defaultValue : true,
1452
+ },
1449
1453
  showXaxis : {
1450
1454
  type : "switch",
1451
1455
  text : "Afficher l'axe des X",
@@ -1864,6 +1868,8 @@ export default class CommonDatagridComponent extends AppComponent {
1864
1868
  chartProps[settingKey] = defaultObj(chartProps[settingKey]);
1865
1869
  chartProps[settingKey][key] = config[key];
1866
1870
  });
1871
+ const mappedColumns = {};
1872
+ const abreviateValues = defaultVal(config.abreviateValues,true);
1867
1873
  const dataLabelFormatter = typeof chartProps.dataLabels?.formatter =="function"? chartProps.dataLabels.formatter : undefined;
1868
1874
  const chartOptions = {
1869
1875
  ...chartProps,
@@ -1871,16 +1877,22 @@ export default class CommonDatagridComponent extends AppComponent {
1871
1877
  formatter : (value, { seriesIndex, dataPointIndex, w })=> {
1872
1878
  const serie = w.config.series[seriesIndex];
1873
1879
  const serieName = serie.name;
1874
- const column = isDonut ? defaultObj((this.state.columns[yAxisColumn.field],yAxisColumn)): defaultObj(this.chartSeriesNamesColumnsMapping[serieName]);
1880
+ const column = mappedColumns[seriesIndex] || isDonut ? defaultObj((this.state.columns[yAxisColumn.field],yAxisColumn)): defaultObj(this.chartSeriesNamesColumnsMapping[serieName]);
1881
+ if((column) && column.field){
1882
+ mappedColumns[seriesIndex] = column;
1883
+ }
1884
+ /*if(value>=660 && value < 661){
1885
+ console.log(value," will format ",column,seriesIndex,serieName)
1886
+ }*/
1875
1887
  const columnField = defaultStr(column.field, isDonut? config.y : undefined);
1876
1888
  if(dataLabelFormatter){
1877
1889
  return dataLabelFormatter({value,column,columnDef:column,columnField,serie,serieName,seriesIndex})
1878
1890
  }
1879
1891
  if(typeof value !=='number') return value;
1880
1892
  if(defaultStr(column.format).toLowerCase() ==='money'){
1881
- return value.formatMoney();
1893
+ return abreviateValues ? value.abreviate2FormatMoney() : value.formatMoney();
1882
1894
  }
1883
- return value.formatNumber();
1895
+ return abreviateValues ? value.abreviate() : value.formatNumber();
1884
1896
  }
1885
1897
  }),
1886
1898
  title :extendObj(true,{}, {
@@ -1940,13 +1952,10 @@ export default class CommonDatagridComponent extends AppComponent {
1940
1952
  }
1941
1953
  yLabels.formatter = (value)=>{
1942
1954
  if(typeof value !='number') return value;
1943
- if(yLabelFormat =='money' || (isDonut && yAxisColumn.format =="money")){
1944
- return value.formatMoney();
1945
- }
1946
- if(yLabelsColumn && yLabelsColumn.format =='money'){
1947
- return value.formatMoney();
1955
+ if((yLabelFormat =='money' || (isDonut && yAxisColumn.format =="money")) || (yLabelsColumn && yLabelsColumn.format =='money')){
1956
+ return abreviateValues ? value.abreviate2FormatMoney() : value.formatMoney();
1948
1957
  }
1949
- return value.formatNumber();
1958
+ return abreviateValues? value.abreviate() : value.formatNumber();
1950
1959
  }
1951
1960
  chartOptions.chart.id = this.chartIdPrefix+"-"+defaultStr(chartType.key,"no-key");
1952
1961
  if(!chartType.isDonut){
@@ -1991,8 +2000,11 @@ export default class CommonDatagridComponent extends AppComponent {
1991
2000
  const displayOnlySectionListHeaders = !!!this.state.displayOnlySectionListHeaders;
1992
2001
  this.setSessionData("displayOnlySectionListHeaders",displayOnlySectionListHeaders);
1993
2002
  if(!displayOnlySectionListHeaders){
1994
- return this.prepareData({data:this.INITIAL_STATE.data,displayOnlySectionListHeaders},(state)=>{
1995
- this.setState({...state,showFooters})
2003
+ return this.setIsLoading(true,()=>{
2004
+ this.prepareData({data:this.INITIAL_STATE.data,displayOnlySectionListHeaders},(state)=>{
2005
+ this.setState({...state,showFooters});
2006
+ this.setIsLoading(false,false);
2007
+ })
1996
2008
  })
1997
2009
  } else {
1998
2010
  this.setIsLoading(true,()=>{
@@ -2003,11 +2015,11 @@ export default class CommonDatagridComponent extends AppComponent {
2003
2015
  }
2004
2016
  });
2005
2017
  this.setState({data,displayOnlySectionListHeaders,showFooters},()=>{
2006
- this.setIsLoading(false),false;
2018
+ this.setIsLoading(false,false);
2007
2019
  });
2008
2020
  },true)
2009
2021
  }
2010
- },100);
2022
+ },0);
2011
2023
  }
2012
2024
  /*** permet d'effectuer le rendu des colonnes groupable dans le menu item */
2013
2025
  renderSectionListMenu(){
@@ -2892,15 +2904,17 @@ export default class CommonDatagridComponent extends AppComponent {
2892
2904
  if(typeof enablePointerEvents =='boolean'){
2893
2905
  this.enablePointerEventsRef.current = enablePointerEvents;
2894
2906
  }
2895
- if(this.canSetIsLoading() && typeof loading =='boolean'){
2896
- return this.progressBarRef.current.setIsLoading(loading,()=>{
2897
- if(typeof cb =='function'){
2898
- cb();
2899
- }
2900
- });
2901
- } else if(typeof cb =='function'){
2902
- cb();
2903
- }
2907
+ setTimeout(()=>{
2908
+ if(this.canSetIsLoading() && typeof loading =='boolean'){
2909
+ return this.progressBarRef.current.setIsLoading(loading,()=>{
2910
+ if(typeof cb =='function'){
2911
+ cb();
2912
+ }
2913
+ });
2914
+ } else if(typeof cb =='function'){
2915
+ cb();
2916
+ }
2917
+ },loading === false && enablePointerEvents === false ? 0 : 0);
2904
2918
  return false;
2905
2919
  }
2906
2920
  /**** met à jour l'état de progression de la mise à jour du tableau */
@@ -49,14 +49,26 @@ export const setSessionData = (key,value)=>{
49
49
 
50
50
 
51
51
 
52
- const timeout = 5000*60*60;
53
- export const swrOptions = {
54
- refreshInterval : timeout, //5 minutes
55
- shouldRetryOnError : false, //retry when fetcher has an error
56
- dedupingInterval : timeout,
57
- errorRetryInterval : timeout*2,
58
- errorRetryCount : 5,
52
+ export const timeout = 5000*60;//5 minutes
53
+ /***@see : https://swr.vercel.app/docs/api */
54
+
55
+ export const getSWROptions = ()=>{
56
+ const delay = defaultNumber(appConfig.get("swrRefreshTimeout"),timeout);
57
+ return {
58
+ dedupingInterval : delay,
59
+ errorRetryInterval : delay*2,
60
+ errorRetryCount : 5,
61
+ revalidateOnMount : false,//enable or disable automatic revalidation when component is mounted
62
+ revalidateOnFocus : true, //automatically revalidate when window gets focused (details)
63
+ revalidateOnReconnect : true, //automatically revalidate when the browser regains a network
64
+ refreshInterval : delay, //5 minutes : Disabled by default: refreshInterval = 0, If set to a number, polling interval in milliseconds, If set to a function, the function will receive the latest data and should return the interval in milliseconds
65
+ refreshWhenHidden : false, //polling when the window is invisible (if refreshInterval is enabled)
66
+ refreshWhenOffline : false, //polling when the browser is offline (determined by navigator.onLine)
67
+ shouldRetryOnError : false, //retry when fetcher has an error
68
+ dedupingInterval : delay,//dedupe requests with the same key in this time span in milliseconds
69
+ }
59
70
  }
71
+
60
72
  const getDefaultPaginationRowsPerPageItems = ()=>{
61
73
  return [5,10,15,20,25,30,40,50,60,80,100,500,1000,...(isDesktopMedia() ? [1500,2000,2500,3000,3500,4000,4500,5000,10000]:[])];
62
74
  }
@@ -158,11 +170,13 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
158
170
  const canHandleLimit = handleQueryLimit !== false ? true : false;
159
171
  const limitRef = React.useRef(!canHandleLimit ?0 : defaultNumber(getSessionData("limit"),500));
160
172
  const isInitializedRef = React.useRef(false);
161
- testID = defaultStr(testID,"RNSWRDatagridComponent")
162
- const {error, isValidating,isLoading,refresh} = useSWR(fetchPath,{
173
+ testID = defaultStr(testID,"RNSWRDatagridComponent");
174
+ const isLoadingRef = React.useRef(true);
175
+ const {error, isValidating,isLoading:customIsLoading,refresh} = useSWR(fetchPath,{
163
176
  fetcher : (url,opts)=>{
164
177
  if(!isInitializedRef.current) {
165
178
  isFetchingRef.current = false;
179
+ isLoadingRef.current = false;
166
180
  return;
167
181
  }
168
182
  opts = extendObj({},opts,fetchOptionsRef.current);
@@ -194,6 +208,7 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
194
208
  url = setQueryParams(url,opts.queryParams);
195
209
  return fetcher(url,opts).then(fetchCB).finally(()=>{
196
210
  isFetchingRef.current = false;
211
+ isLoadingRef.current = false;
197
212
  });
198
213
  }
199
214
  const {url:fUrl,fetcher:cFetcher,...rest} = getFetcherOptions(url,opts);
@@ -203,26 +218,25 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
203
218
  },
204
219
  showError : false,
205
220
  swrOptions : {
206
- ...swrOptions,
221
+ ...getSWROptions(),
207
222
  ...defaultObj(appConfig.swr),
208
223
  },
209
224
  });
225
+ const isLoading = isLoadingRef.current && customIsLoading || false;
210
226
  React.useEffect(()=>{
211
227
  innerRef.current && innerRef.current.setIsLoading && innerRef.current.setIsLoading(isLoading);
212
228
  },[isLoading])
213
229
  React.useEffect(()=>{
214
230
  const cb = refreshCBRef.current;
215
231
  refreshCBRef.current = null;
216
- if(!isValidating && !isLoading && typeof cb =='function'){
232
+ if(!isValidating && !customIsLoading && typeof cb =='function'){
217
233
  cb();
218
234
  }
219
- },[isValidating,isLoading])
235
+ },[isValidating,customIsLoading])
220
236
  const doRefresh = (showProgress)=>{
221
237
  showProgressRef.current = showProgress ? typeof showProgress ==='boolean' : false;
222
238
  if(isFetchingRef.current) return;
223
- refreshCBRef.current = ()=>{
224
- //showProgressRef.current = false;
225
- };
239
+ isLoadingRef.current = true;
226
240
  refresh();
227
241
  }
228
242
  const canPaginate = ()=>{
@@ -260,7 +274,7 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
260
274
  ///si le nombre total d'élements est inférieur au nombre limite alors le trie peut être fait localement
261
275
  return totalRef.current > limitRef.current && true || false;
262
276
  }
263
- const loading = (isLoading|| isValidating);
277
+ const loading = (isLoadingRef.current && (isLoading|| isValidating));
264
278
  const pointerEvents = loading ?"node" : "auto";
265
279
  const itLimits = [{
266
280
  text : "Limite nbre elts par page",
@@ -20,28 +20,36 @@ import appConfig from "$appConfig";
20
20
  * foreignKeyLabel : Le libélé dans la table étrangère
21
21
  */
22
22
  const TableDataSelectField = React.forwardRef((_props,ref)=>{
23
- let {foreignKeyColumn,foreignKeyTable,foreignKeyLabel,dropdownActions,fields,fetchItems:customFetchItem,convertFiltersToSQL,mutateFetchedItems,getForeignKeyTable,onFetchItems,isFilter,isUpdate,isDocEditing,items,onAddProps,fetchDataOpts,...props} = _props;
23
+ let {foreignKeyColumn,foreignKeyTable,fetchItemsPath,foreignKeyLabel,dropdownActions,fields,fetchItems:customFetchItem,convertFiltersToSQL,mutateFetchedItems,getForeignKeyTable,onFetchItems,isFilter,isUpdate,isDocEditing,items,onAddProps,fetchDataOpts,...props} = _props;
24
24
  props = defaultObj(props);
25
25
  props.data = defaultObj(props.data);
26
26
  foreignKeyColumn = foreignKeyColumn.trim();
27
27
  convertFiltersToSQL = defaultVal(convertFiltersToSQL,willConvertFiltersToSQL());
28
28
  getForeignKeyTable = getForeignKeyTable || appConfig.getDatabaseTableData;
29
- const fKeyTable = typeof getForeignKeyTable =='function' ? getForeignKeyTable(foreignKeyTable,props) : undefined
30
- if(!isObj(fKeyTable) || !(defaultStr(fKeyTable.tableName,fKeyTable.table))){
29
+ let fKeyTable = typeof getForeignKeyTable =='function' ? getForeignKeyTable(foreignKeyTable,props) : undefined;
30
+ fetchItemsPath = defaultStr(fetchItemsPath).trim();
31
+ if(!fetchItemsPath && (!isObj(fKeyTable) || !(defaultStr(fKeyTable.tableName,fKeyTable.table)))){
31
32
  console.error("type de données invalide pour la fKeyTable ",fKeyTable," composant SelectTableData",_props);
32
33
  return null;
33
34
  }
35
+ fKeyTable = defaultObj(fKeyTable);
34
36
  foreignKeyTable = defaultStr(fKeyTable.tableName,fKeyTable.table,foreignKeyTable).trim().toUpperCase();
35
37
  const isMounted = React.useIsMounted();
36
- const showAdd = isFilter ? false : React.useRef(Auth.isTableDataAllowed({foreignKeyTable,action:'create'}) ? defaultVal(props.showAdd,props.showAddBtn,true) : false).current;
38
+ const showAdd = isFilter || !foreignKeyTable ? false : React.useRef(Auth.isTableDataAllowed({foreignKeyTable,action:'create'}) ? defaultVal(props.showAdd,props.showAddBtn,true) : false).current;
37
39
  const [state,setState] = React.useState({
38
40
  items : [],isLoading : true,
39
41
  });
40
42
  fetchDataOpts = Object.clone(defaultObj(fetchDataOpts));
41
- const fetchItems = typeof customFetchItem =='function' ? customFetchItem : typeof fKeyTable.queryPath =='string' ? (opts)=>{
42
- return fetch(fKeyTable.queryPath,opts);
43
- } : undefined;
44
- isUpdate = defaultBool(isUpdate,typeof isDocEditing ==='function' && isDocEditing({data:props.data,fKeyTable,foreignKeyTable}));
43
+ const queryPath = fetchItemsPath || typeof fKeyTable.queryPath =='string' && fKeyTable.queryPath || typeof fKeyTable.fetchPath =='string' && fKeyTable.fetchPath || '';
44
+ const cFetch = typeof customFetchItem =='function' && customFetchItem;
45
+ const fetchItems = (opts)=>{
46
+ opts.showError = false;
47
+ if(cFetch) return cFetch(queryPath,opts);
48
+ if(queryPath){
49
+ return fetch(queryPath,opts);
50
+ }
51
+ };
52
+ isUpdate = defaultBool(isUpdate,typeof isDocEditing ==='function' && isDocEditing({data:props.data,foreignKeyTable,foreignKeyColumn}));
45
53
  if(isFilter){
46
54
  isUpdate = false;
47
55
  }
@@ -98,13 +106,16 @@ const TableDataSelectField = React.forwardRef((_props,ref)=>{
98
106
  let opts = Object.clone(fetchDataOpts);
99
107
  opts.selector = prepareFilters(fetchDataOpts.selector,{convertToSQL:convertFiltersToSQL});
100
108
  opts = getFetchOptions(opts);
101
- const r = fetchItems && fetchItems(opts);
109
+ const r = fetchItems(opts);
102
110
  if(r === false) return;
103
111
  if(isPromise(r)){
104
112
  r.then((args)=>{
105
113
  if(Array.isArray(args)){
106
114
  args = {data : args};
107
115
  }
116
+ if(!isObj(args)) {
117
+ args = {items:[]}
118
+ }
108
119
  let items = args.items = args.data = Array.isArray(args.items) ? args.items : Array.isArray(args.data) ? args.data : [];
109
120
  if(dat && isUpdate){
110
121
  if(isFunction(mutateFetchedItems)){
@@ -177,7 +188,6 @@ const TableDataSelectField = React.forwardRef((_props,ref)=>{
177
188
  {...props}
178
189
  isFilter = {isFilter}
179
190
  showAdd = {!isFilter && showAdd}
180
- {...React.setProps(Dropdown,fKeyTable,{})}
181
191
  {...state}
182
192
  dialogProps = {dialogProps}
183
193
  ref = {ref}
@@ -220,14 +230,15 @@ TableDataSelectField.propTypes = {
220
230
  ...Dropdown.propTypes,
221
231
  mutateFetchedItems : PropTypes.func, //la fonction permettant d'effectuer une mutation sur l'ensemble des donnéees récupérées à distance
222
232
  fetchItems : PropTypes.func,//la fonction de rappel à utiliser pour faire une requête fetch permettant de selectionner les données à distance
233
+ getForeignKeyTable : PropTypes.func, //la fonction permettant de récupérer la fKeyTable data dont fait référence le champ
234
+ foreignKeyTable : PropTypes.string, //le nom de la fKeyTable data à laquelle se reporte le champ
235
+ fetchItemsPath : PropTypes.string, //le chemin d'api pour récupérer les items des données étrangères en utilisant la fonction fetch
223
236
  beforeFetchItems : PropTypes.func, //appelée immédiatement avant l'exécution de la requête fetch
224
237
  foreignKeyColumn : PropTypes.string.isRequired,//le nom de la clé étrangère à laquelle fait référence la colone dans la fKeyTable
225
238
  foreignKeyLabel : PropTypes.oneOfType([
226
239
  PropTypes.string,
227
240
  PropTypes.func, //s'il s'agit d'une fonciton qui sera appelée
228
241
  ]),
229
- getForeignKeyTable : PropTypes.func, //la fonction permettant de récupérer la fKeyTable data dont fait référence le champ
230
- foreignKeyTable : PropTypes.string, //le nom de la fKeyTable data à laquelle se reporte le champ
231
242
  onFetchItems : PropTypes.func,
232
243
  fetchDataOpts : PropTypes.shape({
233
244
  fields : PropTypes.oneOfType([
@@ -108,6 +108,7 @@ export const getFilterComponentProps = (_props)=>{
108
108
  component = componentTypes[type.replaceAll("_","")];
109
109
  } else if(isNonNullString(props.foreignKeyColumn) && isNonNullString(props.foreignKeyTable)) {
110
110
  component = Fields.SelectTableData;
111
+ props.multiple = true;
111
112
  }else {
112
113
  const tt = type.replaceAll("_","").toLowerCase();
113
114
  if(React.isComponent(componentTypes[tt])){
@@ -4,6 +4,7 @@ import { ScrollView,Dimensions,useWindowDimensions } from 'react-native';
4
4
  import PropTypes from "prop-types";
5
5
  import View from "$ecomponents/View";
6
6
  import {isMobileNative,isTouchDevice} from "$cplatform";
7
+ import {isDesktopMedia} from "$cdimensions";
7
8
  import {defaultStr,defaultObj} from "$utils";
8
9
  const isNative = isMobileNative();
9
10
  import APP from "$capp/instance";
@@ -25,9 +26,11 @@ const ScrollViewComponent = React.forwardRef((props,ref) => {
25
26
  APP.off(APP.EVENTS.RESIZE_PAGE,onResizePage);
26
27
  }
27
28
  },[])
29
+ const showIndicator = !isTouchDevice() || isDesktopMedia();
28
30
  return virtualized ? <FlatList
31
+ showsHorizontalScrollIndicator = {showIndicator}
32
+ showsVerticalScrollIndicator={showIndicator}
29
33
  {...rest}
30
- showsHorizontalScrollIndicator = {!isTouchDevice()} showsVerticalScrollIndicator={!isTouchDevice()}
31
34
  ref = {ref}
32
35
  testID = {testID}
33
36
  data={[]}
@@ -37,7 +40,8 @@ const ScrollViewComponent = React.forwardRef((props,ref) => {
37
40
  contentContainerStyle = {[!isNative && {flex:1,flexGrow: 1,maxHeight:Math.max(height-100,250)},rest.contentContainerStyle]}
38
41
  ListHeaderComponent={() => <View testID={testID+'_FlatListContent'} {...cProps} mediaQueryUpdateNativeProps = {mediaQueryUpdateNativeProps}
39
42
  >{children}</View>}
40
- /> : <ScrollView showsHorizontalScrollIndicator = {!isTouchDevice()} showsVerticalScrollIndicator={!isTouchDevice()} ref={ref} {...rest} testID={testID} children={children}/>
43
+ /> : <ScrollView showsHorizontalScrollIndicator = {showIndicator}
44
+ showsVerticalScrollIndicator={showIndicator} ref={ref} {...rest} testID={testID} children={children}/>
41
45
  });
42
46
 
43
47
  ScrollViewComponent.displayName = "ScrollViewComponent";