@fto-consult/expo-ui 2.13.2 → 2.14.1
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/package.json +1 -1
- package/src/components/Countries/Flag.js +1 -0
- package/src/components/Countries/SelectCountry.js +1 -1
- package/src/components/Datagrid/Accordion/index.js +5 -0
- package/src/components/Datagrid/Common/Common.js +92 -33
- package/src/components/Datagrid/Common/TableData.js +3 -3
- package/src/components/Datagrid/SWRDatagrid.js +204 -2
- package/src/components/Datagrid/Table/index.js +20 -19
- package/src/components/TableLink/index.js +36 -12
- package/src/layouts/DatabaseStatistics/DatabaseStatistic.js +6 -13
- package/src/layouts/Screen/TableData.js +42 -13
package/package.json
CHANGED
|
@@ -27,7 +27,7 @@ export const getCountryFieldProps = (props)=>{
|
|
|
27
27
|
},
|
|
28
28
|
renderItem : ({item})=>{
|
|
29
29
|
return <View style={[styles.renderedImage]}>
|
|
30
|
-
{(isNonNullString(item.image) || isNumber(item.image)) && <Image accessibilityIgnoresInvertColors {...imageProps} style={[styles.flagImage,{marginRight:10},imageProps.style]} source={isNumber(item.image)?item.image:{uri:item.image}}/>}
|
|
30
|
+
{(isNonNullString(item.image) || isNumber(item.image)) && <Image editable = {false} accessibilityIgnoresInvertColors {...imageProps} style={[styles.flagImage,{marginRight:10},imageProps.style]} source={isNumber(item.image)?item.image:{uri:item.image}}/>}
|
|
31
31
|
<Label>{item.label}</Label>
|
|
32
32
|
</View>
|
|
33
33
|
},
|
|
@@ -308,6 +308,7 @@ const DatagridFactory = (Factory)=>{
|
|
|
308
308
|
filter,
|
|
309
309
|
actions,
|
|
310
310
|
sortable,
|
|
311
|
+
autoSort,
|
|
311
312
|
exportable,
|
|
312
313
|
filterOrOperator,
|
|
313
314
|
filterAndOperator,
|
|
@@ -325,6 +326,7 @@ const DatagridFactory = (Factory)=>{
|
|
|
325
326
|
backToTopProps,
|
|
326
327
|
testID,
|
|
327
328
|
renderEmpty,
|
|
329
|
+
...rest
|
|
328
330
|
} = this.props
|
|
329
331
|
const hasData = this.state.data.length ? true : false;
|
|
330
332
|
testID = defaultStr(testID,"RN_DatagridAccordion");
|
|
@@ -433,6 +435,7 @@ const DatagridFactory = (Factory)=>{
|
|
|
433
435
|
<View testID={testID+"_HeaderQueryLimit"} style={[styles.paginationItem]}>
|
|
434
436
|
{this.renderQueryLimit(this.state.data.length.formatNumber())}
|
|
435
437
|
</View>
|
|
438
|
+
{this.renderCustomPagination()}
|
|
436
439
|
{sortedColumnsLength ? <View testID={testID+"_HeaderSortedColumns"} style={[styles.sortableItems,styles.paginationItem,{paddingRight:10}]}>
|
|
437
440
|
<Icon
|
|
438
441
|
testID={testID+"_HeaderSortIcon"}
|
|
@@ -503,6 +506,7 @@ const DatagridFactory = (Factory)=>{
|
|
|
503
506
|
,icon : showFooters?'view-column':'view-module'
|
|
504
507
|
,text : (showFooters?'Masquer/Ligne des totaux':'Afficher/Ligne des totaux')
|
|
505
508
|
}:null,
|
|
509
|
+
...this.renderCustomMenu(),
|
|
506
510
|
...restItems,
|
|
507
511
|
this.canScrollTo() && {
|
|
508
512
|
text : 'Retour en haut',
|
|
@@ -579,6 +583,7 @@ const DatagridFactory = (Factory)=>{
|
|
|
579
583
|
{hasData ? <FlashList
|
|
580
584
|
estimatedItemSize = {150}
|
|
581
585
|
prepareItems = {false}
|
|
586
|
+
{...rest}
|
|
582
587
|
{...accordionProps}
|
|
583
588
|
testID = {testID}
|
|
584
589
|
extraData = {this.state.refresh}
|
|
@@ -78,7 +78,6 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
78
78
|
sData.fixedTable = defaultBool(sData.fixedTable,false);
|
|
79
79
|
extendObj(this.state, {
|
|
80
80
|
data,
|
|
81
|
-
sort :defaultObj(props.sort),
|
|
82
81
|
showFilters : defaultBool(props.showFilters,(sData.showFilter? true : this.isPivotDatagrid())),
|
|
83
82
|
showFooters : defaultBool(props.showFooters,(sData.showFooters? true : false)),
|
|
84
83
|
fixedTable : sData.fixedTable
|
|
@@ -87,6 +86,9 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
87
86
|
layoutRef : {
|
|
88
87
|
value : React.createRef(null),
|
|
89
88
|
},
|
|
89
|
+
sortRef : {
|
|
90
|
+
value : {current : defaultObj(props.sort)}
|
|
91
|
+
},
|
|
90
92
|
preparedColumns : {
|
|
91
93
|
value : {},override:false, writable:false,
|
|
92
94
|
},
|
|
@@ -109,17 +111,15 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
109
111
|
})
|
|
110
112
|
this.isLoading = this.isLoading.bind(this);
|
|
111
113
|
this.getProgressBar = this.getProgressBar.bind(this);
|
|
112
|
-
this.
|
|
114
|
+
this.sortRef.current.dir = defaultStr(this.sortRef.current.dir,this.sortRef.current.column == "date"?"desc":'asc')
|
|
113
115
|
this.hasColumnsHalreadyInitialized = false;
|
|
114
116
|
this.initColumns(props.columns);
|
|
115
|
-
if(!isNonNullString(this.
|
|
116
|
-
this.
|
|
117
|
+
if(!isNonNullString(this.sortRef.current.column) && "date" in this.state.columns){
|
|
118
|
+
this.sortRef.current.column = "date";
|
|
117
119
|
}
|
|
118
120
|
this.INITIAL_STATE = {
|
|
119
121
|
data,
|
|
120
|
-
sort : this.state.sort
|
|
121
122
|
}
|
|
122
|
-
this._sort = this.state.sort;
|
|
123
123
|
this._datagridId = isNonNullString(this.props.id)? this.props.id : uniqid("datagrid-id")
|
|
124
124
|
this.canDoFilter = true;
|
|
125
125
|
this.filters = {}
|
|
@@ -308,7 +308,8 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
308
308
|
return ;
|
|
309
309
|
}
|
|
310
310
|
canPaginateData(){
|
|
311
|
-
return false;
|
|
311
|
+
if(this.props.handlePagination === false) return false;
|
|
312
|
+
return this.isDatagrid();
|
|
312
313
|
}
|
|
313
314
|
getFiltersProps(){
|
|
314
315
|
return this.props.filters;
|
|
@@ -688,11 +689,11 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
688
689
|
}
|
|
689
690
|
*/
|
|
690
691
|
sort (column,dir){
|
|
691
|
-
|
|
692
|
+
const sort = extendObj({},{
|
|
692
693
|
dir: '',
|
|
693
694
|
column : '',
|
|
694
695
|
ignoreCase : true
|
|
695
|
-
}, this.
|
|
696
|
+
}, this.sortRef.current);
|
|
696
697
|
if(isNonNullString(column)){
|
|
697
698
|
sort.column = column;
|
|
698
699
|
}
|
|
@@ -702,8 +703,8 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
702
703
|
if(isNonNullString(dir)){
|
|
703
704
|
sort.dir = dir;
|
|
704
705
|
}
|
|
705
|
-
if(this.
|
|
706
|
-
switch(this.
|
|
706
|
+
if(this.sortRef.current.column === sort.column){
|
|
707
|
+
switch(this.sortRef.current.dir){
|
|
707
708
|
case 'asc':
|
|
708
709
|
sort.dir = 'desc';
|
|
709
710
|
break;
|
|
@@ -719,9 +720,12 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
719
720
|
sort.dir = sort.dir.trim().toLowerCase();
|
|
720
721
|
}
|
|
721
722
|
if(sort.dir !== "asc" && sort.dir !== "desc") sort.dir = 'asc';
|
|
722
|
-
this._previousSortObj = this.
|
|
723
|
-
this.
|
|
724
|
-
this.prepareColumns({sortedColumn : this.
|
|
723
|
+
this._previousSortObj = Object.clone(this.sortRef.current);
|
|
724
|
+
this.sortRef.current = sort;
|
|
725
|
+
this.prepareColumns({sortedColumn : this.sortRef.current});
|
|
726
|
+
if(typeof this.props.onSort =='function' && this.props.onSort({...sort,context:this,sort,data:this.INITIAL_STATE.data,fields:this.state.columns,columns:this.state.columns}) === false){
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
725
729
|
this.prepareData({data:this.state.data,updateFooters:false},(state)=>{
|
|
726
730
|
this.setState(state);
|
|
727
731
|
});
|
|
@@ -752,7 +756,41 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
752
756
|
}
|
|
753
757
|
this.handlePagination(newStart, limit, nextPage);
|
|
754
758
|
}
|
|
755
|
-
|
|
759
|
+
/*** pour le rendu personalisé de la pagination */
|
|
760
|
+
renderCustomPagination(){
|
|
761
|
+
if(typeof this.props.renderCustomPagination ==='function'){
|
|
762
|
+
const r = this.props.renderCustomPagination({
|
|
763
|
+
context:this,refresh:this.refresh.bind(this)
|
|
764
|
+
});
|
|
765
|
+
return React.isValidElement(r)? r : null;
|
|
766
|
+
}
|
|
767
|
+
return null;
|
|
768
|
+
}
|
|
769
|
+
/*** permet de faire le rendu de certaines entête personalisés
|
|
770
|
+
* utile lorsque l'on veut par exemple afficher d'autres information au niveau de l'entête du tableau
|
|
771
|
+
*/
|
|
772
|
+
renderCustomMenu(){
|
|
773
|
+
const customMenu = []
|
|
774
|
+
Object.map(this.props.customMenu,(menu,i)=>{
|
|
775
|
+
if(isObj(menu)){
|
|
776
|
+
const {onPress,menu,label,text,children,...rest} = menu;
|
|
777
|
+
const args = {context:this,refresh:this.refresh.bind(this)};
|
|
778
|
+
const lCB = defaultVal(children,label,text);
|
|
779
|
+
const labelText = typeof lCB ==='function'? lCB(args) : lCB;
|
|
780
|
+
if(labelText === false || !React.isValidElement(labelText,true)) return;
|
|
781
|
+
customMenu.push({
|
|
782
|
+
...rest,
|
|
783
|
+
label : labelText,
|
|
784
|
+
onPress : (event)=>{
|
|
785
|
+
if(typeof onPress =='function'){
|
|
786
|
+
return onPress({...React.getOnPressArgs(event),...args})
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
})
|
|
790
|
+
}
|
|
791
|
+
});
|
|
792
|
+
return customMenu;
|
|
793
|
+
}
|
|
756
794
|
/*** aller à la dernière page */
|
|
757
795
|
_goToLastPage(){
|
|
758
796
|
let { start,limit} = this._pagination;
|
|
@@ -913,7 +951,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
913
951
|
args = defaultObj(args);
|
|
914
952
|
const filteredColumns = isObjOrArray(args.filteredColumns)?args.filteredColumns : isObjOrArray(this.state.filteredColumns) ? this.state.filteredColumns : {};
|
|
915
953
|
const columns = args.columns || this.state.columns;
|
|
916
|
-
const currentSortedColumn = isObj(args.sortedColumn) && args.sortedColumn.column? args.sortedColumn : defaultObj(this.
|
|
954
|
+
const currentSortedColumn = isObj(args.sortedColumn) && args.sortedColumn.column? args.sortedColumn : defaultObj(this.sortRef.current);
|
|
917
955
|
const visibleColumns = [],headerFilters = [],visibleColumnsNames={};
|
|
918
956
|
const sortable = defaultBool(this.props.sortable,true);
|
|
919
957
|
const sortedColumns = {};
|
|
@@ -1072,7 +1110,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1072
1110
|
}
|
|
1073
1111
|
getPaginatedSelectedRows(data){
|
|
1074
1112
|
data = isArray(data)? data : this.INITIAL_STATE.data;
|
|
1075
|
-
if(JSON.stringify(this._previousSortObj) !== JSON.stringify(this.
|
|
1113
|
+
if(JSON.stringify(this._previousSortObj) !== JSON.stringify(this.sortRef.current) || JSON.stringify(this._previousPagination) !== JSON.stringify(this._pagination) && this.getPaginatedData().length !== data.length){
|
|
1076
1114
|
return {};
|
|
1077
1115
|
}
|
|
1078
1116
|
return this.selectedRows;
|
|
@@ -1107,10 +1145,10 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1107
1145
|
});
|
|
1108
1146
|
data = newData;
|
|
1109
1147
|
}
|
|
1110
|
-
if(this.
|
|
1111
|
-
if(isObj(this.state.columns) && this.state.columns[this.
|
|
1112
|
-
let field = this.state.columns[this.
|
|
1113
|
-
const cfg = Object.assign({},this.
|
|
1148
|
+
if(this.canAutoSort() && isNonNullString(this.sortRef.current.column)){
|
|
1149
|
+
if(isObj(this.state.columns) && this.state.columns[this.sortRef.current.column]){
|
|
1150
|
+
let field = this.state.columns[this.sortRef.current.column];
|
|
1151
|
+
const cfg = Object.assign({},this.sortRef.current);
|
|
1114
1152
|
cfg.getItem = (item,columnName,{getItem})=>{
|
|
1115
1153
|
if(isObj(item) && (field.type =='decimal' || field.type =="number")){
|
|
1116
1154
|
const v = item[columnName];
|
|
@@ -1131,7 +1169,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1131
1169
|
} else if(force){
|
|
1132
1170
|
this.setSelectedRows();
|
|
1133
1171
|
}
|
|
1134
|
-
const state = {data
|
|
1172
|
+
const state = {data};
|
|
1135
1173
|
if((cb)){
|
|
1136
1174
|
cb(state);
|
|
1137
1175
|
}
|
|
@@ -1320,7 +1358,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1320
1358
|
this._pagination.start = 0;
|
|
1321
1359
|
}
|
|
1322
1360
|
this.filtersSelectors = {selector:this.getFilters()};
|
|
1323
|
-
return this.fetchData({force:true,fetchOptions:this.filtersSelectors});
|
|
1361
|
+
return this.fetchData({force:true,isFiltering : true,fetchOptions:this.filtersSelectors});
|
|
1324
1362
|
}
|
|
1325
1363
|
onSetQueryLimit(){
|
|
1326
1364
|
if(!this.canSetQueryLimit()) return;
|
|
@@ -1334,7 +1372,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1334
1372
|
this.currentDatagridQueryLimit = this.getSessionData("dataSourceQueryLimit");
|
|
1335
1373
|
setQueryLimit(this.currentDatagridQueryLimit,(limit)=>{
|
|
1336
1374
|
this.setSessionData("dataSourceQueryLimit",limit)
|
|
1337
|
-
notify.success("Le nombre maximal d'élément a été définit à la valeur "+(limit==0?" infinit ":limit.formatNumber())+". Cette valeur sera prise en compte à la prochaine réactualisation du tableau")
|
|
1375
|
+
notify.success("Le nombre maximal d'élément à récuperer par page a été définit à la valeur "+(limit==0?" infinit ":limit.formatNumber())+". Cette valeur sera prise en compte à la prochaine réactualisation du tableau")
|
|
1338
1376
|
});
|
|
1339
1377
|
}
|
|
1340
1378
|
|
|
@@ -1348,6 +1386,9 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1348
1386
|
return 0;
|
|
1349
1387
|
}
|
|
1350
1388
|
canHandleQueryLimit(){
|
|
1389
|
+
if(typeof this.props.handleQueryLimit ==='boolean'){
|
|
1390
|
+
return this.props.handleQueryLimit;
|
|
1391
|
+
}
|
|
1351
1392
|
return true;
|
|
1352
1393
|
}
|
|
1353
1394
|
renderQueryLimit(content){
|
|
@@ -1357,7 +1398,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1357
1398
|
let s = "";
|
|
1358
1399
|
let canSetQ = this.canSetQueryLimit();
|
|
1359
1400
|
if(canSetQ){
|
|
1360
|
-
s = ".\nPressez pendent quelques secondes pour modifier cette valeur du nombre limite d'éléments de la liste";
|
|
1401
|
+
s = ".\nPressez pendent quelques secondes pour modifier cette valeur du nombre limite d'éléments de la liste par page";
|
|
1361
1402
|
}
|
|
1362
1403
|
else if(isDecimal(cLImit)){
|
|
1363
1404
|
cLImit = (" de "+cLImit.formatNumber())
|
|
@@ -1533,9 +1574,19 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1533
1574
|
getLinesProgressBar(){
|
|
1534
1575
|
return CommonDatagridComponent.LinesProgressBar(this.props);
|
|
1535
1576
|
}
|
|
1577
|
+
/*** si le datagrid sera sortable */
|
|
1578
|
+
isSortable(){
|
|
1579
|
+
return this.isDatagrid() && this.props.sortable !== false? true : false;
|
|
1580
|
+
}
|
|
1581
|
+
canAutoSort(){
|
|
1582
|
+
return this.isSortable() && this.props.autoSort !==false ? true : false;
|
|
1583
|
+
}
|
|
1536
1584
|
isSelectableMultiple(){
|
|
1537
1585
|
return defaultBool(this.props.selectableMultiple,true)
|
|
1538
1586
|
}
|
|
1587
|
+
getSort(){
|
|
1588
|
+
return defaultObj(this.sortRef.current);
|
|
1589
|
+
}
|
|
1539
1590
|
renderHeaderCell({columnDef,columnField}){
|
|
1540
1591
|
if(this.isSelectableColumn(columnDef,columnField)){
|
|
1541
1592
|
return <Checkbox
|
|
@@ -1666,16 +1717,16 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1666
1717
|
else if(_type =='select_country' || _type =='selectcountry'){
|
|
1667
1718
|
_render = <Flag withCode {...columnDef} length={undefined} width={undefined} height={undefined} code={defaultValue}/>
|
|
1668
1719
|
}
|
|
1669
|
-
///le lien vers le table data se fait via
|
|
1670
|
-
else if(arrayValueExists(['
|
|
1671
|
-
let tableName = defaultStr(columnDef.linkToTable && columnDef.linkToTable,columnDef.foreignKeyTable && columnDef.foreignKeyTable,columnDef.tableName,columnDef.table).toUpperCase();
|
|
1720
|
+
///le lien vers le table data se fait via la colonne ayant la propriété foreignKeyTable de type chaine de caractère non nulle
|
|
1721
|
+
else if(isNonNullString(columnDef.foreignKeyTable) || columnDef.primaryKey === true || arrayValueExists(['id','piece'],_type)){
|
|
1672
1722
|
const id = rowData[columnField]?.toString();
|
|
1673
1723
|
if(isNonNullString(id)){
|
|
1674
1724
|
_render = <TableLink
|
|
1675
|
-
tableName = {tableName}
|
|
1676
1725
|
id = {id}
|
|
1726
|
+
foreignKeyTable = {defaultStr(columnDef.foreignKeyTable,columnDef.table,columnDef.tableName)}
|
|
1727
|
+
foreignKeyColumn = {defaultStr(columnDef.foreignKeyColumn,columnDef.field)}
|
|
1728
|
+
{...columnDef}
|
|
1677
1729
|
data = {rowData}
|
|
1678
|
-
columnDef = {columnDef}
|
|
1679
1730
|
columnField = {columnField}
|
|
1680
1731
|
>
|
|
1681
1732
|
{rowData[columnField]}
|
|
@@ -1770,9 +1821,9 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1770
1821
|
let fmat = defaultStr(columnDef.format).toLowerCase();
|
|
1771
1822
|
if(fmat == "money"){
|
|
1772
1823
|
_render = _render.formatMoney();
|
|
1773
|
-
} else if(fmat =="number") {
|
|
1824
|
+
} else //if(fmat =="number") {
|
|
1774
1825
|
_render = _render.formatNumber();
|
|
1775
|
-
}
|
|
1826
|
+
//}
|
|
1776
1827
|
}
|
|
1777
1828
|
if(_render && isObj(renderProps)){
|
|
1778
1829
|
let Component = defaultVal(renderProps.Component,Label);
|
|
@@ -1782,7 +1833,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1782
1833
|
if(typeof _render =='boolean'){
|
|
1783
1834
|
_render = _render ? "Oui" : "Non";
|
|
1784
1835
|
}
|
|
1785
|
-
if(typeof _render ==='string' || typeof _render =='
|
|
1836
|
+
if(typeof _render ==='string' || typeof _render =='number'){
|
|
1786
1837
|
_render = <Label selectable>{_render}</Label>
|
|
1787
1838
|
}
|
|
1788
1839
|
_render = React.isValidElement(_render)|| Array.isArray(_render)?_render:null;
|
|
@@ -1950,6 +2001,14 @@ CommonDatagridComponent.propTypes = {
|
|
|
1950
2001
|
/*** pour le rendu du footer, pied de page en affichage accordion */
|
|
1951
2002
|
sessionName : PropTypes.string,
|
|
1952
2003
|
onFetchData : PropTypes.func,
|
|
2004
|
+
handleQueryLimit : PropTypes.bool, ///si le datagrid devra gérer les queryLimit
|
|
2005
|
+
/**** les menus customisés à ajouter au composant Datagrid */
|
|
2006
|
+
customMenu : PropTypes.oneOfType([
|
|
2007
|
+
PropTypes.arrayOf(PropTypes.object),
|
|
2008
|
+
PropTypes.objectOf(PropTypes.object),
|
|
2009
|
+
]),
|
|
2010
|
+
/**** la fonction permettant de faire le rendu dun contenu paginé, personalisé */
|
|
2011
|
+
renderCustomPagination : PropTypes.func,
|
|
1953
2012
|
getActionsArgs : PropTypes.func,//fonction permettant de récupérer les props supplémentaires à passer aux actions du datagrid
|
|
1954
2013
|
}
|
|
1955
2014
|
|
|
@@ -60,7 +60,7 @@ export default class CommonTableDatagrid extends CommonDatagrid{
|
|
|
60
60
|
la table dans la base common.
|
|
61
61
|
Elle pourra éventuellement passer directement la limite et les filtres à la fonction fetchdata
|
|
62
62
|
*/
|
|
63
|
-
fetchData ({cb,callback,force,fetchOptions}){
|
|
63
|
+
fetchData ({cb,callback,force,fetchOptions,...rest}){
|
|
64
64
|
if(!this._isMounted()) return Promise.resolve(this.state.data);
|
|
65
65
|
if(this.isFetchingData) {
|
|
66
66
|
if(!isPromise(this.fetchingPromiseData)){
|
|
@@ -82,7 +82,7 @@ export default class CommonTableDatagrid extends CommonDatagrid{
|
|
|
82
82
|
fetchOptions.dataSources = this.currentDataSources;
|
|
83
83
|
fetchOptions = extendObj(true,true,{},fetchOptions,{selector : fetchFilters});
|
|
84
84
|
fetchOptions.dataSources = this.currentDataSources;
|
|
85
|
-
fetchOptions.sort = this.
|
|
85
|
+
fetchOptions.sort = this.getSort();
|
|
86
86
|
let limit = this.getQueryLimit();
|
|
87
87
|
if(limit > 0 && !this.isPivotDatagrid()){
|
|
88
88
|
fetchOptions.limit = limit;
|
|
@@ -92,7 +92,7 @@ export default class CommonTableDatagrid extends CommonDatagrid{
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
this.beforeFetchData(fetchOptions);
|
|
95
|
-
if(typeof this.props.beforeFetchData =='function' && this.props.beforeFetchData({context:this,force,fetchOptions,options:fetchOptions}) === false){
|
|
95
|
+
if(typeof this.props.beforeFetchData =='function' && this.props.beforeFetchData({...rest,context:this,force,fetchOptions,options:fetchOptions}) === false){
|
|
96
96
|
this.isFetchingData = false;
|
|
97
97
|
return resolve(this.state.data);
|
|
98
98
|
}
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import Datagrid from "./IndexComponent";
|
|
9
9
|
import {defaultStr,defaultObj,defaultVal,isObjOrArray,isObj,extendObj} from "$utils";
|
|
10
|
+
import {Pressable} from "react-native";
|
|
11
|
+
import SimpleSelect from "$ecomponents/SimpleSelect";
|
|
10
12
|
import React from "$react";
|
|
11
13
|
import Auth from "$cauth";
|
|
12
14
|
import DateLib from "$lib/date";
|
|
@@ -22,6 +24,9 @@ import appConfig from "$capp/config";
|
|
|
22
24
|
import APP from "$capp/instance";
|
|
23
25
|
import cAction from "$cactions";
|
|
24
26
|
import PropTypes from "prop-types";
|
|
27
|
+
import {isDesktopMedia} from "$dimensions";
|
|
28
|
+
import ActivityIndicator from "$ecomponents/ActivityIndicator";
|
|
29
|
+
import {Menu} from "$ecomponents/BottomSheet";
|
|
25
30
|
|
|
26
31
|
const timeout = 5000*60*60;
|
|
27
32
|
export const swrOptions = {
|
|
@@ -31,7 +36,9 @@ export const swrOptions = {
|
|
|
31
36
|
errorRetryInterval : timeout*2,
|
|
32
37
|
errorRetryCount : 5,
|
|
33
38
|
}
|
|
34
|
-
|
|
39
|
+
const getDefaultPaginationRowsPerPageItems = ()=>{
|
|
40
|
+
return [5,10,15,20,25,30,40,50,60,80,100,500,1000,...(isDesktopMedia() ? [1500,2000,2500,3000,3500,4000,4500,5000,10000]:[])];
|
|
41
|
+
}
|
|
35
42
|
/****la fonction fetcher doit toujours retourner :
|
|
36
43
|
* 1. la liste des éléments fetchés dans la props data
|
|
37
44
|
* 2. le nombre total d'éléments de la liste obtenue en escluant les clause limit et offset correspondant à la même requête
|
|
@@ -53,10 +60,14 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
|
53
60
|
fetchData,
|
|
54
61
|
fetchPath,
|
|
55
62
|
fetcher,
|
|
63
|
+
ListFooterComponent,
|
|
64
|
+
testID,
|
|
65
|
+
autoSort,
|
|
56
66
|
...rest
|
|
57
67
|
} = props;
|
|
58
68
|
rest = defaultObj(rest);
|
|
59
69
|
rest.exportTableProps = defaultObj(rest.exportTableProps)
|
|
70
|
+
const firstPage = 1;
|
|
60
71
|
const tableName = defaultStr(table.tableName,table.table).trim().toUpperCase();
|
|
61
72
|
canMakePhoneCall = defaultBool(canMakePhoneCall,table.canMakePhoneCall);
|
|
62
73
|
makePhoneCallProps = defaultObj(makePhoneCallProps,rest.makePhoneCallProps,table.makePhoneCallProps);
|
|
@@ -98,13 +109,33 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
|
98
109
|
const hasResultRef = React.useRef(false);
|
|
99
110
|
const totalRef = React.useRef(0);
|
|
100
111
|
const isFetchingRef = React.useRef(false);
|
|
112
|
+
const pageRef = React.useRef(1);
|
|
113
|
+
const limitRef = React.useRef(500);
|
|
114
|
+
const isInitializedRef = React.useRef(false);
|
|
115
|
+
testID = defaultStr(testID,"RNSWRDatagridComponent")
|
|
101
116
|
const {error, isValidating,isLoading,refresh} = useSWR(fetchPath,{
|
|
102
117
|
fetcher : (url,opts)=>{
|
|
118
|
+
if(!isInitializedRef.current) {
|
|
119
|
+
isFetchingRef.current = false;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
103
122
|
opts = extendObj({},opts,fetchOptionsRef.current);
|
|
104
123
|
opts.queryParams = defaultObj(opts.queryParams);
|
|
105
124
|
opts.queryParams.withTotal = true;
|
|
125
|
+
opts.queryParams.limit = limitRef.current;
|
|
126
|
+
opts.queryParams.page = pageRef.current -1;
|
|
127
|
+
if(isObj(opts.sort)){
|
|
128
|
+
opts.queryParams.sort = opts.sort;
|
|
129
|
+
}
|
|
106
130
|
const fetchCB = ({data,total})=>{
|
|
107
131
|
totalRef.current = total;
|
|
132
|
+
/***
|
|
133
|
+
* if(pageRef.current ===firstPage){
|
|
134
|
+
dataRef.current = data;
|
|
135
|
+
} else {
|
|
136
|
+
dataRef.current = prevPage != pageRef.current ? (isObj(data)?{...dataRef.current,...data}:[...dataRef.current,...data]) : data;
|
|
137
|
+
}
|
|
138
|
+
*/
|
|
108
139
|
dataRef.current = data;
|
|
109
140
|
hasResultRef.current = true;
|
|
110
141
|
return data;
|
|
@@ -146,6 +177,41 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
|
146
177
|
};
|
|
147
178
|
refresh();
|
|
148
179
|
}
|
|
180
|
+
const canPagninate = ()=>{
|
|
181
|
+
if(typeof totalRef.current !=='number' || typeof pageRef.current !='number' || typeof limitRef.current !='number') return false;
|
|
182
|
+
if(limitRef.current <= 0) return false;
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
const getTotalPages = ()=>{
|
|
186
|
+
if(!canPagninate()) return false;
|
|
187
|
+
return Math.ceil(totalRef.current / limitRef.current);;
|
|
188
|
+
};
|
|
189
|
+
const getNextPage = ()=>{
|
|
190
|
+
if(!canPagninate()) return false;
|
|
191
|
+
const totalPages = getTotalPages();
|
|
192
|
+
let nPage = pageRef.current+1;
|
|
193
|
+
if(nPage > totalPages){
|
|
194
|
+
nPage = totalPages;
|
|
195
|
+
}
|
|
196
|
+
if(nPage === pageRef.current){
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
return nPage;
|
|
200
|
+
},getPrevPage = ()=>{
|
|
201
|
+
if(!canPagninate()) return false;
|
|
202
|
+
let pPage = pageRef.current - 1;
|
|
203
|
+
if(pPage < firstPage){
|
|
204
|
+
pPage = firstPage;
|
|
205
|
+
}
|
|
206
|
+
if(pPage === pageRef.current){
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
return pPage;
|
|
210
|
+
}, canSortRemotely = ()=>{
|
|
211
|
+
if(!canPagninate() || autoSort === true) return false;
|
|
212
|
+
///si le nombre total d'élements est inférieur au nombre limite alors le trie peut être fait localement
|
|
213
|
+
return totalRef.current > limitRef.current && true || false;
|
|
214
|
+
}
|
|
149
215
|
React.useEffect(()=>{
|
|
150
216
|
const upsert = cAction.upsert(tableName);
|
|
151
217
|
const remove = cAction.remove(tableName);
|
|
@@ -159,15 +225,146 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
|
159
225
|
APP.off(remove,onUpsert);
|
|
160
226
|
}
|
|
161
227
|
},[]);
|
|
228
|
+
const loading = (isLoading|| isValidating);
|
|
229
|
+
const pointerEvents = loading ?"node" : "auto";
|
|
162
230
|
return (
|
|
163
231
|
<Datagrid
|
|
232
|
+
testID = {testID}
|
|
164
233
|
{...rest}
|
|
165
234
|
{...defaultObj(table.datagrid)}
|
|
166
|
-
|
|
235
|
+
onSort = {({sort})=>{
|
|
236
|
+
if(!canSortRemotely()) return;
|
|
237
|
+
fetchOptionsRef.current.sort = sort;
|
|
238
|
+
pageRef.current = firstPage;
|
|
239
|
+
doRefresh(true);
|
|
240
|
+
return false;
|
|
241
|
+
}}
|
|
242
|
+
renderCustomPagination = {({context})=>{
|
|
243
|
+
if(!canPagninate()) return null;
|
|
244
|
+
const page = pageRef.current, totalPages = getTotalPages(), prevPage = getPrevPage(),nextPage = getNextPage();
|
|
245
|
+
const iconProp = {
|
|
246
|
+
size : 25,
|
|
247
|
+
style : [theme.styles.noMargin,theme.styles.noPadding],
|
|
248
|
+
}
|
|
249
|
+
const sStyle = [styles.limitStyle1,theme.styles.noPadding,theme.styles.noMargin];
|
|
250
|
+
return <View testID={testID+"_PaginationContainer"} pointerEvents={pointerEvents}>
|
|
251
|
+
<View style={[theme.styles.row,theme.styles.w100]} pointerEvents={pointerEvents} testID={testID+"_PaginationContentContainer"}>
|
|
252
|
+
<Menu
|
|
253
|
+
testID={testID+"_SimpleSelect"}
|
|
254
|
+
style = {sStyle}
|
|
255
|
+
anchor = {(p)=>{
|
|
256
|
+
return <Pressable style={[theme.styles.noMargin,theme.styles.noPadding]} {...p} testID={testID+"MenuSelectLimit"}>
|
|
257
|
+
<Label primary testID={testID+"_Label"} style={[{fontSize:15}]}>
|
|
258
|
+
{limitRef.current.formatNumber()}
|
|
259
|
+
</Label>
|
|
260
|
+
</Pressable>
|
|
261
|
+
}}
|
|
262
|
+
title = {'Limite du nombre d\'éléments par page'}
|
|
263
|
+
items = {getDefaultPaginationRowsPerPageItems().map((item)=>{
|
|
264
|
+
return {
|
|
265
|
+
text : item.formatNumber(),
|
|
266
|
+
icon : limitRef.current == item ? 'check' : null,
|
|
267
|
+
primary : limitRef.current === item ? true : false,
|
|
268
|
+
onPress : ()=>{
|
|
269
|
+
if(item == limitRef.current) return;
|
|
270
|
+
limitRef.current = item;
|
|
271
|
+
pageRef.current = firstPage;
|
|
272
|
+
setTimeout(() => {
|
|
273
|
+
doRefresh(true);
|
|
274
|
+
}, (500));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
})}
|
|
278
|
+
/>
|
|
279
|
+
<Icon
|
|
280
|
+
///firstPage
|
|
281
|
+
{...iconProp}
|
|
282
|
+
title = {"Aller à la première page"}
|
|
283
|
+
name="material-first-page"
|
|
284
|
+
disabled = {pageRef.current <= 1 && true || false}
|
|
285
|
+
onPress = {()=>{
|
|
286
|
+
if(pageRef.current <= firstPage) return;
|
|
287
|
+
pageRef.current = firstPage;
|
|
288
|
+
doRefresh(true);
|
|
289
|
+
}}
|
|
290
|
+
/>
|
|
291
|
+
<Icon
|
|
292
|
+
//decrement
|
|
293
|
+
{...iconProp}
|
|
294
|
+
title = {"Aller à la page précédente {0}".sprintf(prevPage && prevPage.formatNumber()||undefined)}
|
|
295
|
+
name="material-keyboard-arrow-left"
|
|
296
|
+
disabled = {page === prevPage || getPrevPage() === false ? true : false}
|
|
297
|
+
onPress = {()=>{
|
|
298
|
+
const page = getPrevPage();
|
|
299
|
+
if(page === false) return;
|
|
300
|
+
if(pageRef.current === page) return;
|
|
301
|
+
pageRef.current = page;
|
|
302
|
+
doRefresh(true);
|
|
303
|
+
}}
|
|
304
|
+
|
|
305
|
+
/>
|
|
306
|
+
<View testID={testID+"_PaginationLabel"}>
|
|
307
|
+
<Label style={{fontSize:15}}>
|
|
308
|
+
{page.formatNumber()}-{totalPages.formatNumber()}{" / "}{totalRef.current.formatNumber()}
|
|
309
|
+
</Label>
|
|
310
|
+
</View>
|
|
311
|
+
<Icon
|
|
312
|
+
//increment
|
|
313
|
+
{...iconProp}
|
|
314
|
+
title = {"Aller à la page suivante {0}".sprintf(nextPage && nextPage.formatNumber()||undefined)}
|
|
315
|
+
name="material-keyboard-arrow-right"
|
|
316
|
+
disabled = {nextPage >= totalPages || getNextPage() === false ? true : false}
|
|
317
|
+
onPress = {()=>{
|
|
318
|
+
const page = getNextPage();
|
|
319
|
+
if(page === false) return;
|
|
320
|
+
if(pageRef.current === page) return;
|
|
321
|
+
pageRef.current = page;
|
|
322
|
+
doRefresh(true);
|
|
323
|
+
}}
|
|
324
|
+
/>
|
|
325
|
+
<Icon
|
|
326
|
+
//lastPage
|
|
327
|
+
{...iconProp}
|
|
328
|
+
name="material-last-page"
|
|
329
|
+
title = {"Aller à la dernière page {0}".sprintf(totalPages && totalPages.formatNumber()||undefined)}
|
|
330
|
+
disabled = {page >= totalPages ? true : false}
|
|
331
|
+
onPress = {()=>{
|
|
332
|
+
const page = getTotalPages();
|
|
333
|
+
if(pageRef.current >= page) return;
|
|
334
|
+
pageRef.current = page;
|
|
335
|
+
doRefresh(true);
|
|
336
|
+
}}
|
|
337
|
+
|
|
338
|
+
/>
|
|
339
|
+
</View>
|
|
340
|
+
</View>
|
|
341
|
+
}}
|
|
342
|
+
ListFooterComponent = {(props)=>{
|
|
343
|
+
const r = typeof ListFooterComponent =='function'? ListFooterComponent(props) : null;
|
|
344
|
+
if(!loading) return r;
|
|
345
|
+
const aContent = <View testID={testID+"_ListHeaderActivityIndicator"} style={[theme.styles.w100,theme.styles.justifyContentCenter]}>
|
|
346
|
+
<ActivityIndicator color={theme.colors.primary}/>
|
|
347
|
+
</View>;
|
|
348
|
+
if(r){
|
|
349
|
+
return <View testID={testID+"_ListHeaderContainer"} style={[theme.styles.w100]}>
|
|
350
|
+
{r}
|
|
351
|
+
{aContent}
|
|
352
|
+
</View>
|
|
353
|
+
}
|
|
354
|
+
return aContent;
|
|
355
|
+
}}
|
|
356
|
+
handleQueryLimit = {false}
|
|
357
|
+
handlePagination = {false}
|
|
358
|
+
autoSort = {canSortRemotely()? false : true}
|
|
359
|
+
isLoading = {loading && !error && showProgressRef.current && true || false}
|
|
167
360
|
beforeFetchData = {({fetchOptions:opts,force})=>{
|
|
168
361
|
opts.fields = fetchFields;
|
|
169
362
|
opts = getFetchOptions({showError:showProgressRef.current,...opts});
|
|
363
|
+
isInitializedRef.current = true;
|
|
170
364
|
fetchOptionsRef.current = opts;
|
|
365
|
+
if(force){
|
|
366
|
+
pageRef.current = firstPage;
|
|
367
|
+
}
|
|
171
368
|
doRefresh(force);
|
|
172
369
|
return false;
|
|
173
370
|
}}
|
|
@@ -218,6 +415,11 @@ const styles = StyleSheet.create({
|
|
|
218
415
|
labelTitle: {
|
|
219
416
|
fontSize : 18,
|
|
220
417
|
},
|
|
418
|
+
limitStyle : {
|
|
419
|
+
backgroundColor:'transparent',
|
|
420
|
+
width:50,
|
|
421
|
+
height : 35,
|
|
422
|
+
},
|
|
221
423
|
emptyText : {
|
|
222
424
|
fontSize : 16,
|
|
223
425
|
fontWeight : 'bold',
|
|
@@ -111,7 +111,10 @@ const DatagridFactory = (Factory)=>{
|
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
render(){
|
|
114
|
-
let {title,testID,actions,selectableMultiple,
|
|
114
|
+
let {title,testID,actions,selectableMultiple,
|
|
115
|
+
sortable,
|
|
116
|
+
autoSort,
|
|
117
|
+
exportable,
|
|
115
118
|
selectable,pagin,showPagination,
|
|
116
119
|
sessionName,onMount,onUnmount,onFetchData,dataSourceSelector,dataSourceSelectorProps,queryLimit,
|
|
117
120
|
filters,
|
|
@@ -138,7 +141,6 @@ const DatagridFactory = (Factory)=>{
|
|
|
138
141
|
_dataSourceSelector = null;
|
|
139
142
|
}
|
|
140
143
|
exportable = defaultBool(exportable,true);
|
|
141
|
-
sortable = defaultVal(sortable,true);
|
|
142
144
|
let isMobile = isMobileOrTabletMedia();
|
|
143
145
|
selectable = defaultVal(selectable,true);
|
|
144
146
|
selectableMultiple = defaultBool(selectableMultiple,true);
|
|
@@ -170,20 +172,21 @@ const DatagridFactory = (Factory)=>{
|
|
|
170
172
|
if(selectableMultiple && max && defaultBool(this.props.selectableMultiple,true)){
|
|
171
173
|
max = max.formatNumber();
|
|
172
174
|
restItems = [
|
|
173
|
-
|
|
174
|
-
|
|
175
|
+
...this.renderCustomMenu(),
|
|
176
|
+
...(selectableMultiple ? [{
|
|
177
|
+
label : "Sélect "+max,
|
|
175
178
|
icon : "select-all",
|
|
176
179
|
onPress : (x,event)=>{
|
|
177
180
|
this.handleAllRowsToggle(true);
|
|
178
181
|
}
|
|
179
182
|
},
|
|
180
183
|
{
|
|
181
|
-
|
|
184
|
+
label : "Tout désélec",
|
|
182
185
|
onPress : (x,event)=>{
|
|
183
186
|
this.handleAllRowsToggle(false);
|
|
184
187
|
},
|
|
185
188
|
icon : "select"
|
|
186
|
-
}
|
|
189
|
+
}] : [])
|
|
187
190
|
]
|
|
188
191
|
}
|
|
189
192
|
const rPagination = showPagination ? <View style={[styles.paginationContainer]}>
|
|
@@ -192,6 +195,7 @@ const DatagridFactory = (Factory)=>{
|
|
|
192
195
|
<View testID={testID+"_HeaderQueryLimit"}>
|
|
193
196
|
{this.renderQueryLimit(this.state.data.length.formatNumber())}
|
|
194
197
|
</View>
|
|
198
|
+
{this.renderCustomPagination()}
|
|
195
199
|
{!isMobile && <>
|
|
196
200
|
<Button normal style={[styles.paginationItem]} icon = {"refresh"} onPress = {this.refresh.bind(this)}>
|
|
197
201
|
Rafraichir
|
|
@@ -214,19 +218,15 @@ const DatagridFactory = (Factory)=>{
|
|
|
214
218
|
>
|
|
215
219
|
{showFooters?'Masquer/Ligne des totaux':'Afficher/Ligne des totaux'}
|
|
216
220
|
</Button>:null}
|
|
217
|
-
{
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
{item.text}
|
|
227
|
-
</Button>
|
|
228
|
-
})}
|
|
229
|
-
</>)}
|
|
221
|
+
{restItems.map((item,index)=>{
|
|
222
|
+
return <Button
|
|
223
|
+
normal
|
|
224
|
+
key = {index}
|
|
225
|
+
{...item}
|
|
226
|
+
style={[styles.paginationItem,item.style]}
|
|
227
|
+
children = {item.children|| item.label}
|
|
228
|
+
/>
|
|
229
|
+
})}
|
|
230
230
|
</>}
|
|
231
231
|
{exportable && (
|
|
232
232
|
<>{/**
|
|
@@ -320,6 +320,7 @@ const DatagridFactory = (Factory)=>{
|
|
|
320
320
|
</View>
|
|
321
321
|
<Table
|
|
322
322
|
ref = {this.listRef}
|
|
323
|
+
{...rest}
|
|
323
324
|
hasFooters = {hasFooterFields}
|
|
324
325
|
showFilters = {showFilters}
|
|
325
326
|
showFooters = {showFooters}
|
|
@@ -11,34 +11,55 @@ import {defaultStr,isPromise,defaultObj} from "$utils";
|
|
|
11
11
|
import {open as openPreloader,close as closePreloader} from "$preloader";
|
|
12
12
|
import {styles as _styles} from "$theme";
|
|
13
13
|
import Tooltip from "$ecomponents/Tooltip";
|
|
14
|
+
import {navigateToTableData} from "$enavigation/utils";
|
|
15
|
+
import Auth from "$cauth";
|
|
16
|
+
import fetch from "$capi/fetch";
|
|
14
17
|
|
|
15
18
|
const TableLinKComponent = React.forwardRef((props,ref)=>{
|
|
16
|
-
let {disabled,labelProps,server,containerProps,id,
|
|
19
|
+
let {disabled,readOnly,labelProps,server,containerProps,perm,id,fetchForeignData,foreignKeyTable,foreignKeyColumn,data,testID,Component,routeName,routeParams,component,primary,triggerProps,onPress,children, ...rest} = props;
|
|
17
20
|
testID = defaultStr(testID,"RN_TableDataLinkContainer")
|
|
18
|
-
|
|
21
|
+
foreignKeyTable = defaultStr(foreignKeyTable).trim();
|
|
22
|
+
foreignKeyColumn = defaultStr(foreignKeyColumn).trim();
|
|
19
23
|
rest = defaultObj(rest);
|
|
20
24
|
containerProps = defaultObj(containerProps)
|
|
21
25
|
labelProps = defaultObj(labelProps);
|
|
22
|
-
columnDef = defaultObj(columnDef);
|
|
23
26
|
data = defaultObj(data);
|
|
24
27
|
id = defaultStr(id);
|
|
25
|
-
if(!id){
|
|
26
|
-
|
|
28
|
+
if(!id || !foreignKeyTable){
|
|
29
|
+
readOnly = true;
|
|
27
30
|
}
|
|
28
|
-
const pointerEvents = disabled || !id? 'none' : 'auto';
|
|
31
|
+
const pointerEvents = disabled || readOnly || !id? 'none' : 'auto';
|
|
29
32
|
const onPressLink = (event)=>{
|
|
30
33
|
React.stopEventPropagation(event);
|
|
31
|
-
|
|
34
|
+
if((isNonNullString(perm) && !Auth.isAllowedFromString(perm)) || !Auth.isTableDataAllowed({table:foreignKeyTable,action:'read'})){
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const args = {...React.getOnPressArgs(event),...rest,fetch,foreignKeyTable,foreignKeyColumn,data,id,value:id};
|
|
38
|
+
let r = typeof onPress =='function'? onPress(args) : undefined;
|
|
39
|
+
if(r === false) return;
|
|
40
|
+
const cb = (a)=>{
|
|
41
|
+
const r2 = typeof fetchForeignData === 'function'? fetchForeignData({...args,...defaultObj(a)}) : undefined;
|
|
42
|
+
if(isPromise(r2)){
|
|
43
|
+
return r2.then((data)=>{
|
|
44
|
+
if(isObj(data) && data[foreignKeyColumn] !== undefined){
|
|
45
|
+
navigateToTableData({tableName:foreignKeyTable,data});
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return Promise.reject({msg:'type de données retournée par la fonction fetchForeignKeyData invalide'});
|
|
50
|
+
}
|
|
51
|
+
openPreloader("traitement de la requête...");
|
|
32
52
|
if(isPromise(r)){
|
|
33
|
-
|
|
34
|
-
|
|
53
|
+
r.then(cb).finally(closePreloader);
|
|
54
|
+
} else {
|
|
55
|
+
cb().finally(closePreloader);
|
|
35
56
|
}
|
|
36
57
|
}
|
|
37
58
|
rest.style = [rest.style,_styles.cursorPointer];
|
|
38
|
-
const CP = disabled ? View : TouchableOpacity;
|
|
59
|
+
const CP = disabled || readOnly ? View : TouchableOpacity;
|
|
39
60
|
return <CP testID={testID} onLongPres={(e)=>React.stopEventPropagation(e)} {...containerProps} onPress={disabled? undefined : onPressLink} style={[styles.container,containerProps.style]}>
|
|
40
|
-
<Tooltip testID={testID+"_Tooltip"} {...rest} Component={Component} onPress={disabled?undefined:onPressLink} ref={ref} pointerEvents={pointerEvents} disabled = {disabled}>
|
|
41
|
-
<Label testID={testID+"_Label"} underlined primary {...labelProps} style={[_styles.lh15,labelProps.style]} disabled={disabled}>{children}</Label>
|
|
61
|
+
<Tooltip testID={testID+"_Tooltip"} {...rest} Component={Component} onPress={disabled || readOnly?undefined:onPressLink} ref={ref} pointerEvents={pointerEvents} readOnly={readOnly} disabled = {disabled}>
|
|
62
|
+
<Label testID={testID+"_Label"} underlined primary {...labelProps} style={[_styles.lh15,labelProps.style]} disabled={disabled} readOnly={readOnly}>{children}</Label>
|
|
42
63
|
</Tooltip>
|
|
43
64
|
</CP>
|
|
44
65
|
});
|
|
@@ -47,6 +68,9 @@ export default TableLinKComponent;
|
|
|
47
68
|
|
|
48
69
|
|
|
49
70
|
TableLinKComponent.propTypes = {
|
|
71
|
+
foreignKeyColumn : PropTypes.string.isRequired,//le nom de la colonne de la clé étrangère
|
|
72
|
+
foreignKeyTable : PropTypes.string.isRequired, //le nom de la table référencée
|
|
73
|
+
fetchForeignData : PropTypes.func, // la fonction permettant de chercher la données à distance
|
|
50
74
|
server : PropTypes.string,//le serveur sur lequel rechercher les données
|
|
51
75
|
primary : PropTypes.bool,//si le composant sera stylé en theme primary de react
|
|
52
76
|
///les props à utiliser pour afficher la table de données en cas de click sur le lien
|
|
@@ -13,10 +13,8 @@ import cActions from "$cactions";
|
|
|
13
13
|
import {View} from "react-native";
|
|
14
14
|
|
|
15
15
|
export default function DatabaseStatisticContainer (props){
|
|
16
|
-
const [
|
|
17
|
-
|
|
18
|
-
count : 0,
|
|
19
|
-
});
|
|
16
|
+
const [count,setCount] = React.useState(0);
|
|
17
|
+
const [isLoading,setIsLoading] = React.useState(true);
|
|
20
18
|
let {table,fetchCount,index,testID,title,icon,onPress} = props;
|
|
21
19
|
title = defaultStr(title)
|
|
22
20
|
table = defaultObj(table);
|
|
@@ -28,14 +26,14 @@ export default function DatabaseStatisticContainer (props){
|
|
|
28
26
|
const refresh = ()=>{
|
|
29
27
|
if(refreshingRef.current || !isMounted()) return;
|
|
30
28
|
refreshingRef.current = true;
|
|
29
|
+
setIsLoading(true);
|
|
31
30
|
setTimeout(()=>{
|
|
32
31
|
fetchCount().then((count)=>{
|
|
33
|
-
|
|
32
|
+
setCount(count);
|
|
33
|
+
setIsLoading(false);
|
|
34
34
|
refreshingRef.current = false;
|
|
35
35
|
}).catch((e)=>{
|
|
36
|
-
|
|
37
|
-
isLoading : false, count : 0,
|
|
38
|
-
});
|
|
36
|
+
setIsLoading(false);
|
|
39
37
|
refreshingRef.current = false;
|
|
40
38
|
});
|
|
41
39
|
},100);
|
|
@@ -50,10 +48,6 @@ export default function DatabaseStatisticContainer (props){
|
|
|
50
48
|
APP.off(cActions.remove(tableName),refresh);
|
|
51
49
|
}
|
|
52
50
|
},[]);
|
|
53
|
-
React.useEffect(()=>{
|
|
54
|
-
//refresh();
|
|
55
|
-
},[props])
|
|
56
|
-
const {isLoading,count} = state;
|
|
57
51
|
return <Item
|
|
58
52
|
testID = {defaultStr(testID,"RN_DatabaseStatistic_"+table)}
|
|
59
53
|
onPress = {(args)=>{
|
|
@@ -65,7 +59,6 @@ export default function DatabaseStatisticContainer (props){
|
|
|
65
59
|
left = {(aProps)=>{
|
|
66
60
|
return <Avatar suffix={index} {...aProps} icon= {icon} size={40} label={title}/>
|
|
67
61
|
}}
|
|
68
|
-
//right = {(rP)=><Icon {...rP} name='refresh' onPress={refresh}/>}
|
|
69
62
|
title = {<Label splitText numberOfLines={1} primary style={[{fontSize:15}]}>{title}</Label>}
|
|
70
63
|
titleProps = {{primary : true}}
|
|
71
64
|
description = {isLoading?<View style={[theme.styles.justifyContentFlexStart,theme.styles.alignItemsFlexStart]}>
|
|
@@ -29,6 +29,43 @@ const DEFAULT_TABS_KEYS = "main-tabs";
|
|
|
29
29
|
|
|
30
30
|
const TIMEOUT = 50;
|
|
31
31
|
|
|
32
|
+
const checkPrimary = (data,f)=>{
|
|
33
|
+
return !(!(f in data) || (data[f] == null) || (!data[f] && typeof data !=='number'));
|
|
34
|
+
}
|
|
35
|
+
/*** vérifie si le document passé en paramètre est éditable
|
|
36
|
+
* @param {object} data la données à vérifier
|
|
37
|
+
* @param {object| array} les champs sur lesquels se baser pour vérifier si la donénes est une mise à jour
|
|
38
|
+
* @param {func} checkPrimaryKey la foncition permettant de vérifier s'il s'agit d'une clé primaire pour la données courante
|
|
39
|
+
*/
|
|
40
|
+
export const isDocEditing = (data,fields,checkPrimaryKey)=>{
|
|
41
|
+
if(!isObj(data) || !isObjOrArray(fields)) return false;
|
|
42
|
+
|
|
43
|
+
let hasPrimaryFields = false;
|
|
44
|
+
let hasValidated = true;
|
|
45
|
+
for(let i in fields){
|
|
46
|
+
const field = fields[i];
|
|
47
|
+
if(typeof checkPrimaryKey =='function') {
|
|
48
|
+
hasPrimaryFields = true;
|
|
49
|
+
if(checkPrimaryKey({field,i,index:i,data}) === false){
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if(!isObj(field)) continue;
|
|
55
|
+
hasPrimaryFields = true;
|
|
56
|
+
const f = defaultStr(field.field,i);
|
|
57
|
+
if(field.primaryKey === true){
|
|
58
|
+
if(!checkPrimary(data,f)){
|
|
59
|
+
hasValidated = false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if(hasPrimaryFields){
|
|
64
|
+
return hasValidated;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
32
69
|
export default class TableDataScreenComponent extends FormDataScreen{
|
|
33
70
|
constructor(props){
|
|
34
71
|
super(props);
|
|
@@ -49,7 +86,7 @@ export default class TableDataScreenComponent extends FormDataScreen{
|
|
|
49
86
|
Object.map(table.fields,(field,i)=>{
|
|
50
87
|
if(isObj(field) && field.form !== false){
|
|
51
88
|
fields[i] = Object.clone(field);
|
|
52
|
-
if(field.
|
|
89
|
+
if(field.primaryKey === true){
|
|
53
90
|
primaryKeyFields[field.field || i] = true;
|
|
54
91
|
}
|
|
55
92
|
} else {
|
|
@@ -420,17 +457,9 @@ export default class TableDataScreenComponent extends FormDataScreen{
|
|
|
420
457
|
isDocEditing(data){
|
|
421
458
|
data = defaultObj(data);
|
|
422
459
|
if(!this.isDocEditingProp){
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
hasPrimaryFields = true;
|
|
427
|
-
if(!(f in data) || (data[f] == null) || (!data[f] && typeof data !=='number')){
|
|
428
|
-
hasValidated = false;
|
|
429
|
-
}
|
|
430
|
-
});
|
|
431
|
-
if(hasPrimaryFields){
|
|
432
|
-
return hasValidated;
|
|
433
|
-
}
|
|
460
|
+
if(isDocEditing(data,this.primaryKeyFields,({index:field,data})=>{
|
|
461
|
+
return checkPrimary(data,field);
|
|
462
|
+
})) return true;
|
|
434
463
|
}
|
|
435
464
|
return super.isDocEditing(data);
|
|
436
465
|
}
|
|
@@ -448,7 +477,7 @@ export default class TableDataScreenComponent extends FormDataScreen{
|
|
|
448
477
|
if(this.cloneProp && this.cloneProp(data,this) === false) return data;
|
|
449
478
|
this.showPreloader();
|
|
450
479
|
delete data.approved;
|
|
451
|
-
Object.map(['_rev',...generatedColumnsProperties,'_id','code','updateBy','updatedDate','createBy','updatedHour','createdHour','createdDate'],(idx)=>{
|
|
480
|
+
Object.map(['_rev',...generatedColumnsProperties,...Object.keys(this.primaryKeyFields),'_id','code','updateBy','updatedDate','createBy','updatedHour','createdHour','createdDate'],(idx)=>{
|
|
452
481
|
data[idx] = undefined;
|
|
453
482
|
delete data[idx];
|
|
454
483
|
});
|