@fto-consult/expo-ui 2.7.13 → 2.8.0
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 +115 -115
- package/src/auth/Login.js +4 -3
- package/src/components/Datagrid/Common/Common.js +6 -3
- package/src/components/Filter/index.js +2 -31
- package/src/components/Form/Fields/Field.js +2 -1
- package/src/components/Form/FormData/FormData.js +1 -1
- package/src/components/Icon/Font.js +7 -3
- package/src/components/Table/index.js +1 -1
- package/src/navigation/Drawer/items/index.js +1 -1
- package/src/components/Filter/session.js +0 -18
- package/src/components/Filter/utils.js +0 -552
package/package.json
CHANGED
|
@@ -1,115 +1,115 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@fto-consult/expo-ui",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Bibliothèque de composants UI Expo,react-native",
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"resolutions": {
|
|
7
|
-
"@expo/cli": "xxx"
|
|
8
|
-
},
|
|
9
|
-
"scripts": {
|
|
10
|
-
"publish1": "npm publish --access=public",
|
|
11
|
-
"unpublish": "npm -f unpublish @fto-consult/expo-ui",
|
|
12
|
-
"build-web": "",
|
|
13
|
-
"dev": "npx expo start -c --no-minify",
|
|
14
|
-
"start": "npx expo start --dev --no-minify",
|
|
15
|
-
"start-d": "npx expo start -c --no-dev --no-minify",
|
|
16
|
-
"start-p": "npm run start-d",
|
|
17
|
-
"expo-start-client": "npx expo start --dev --no-minify --dev-client",
|
|
18
|
-
"start-m": "npx expo start - c--dev--no -minify",
|
|
19
|
-
"android": "npx expo start --android -c",
|
|
20
|
-
"ios": "npx expo start --ios",
|
|
21
|
-
"web": "npx expo start --web",
|
|
22
|
-
"web-c": "npx expo start --web -c",
|
|
23
|
-
"eject": "expo eject",
|
|
24
|
-
"emulator": "npm run android-emulator",
|
|
25
|
-
"web-server": "npx serve web-build",
|
|
26
|
-
"build-android": "eas build --clear-cache -p android --profile preview",
|
|
27
|
-
"build-android-local": "eas build --platform android --local",
|
|
28
|
-
"build-android-dist": "eas build --clear-cache -p android",
|
|
29
|
-
"build-ios": "eas build --clear-cache -p ios --profile preview",
|
|
30
|
-
"build-ios-dist": "eas build --clear-cache -p ios",
|
|
31
|
-
"install-apk": "adb -s emulator-5554 install myapp.apk",
|
|
32
|
-
"android-emulator": "emulator -avd EMULATOR",
|
|
33
|
-
"flipper": "npx cross-env METRO_SERVER_PORT=19000 E:\\Studies\\react-native\\debugger\\Flipper-win\\Flipper.exe",
|
|
34
|
-
"build-electron": "electron-webpack && electron-builder --dir -c.compression=store",
|
|
35
|
-
"test:build": "electron-webpack && electron-builder --dir -c.compression=store -c.mac.identity=null",
|
|
36
|
-
"compile-electron": "webpack --config ./electron/webpack.config.js",
|
|
37
|
-
"compile-electron-p": "webpack --config ./electron/webpack.config.js --mode=production",
|
|
38
|
-
"electron": "electron ./electron",
|
|
39
|
-
"logcat": "adb -d logcat com.ftc.apps.salite1:E > errors.txt",
|
|
40
|
-
"logcat-export": "adb -d logcat com.ftc.apps.salite1 *:S > logcat.txt",
|
|
41
|
-
"electron-c": "npm run compile-electron && npm run electron",
|
|
42
|
-
"electron-p": "npm run compile-electron-p && npm run electron",
|
|
43
|
-
"update-app-version": "node ./update-app-version.js",
|
|
44
|
-
"find-licenses": "node ./find-licenses.js",
|
|
45
|
-
"fix-dependencies": "expo doctor --fix-dependencies",
|
|
46
|
-
"delete-node-modules": "rimraf ./**/node_modules"
|
|
47
|
-
},
|
|
48
|
-
"repository": {
|
|
49
|
-
"type": "git",
|
|
50
|
-
"url": "git+https://github.com/borispipo/expo-ui.git"
|
|
51
|
-
},
|
|
52
|
-
"keywords": [
|
|
53
|
-
"Expo",
|
|
54
|
-
"React-Native"
|
|
55
|
-
],
|
|
56
|
-
"author": "Boris Fouomene",
|
|
57
|
-
"license": "ISC",
|
|
58
|
-
"bugs": {
|
|
59
|
-
"url": "https://github.com/borispipo/expo-ui/issues"
|
|
60
|
-
},
|
|
61
|
-
"homepage": "https://github.com/borispipo/expo-ui#readme",
|
|
62
|
-
"dependencies": {
|
|
63
|
-
"@babel/plugin-proposal-export-namespace-from": "^7.18.9",
|
|
64
|
-
"@babel/preset-react": "^7.18.6",
|
|
65
|
-
"@emotion/native": "^11.10.0",
|
|
66
|
-
"@expo/html-elements": "^0.2.0",
|
|
67
|
-
"@expo/metro-config": "^0.4.0",
|
|
68
|
-
"@expo/vector-icons": "^13.0.0",
|
|
69
|
-
"@expo/webpack-config": "^0.17.2",
|
|
70
|
-
"@fto-consult/common": "^1.
|
|
71
|
-
"@gorhom/portal": "^1.0.14",
|
|
72
|
-
"@react-native-async-storage/async-storage": "~1.17.3",
|
|
73
|
-
"@react-native-community/datetimepicker": "6.5.2",
|
|
74
|
-
"@react-native-community/netinfo": "9.3.5",
|
|
75
|
-
"@react-navigation/native": "^6.0.13",
|
|
76
|
-
"@react-navigation/native-stack": "^6.9.1",
|
|
77
|
-
"@shopify/flash-list": "1.3.1",
|
|
78
|
-
"babel-plugin-inline-dotenv": "^1.7.0",
|
|
79
|
-
"babel-plugin-module-resolver": "^4.1.0",
|
|
80
|
-
"babel-plugin-transform-inline-environment-variables": "^0.4.4",
|
|
81
|
-
"expo": "^47.0.8",
|
|
82
|
-
"expo-camera": "~13.1.0",
|
|
83
|
-
"expo-clipboard": "~4.0.1",
|
|
84
|
-
"expo-font": "~11.0.1",
|
|
85
|
-
"expo-image-picker": "~14.0.2",
|
|
86
|
-
"expo-linking": "~3.2.3",
|
|
87
|
-
"expo-sqlite": "~11.0.0",
|
|
88
|
-
"expo-status-bar": "~1.4.2",
|
|
89
|
-
"expo-system-ui": "~2.0.1",
|
|
90
|
-
"expo-web-browser": "~12.0.0",
|
|
91
|
-
"google-libphonenumber": "^3.2.31",
|
|
92
|
-
"htmlparser2-without-node-native": "^3.9.2",
|
|
93
|
-
"mongo-parse": "^2.1.0",
|
|
94
|
-
"parent-package-json": "^2.0.1",
|
|
95
|
-
"prop-types": "^15.8.1",
|
|
96
|
-
"react": "18.1.0",
|
|
97
|
-
"react-apexcharts": "^1.4.0",
|
|
98
|
-
"react-content-loader": "^6.2.0",
|
|
99
|
-
"react-dom": "18.1.0",
|
|
100
|
-
"react-native": "0.70.5",
|
|
101
|
-
"react-native-big-list": "^1.5.5",
|
|
102
|
-
"react-native-gesture-handler": "~2.8.0",
|
|
103
|
-
"react-native-paper": "^4.12.5",
|
|
104
|
-
"react-native-paper-dates": "^0.9.2",
|
|
105
|
-
"react-native-reanimated": "~2.12.0",
|
|
106
|
-
"react-native-safe-area-context": "4.4.1",
|
|
107
|
-
"react-native-screens": "~3.18.0",
|
|
108
|
-
"react-native-svg": "13.4.0",
|
|
109
|
-
"react-native-web": "~0.18.7",
|
|
110
|
-
"react-native-webview": "11.23.1",
|
|
111
|
-
"sharp-cli": "^2.1.0",
|
|
112
|
-
"tippy.js": "^6.3.7",
|
|
113
|
-
"yargs": "^17.1.1-candidate.0"
|
|
114
|
-
}
|
|
115
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@fto-consult/expo-ui",
|
|
3
|
+
"version": "2.8.0",
|
|
4
|
+
"description": "Bibliothèque de composants UI Expo,react-native",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"resolutions": {
|
|
7
|
+
"@expo/cli": "xxx"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"publish1": "npm publish --access=public",
|
|
11
|
+
"unpublish": "npm -f unpublish @fto-consult/expo-ui",
|
|
12
|
+
"build-web": "",
|
|
13
|
+
"dev": "npx expo start -c --no-minify",
|
|
14
|
+
"start": "npx expo start --dev --no-minify",
|
|
15
|
+
"start-d": "npx expo start -c --no-dev --no-minify",
|
|
16
|
+
"start-p": "npm run start-d",
|
|
17
|
+
"expo-start-client": "npx expo start --dev --no-minify --dev-client",
|
|
18
|
+
"start-m": "npx expo start - c--dev--no -minify",
|
|
19
|
+
"android": "npx expo start --android -c",
|
|
20
|
+
"ios": "npx expo start --ios",
|
|
21
|
+
"web": "npx expo start --web",
|
|
22
|
+
"web-c": "npx expo start --web -c",
|
|
23
|
+
"eject": "expo eject",
|
|
24
|
+
"emulator": "npm run android-emulator",
|
|
25
|
+
"web-server": "npx serve web-build",
|
|
26
|
+
"build-android": "eas build --clear-cache -p android --profile preview",
|
|
27
|
+
"build-android-local": "eas build --platform android --local",
|
|
28
|
+
"build-android-dist": "eas build --clear-cache -p android",
|
|
29
|
+
"build-ios": "eas build --clear-cache -p ios --profile preview",
|
|
30
|
+
"build-ios-dist": "eas build --clear-cache -p ios",
|
|
31
|
+
"install-apk": "adb -s emulator-5554 install myapp.apk",
|
|
32
|
+
"android-emulator": "emulator -avd EMULATOR",
|
|
33
|
+
"flipper": "npx cross-env METRO_SERVER_PORT=19000 E:\\Studies\\react-native\\debugger\\Flipper-win\\Flipper.exe",
|
|
34
|
+
"build-electron": "electron-webpack && electron-builder --dir -c.compression=store",
|
|
35
|
+
"test:build": "electron-webpack && electron-builder --dir -c.compression=store -c.mac.identity=null",
|
|
36
|
+
"compile-electron": "webpack --config ./electron/webpack.config.js",
|
|
37
|
+
"compile-electron-p": "webpack --config ./electron/webpack.config.js --mode=production",
|
|
38
|
+
"electron": "electron ./electron",
|
|
39
|
+
"logcat": "adb -d logcat com.ftc.apps.salite1:E > errors.txt",
|
|
40
|
+
"logcat-export": "adb -d logcat com.ftc.apps.salite1 *:S > logcat.txt",
|
|
41
|
+
"electron-c": "npm run compile-electron && npm run electron",
|
|
42
|
+
"electron-p": "npm run compile-electron-p && npm run electron",
|
|
43
|
+
"update-app-version": "node ./update-app-version.js",
|
|
44
|
+
"find-licenses": "node ./find-licenses.js",
|
|
45
|
+
"fix-dependencies": "expo doctor --fix-dependencies",
|
|
46
|
+
"delete-node-modules": "rimraf ./**/node_modules"
|
|
47
|
+
},
|
|
48
|
+
"repository": {
|
|
49
|
+
"type": "git",
|
|
50
|
+
"url": "git+https://github.com/borispipo/expo-ui.git"
|
|
51
|
+
},
|
|
52
|
+
"keywords": [
|
|
53
|
+
"Expo",
|
|
54
|
+
"React-Native"
|
|
55
|
+
],
|
|
56
|
+
"author": "Boris Fouomene",
|
|
57
|
+
"license": "ISC",
|
|
58
|
+
"bugs": {
|
|
59
|
+
"url": "https://github.com/borispipo/expo-ui/issues"
|
|
60
|
+
},
|
|
61
|
+
"homepage": "https://github.com/borispipo/expo-ui#readme",
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"@babel/plugin-proposal-export-namespace-from": "^7.18.9",
|
|
64
|
+
"@babel/preset-react": "^7.18.6",
|
|
65
|
+
"@emotion/native": "^11.10.0",
|
|
66
|
+
"@expo/html-elements": "^0.2.0",
|
|
67
|
+
"@expo/metro-config": "^0.4.0",
|
|
68
|
+
"@expo/vector-icons": "^13.0.0",
|
|
69
|
+
"@expo/webpack-config": "^0.17.2",
|
|
70
|
+
"@fto-consult/common": "^1.14.15",
|
|
71
|
+
"@gorhom/portal": "^1.0.14",
|
|
72
|
+
"@react-native-async-storage/async-storage": "~1.17.3",
|
|
73
|
+
"@react-native-community/datetimepicker": "6.5.2",
|
|
74
|
+
"@react-native-community/netinfo": "9.3.5",
|
|
75
|
+
"@react-navigation/native": "^6.0.13",
|
|
76
|
+
"@react-navigation/native-stack": "^6.9.1",
|
|
77
|
+
"@shopify/flash-list": "1.3.1",
|
|
78
|
+
"babel-plugin-inline-dotenv": "^1.7.0",
|
|
79
|
+
"babel-plugin-module-resolver": "^4.1.0",
|
|
80
|
+
"babel-plugin-transform-inline-environment-variables": "^0.4.4",
|
|
81
|
+
"expo": "^47.0.8",
|
|
82
|
+
"expo-camera": "~13.1.0",
|
|
83
|
+
"expo-clipboard": "~4.0.1",
|
|
84
|
+
"expo-font": "~11.0.1",
|
|
85
|
+
"expo-image-picker": "~14.0.2",
|
|
86
|
+
"expo-linking": "~3.2.3",
|
|
87
|
+
"expo-sqlite": "~11.0.0",
|
|
88
|
+
"expo-status-bar": "~1.4.2",
|
|
89
|
+
"expo-system-ui": "~2.0.1",
|
|
90
|
+
"expo-web-browser": "~12.0.0",
|
|
91
|
+
"google-libphonenumber": "^3.2.31",
|
|
92
|
+
"htmlparser2-without-node-native": "^3.9.2",
|
|
93
|
+
"mongo-parse": "^2.1.0",
|
|
94
|
+
"parent-package-json": "^2.0.1",
|
|
95
|
+
"prop-types": "^15.8.1",
|
|
96
|
+
"react": "18.1.0",
|
|
97
|
+
"react-apexcharts": "^1.4.0",
|
|
98
|
+
"react-content-loader": "^6.2.0",
|
|
99
|
+
"react-dom": "18.1.0",
|
|
100
|
+
"react-native": "0.70.5",
|
|
101
|
+
"react-native-big-list": "^1.5.5",
|
|
102
|
+
"react-native-gesture-handler": "~2.8.0",
|
|
103
|
+
"react-native-paper": "^4.12.5",
|
|
104
|
+
"react-native-paper-dates": "^0.9.2",
|
|
105
|
+
"react-native-reanimated": "~2.12.0",
|
|
106
|
+
"react-native-safe-area-context": "4.4.1",
|
|
107
|
+
"react-native-screens": "~3.18.0",
|
|
108
|
+
"react-native-svg": "13.4.0",
|
|
109
|
+
"react-native-web": "~0.18.7",
|
|
110
|
+
"react-native-webview": "11.23.1",
|
|
111
|
+
"sharp-cli": "^2.1.0",
|
|
112
|
+
"tippy.js": "^6.3.7",
|
|
113
|
+
"yargs": "^17.1.1-candidate.0"
|
|
114
|
+
}
|
|
115
|
+
}
|
package/src/auth/Login.js
CHANGED
|
@@ -86,7 +86,7 @@ export default function LoginComponent(props){
|
|
|
86
86
|
},1000)
|
|
87
87
|
}
|
|
88
88
|
},[withPortal])
|
|
89
|
-
const {header,withScrollView:customWithScrollView,children,initialize,contentTop,data:loginData,canGoToNext,keyboardEvents,onSuccess:onLoginSuccess,mutateData,canSubmit:canSubmitForm,onStepChange,...loginProps} = defaultObj(getProps({
|
|
89
|
+
const {header,withScrollView:customWithScrollView,children,initialize,contentTop,data:loginData,canGoToNext,keyboardEvents,onSuccess:onLoginSuccess,mutateData,beforeSubmit:beforeSubmitForm,canSubmit:canSubmitForm,onStepChange,...loginProps} = defaultObj(getProps({
|
|
90
90
|
...state,
|
|
91
91
|
setState,
|
|
92
92
|
state,
|
|
@@ -119,6 +119,7 @@ export default function LoginComponent(props){
|
|
|
119
119
|
* par défaut, on envoie les données lorssqu'on est à l'étappe 2
|
|
120
120
|
* **/
|
|
121
121
|
const canSubmit = typeof canSubmitForm =='function'? canSubmitForm : ({step})=>step >= 2;
|
|
122
|
+
const beforeSubmit = typeof beforeSubmitForm =='function'? beforeSubmitForm : x=> true;
|
|
122
123
|
const goToNext = ()=>{
|
|
123
124
|
let step = state.step;
|
|
124
125
|
const data = getData();
|
|
@@ -149,7 +150,7 @@ export default function LoginComponent(props){
|
|
|
149
150
|
nextButtonRef.current?.enable();
|
|
150
151
|
}
|
|
151
152
|
if(step > 1){
|
|
152
|
-
if(canSubmit(args)){
|
|
153
|
+
if(canSubmit(args) && beforeSubmit(args) !== false){
|
|
153
154
|
///pour modifier automatiquement la données à mettre à jour
|
|
154
155
|
if(typeof mutateData =='function'){
|
|
155
156
|
mutateData(data);
|
|
@@ -178,7 +179,7 @@ export default function LoginComponent(props){
|
|
|
178
179
|
else {
|
|
179
180
|
loginFields[i] = Object.clone(field);
|
|
180
181
|
hasLoginFields = true;
|
|
181
|
-
if("autoFocusOnStep" in loginFields[i]){
|
|
182
|
+
if("autoFocusOnStep" in loginFields[i] && typeof loginFields[i].autoFocus !=='boolean'){
|
|
182
183
|
loginFields[i].autoFocus = !!loginFields[i].autoFocusOnStep;
|
|
183
184
|
}
|
|
184
185
|
}
|
|
@@ -11,7 +11,7 @@ import {notify,showConfirm} from "$ecomponents/Dialog";
|
|
|
11
11
|
import Label from "$ecomponents/Label";
|
|
12
12
|
import Image from "$ecomponents/Image";
|
|
13
13
|
import Icon,{COPY_ICON} from "$ecomponents/Icon";
|
|
14
|
-
import filterUtils from "$
|
|
14
|
+
import filterUtils from "$cfilters";
|
|
15
15
|
import Hashtag from "$ecomponents/Hashtag";
|
|
16
16
|
import {sortBy,isDecimal,extendObj,isObjOrArray,defaultNumber,defaultStr,isFunction,defaultBool,defaultArray,defaultObj,isNonNullString,defaultDecimal} from "$utils";
|
|
17
17
|
import {Datagrid as DatagridContentLoader} from "$ecomponents/ContentLoader";
|
|
@@ -900,7 +900,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
900
900
|
field = header.field = defaultStr(header.field,field,headerIndex);
|
|
901
901
|
delete restCol.filter;
|
|
902
902
|
|
|
903
|
-
const type = defaultStr(header.type).toLowerCase();
|
|
903
|
+
const type = defaultStr(header.jsType,header.type,"text").toLowerCase();
|
|
904
904
|
sortType = defaultStr(sortType,type).toLowerCase();
|
|
905
905
|
width = defaultDecimal(width);
|
|
906
906
|
if(width <COLUMN_WIDTH/2){
|
|
@@ -929,6 +929,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
929
929
|
});
|
|
930
930
|
restCol.field = header.field;
|
|
931
931
|
restCol.label = defaultStr(header.text,header.label) ;
|
|
932
|
+
restCol.type = type;
|
|
932
933
|
if(!restCol.label){
|
|
933
934
|
console.error(header," has not label or text in datagrid",columns,this.props)
|
|
934
935
|
}
|
|
@@ -957,6 +958,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
957
958
|
delete restCol.sortable;
|
|
958
959
|
filterProps = {
|
|
959
960
|
...restCol,
|
|
961
|
+
type,
|
|
960
962
|
columnIndex,
|
|
961
963
|
visibleColumnIndex,
|
|
962
964
|
sortable:isColumnSortable,
|
|
@@ -986,6 +988,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
986
988
|
}
|
|
987
989
|
this.prepareColumn({
|
|
988
990
|
visible,
|
|
991
|
+
type,
|
|
989
992
|
columnIndex,
|
|
990
993
|
visibleColumnIndex,
|
|
991
994
|
sortable:isColumnSortable,
|
|
@@ -1493,6 +1496,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1493
1496
|
if(!isObj(rowData)) return {render:null,extra:{}};
|
|
1494
1497
|
let _render = null;
|
|
1495
1498
|
columnDef = defaultObj(columnDef);
|
|
1499
|
+
let _type = defaultStr(columnDef.jsType,columnDef.type).trim().toLowerCase();
|
|
1496
1500
|
if(this.isSelectableColumn(columnDef,columnField)){
|
|
1497
1501
|
rowKey = rowKey ? rowKey : this.getRowKey(rowData,rowIndex);
|
|
1498
1502
|
return {render :handleSelectableColumn === false ? null : this.renderSelectableCheckboxCell({
|
|
@@ -1528,7 +1532,6 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1528
1532
|
_render = defaultDecimal(columnDef.multiplicater({...renderArgs,value:rowData[columnField]}),rowData[columnField]);
|
|
1529
1533
|
} else {
|
|
1530
1534
|
_render = defaultValue;
|
|
1531
|
-
let _type = defaultStr(columnDef.type).trim().toLowerCase();
|
|
1532
1535
|
if(defaultStr(columnDef.format).toLowerCase() === 'hashtag'){
|
|
1533
1536
|
_render = <Hashtag>{_render}</Hashtag>
|
|
1534
1537
|
} else if(typeof columnDef.render === "function"){
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import DateLib from "$lib/date";
|
|
4
4
|
import {isNonNullString,defaultStr,isNullOrEmpty,debounce,uniqid} from "$utils";
|
|
5
|
-
import {regexParser,regexActions,getFilterStateValues} from "
|
|
5
|
+
import {regexParser,regexActions,operators as _operators,actions as _actions,periodActions, inActions as _inActions,getFilterStateValues,getSessionData,setSessionData} from "$cfilters";
|
|
6
6
|
import {parseDecimal} from "$ecomponents/TextField";
|
|
7
7
|
import notify from "$notify";
|
|
8
8
|
import PropTypes from "prop-types";
|
|
@@ -15,41 +15,12 @@ import React,{Component as AppComponent} from "$react";
|
|
|
15
15
|
import theme from "$theme";
|
|
16
16
|
import {isMobileMedia} from "$cplatform/dimensions";
|
|
17
17
|
import { ActivityIndicator } from "react-native-paper";
|
|
18
|
-
import { getSessionData,setSessionData } from "./session";
|
|
19
18
|
import DialogProvider from "$components/Form/FormData/DialogProvider";
|
|
20
19
|
|
|
21
20
|
const manualRunKey = "manual-run";
|
|
22
21
|
|
|
23
|
-
export * from "
|
|
22
|
+
export * from "$cfilters";
|
|
24
23
|
|
|
25
|
-
const _actions = {
|
|
26
|
-
'$eq' : 'Egal à',
|
|
27
|
-
"$ne" : 'Défférent de',
|
|
28
|
-
'$gt' : 'Supérieur à',
|
|
29
|
-
'$gte' : 'Supérieur ou égal',
|
|
30
|
-
'$lt' : 'Inférieur à',
|
|
31
|
-
'$lte' : 'Inférieur où égal à',
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const _inActions = {
|
|
35
|
-
'$in' :'Est inc ds la liste', //Array of JSON values The document field must exist in the list provided.
|
|
36
|
-
'$nin' : 'N\'est pas inc ds la liste', //Array of JSON values The document field not must exist in the list provided.
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const _operators = {
|
|
41
|
-
'$and' : 'Et', //Array Matches if all the selectors in the array match.
|
|
42
|
-
'$or' : 'Ou', //Array Matches if any of the selectors in the array match. All selectors must use the same index.
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const periodActions = {
|
|
46
|
-
$yesterday : "Hier",
|
|
47
|
-
$today:"Aujourd'hui",
|
|
48
|
-
$prevWeek:"Semaine passée",
|
|
49
|
-
$week:'Cette semaine',
|
|
50
|
-
$month:'Ce mois',
|
|
51
|
-
$period:"Période"
|
|
52
|
-
}
|
|
53
24
|
|
|
54
25
|
/***** Coposant Filter, pour les filtres de données */
|
|
55
26
|
export default class Filter extends AppComponent {
|
|
@@ -863,7 +863,7 @@ export default class Field extends AppComponent {
|
|
|
863
863
|
delete rest.archivable;
|
|
864
864
|
|
|
865
865
|
this.___formattedField = undefined;
|
|
866
|
-
let _type = this.type = defaultStr(this.props.type,this.type,"text").trim().toLowerCase();
|
|
866
|
+
let _type = this.type = defaultStr(this.props.jsType,this.props.type,this.type,"text").trim().toLowerCase();
|
|
867
867
|
format = defaultStr(format).toLowerCase().trim();
|
|
868
868
|
tooltip = defaultVal(tooltip,title);
|
|
869
869
|
|
|
@@ -959,6 +959,7 @@ Field.propTypes = {
|
|
|
959
959
|
PropTypes.node,
|
|
960
960
|
PropTypes.func,
|
|
961
961
|
]),
|
|
962
|
+
jsType : PropTypes.string,
|
|
962
963
|
usePlaceholderWhenEmpty : PropTypes.bool,//si la valeur du placeholder sera utilée, lorsque la valeur du champ de type formatable est nulle ou égale à la valeur vide
|
|
963
964
|
responsive : PropTypes.bool,
|
|
964
965
|
responsiveProps : PropTypes.object,
|
|
@@ -191,7 +191,7 @@ export default class FormDataComponent extends AppComponent{
|
|
|
191
191
|
content.push(<Divider key = {index} style={theme.styles.w100}/>)
|
|
192
192
|
} else if(isObj(field) && field.form !== false) {
|
|
193
193
|
const name = defaultStr(field.name,field.field,index);
|
|
194
|
-
const type = defaultStr(field.type,"text").trim().toLowerCase().replaceAll("_","");
|
|
194
|
+
const type = defaultStr(field.jsType,field.type,"text").trim().toLowerCase().replaceAll("_","");
|
|
195
195
|
const Component = componentTypes[type] || componentTypes.default;
|
|
196
196
|
let {defaultValue,useDefaultValueFromData,hidden,renderFormDataField,getMediaQueryStyle,printLabels,queryLimit,selected,value,visible,dataFilesInterest,perm,ignore,form,responsiveProps:customResponsiveProps,...rest} = field;
|
|
197
197
|
rest = Object.assign({},rest);
|
|
@@ -61,12 +61,16 @@ const FontIcon = React.forwardRef(({icon,name,testID,color,iconStyle,backgroundC
|
|
|
61
61
|
console.warn("Icone non définie pour le composant FontIcon, icon [{0}], merci de spécifier une icone supportée par la liste du module https://github.com/expo/vector-icons/MaterialCommunityIcons".sprintf(icon),props);
|
|
62
62
|
return null;
|
|
63
63
|
}
|
|
64
|
-
const iconName = icon.ltrim("")
|
|
64
|
+
const iconName = icon.ltrim("material-")
|
|
65
|
+
.ltrim("fa-").ltrim("ant-").ltrim("fontisto-")
|
|
66
|
+
.ltrim("foundation-").ltrim("ionic-").ltrim("octicons-")
|
|
67
|
+
.ltrim("simple-line-").ltrim("zocial-").trim();
|
|
68
|
+
|
|
65
69
|
return <Icon {...props}
|
|
66
70
|
ref = {ref}
|
|
67
71
|
testID = {testID}
|
|
68
72
|
color={color}
|
|
69
|
-
name = {
|
|
73
|
+
name = {iconName}
|
|
70
74
|
backgroundColor = {backgroundColor}
|
|
71
75
|
/>
|
|
72
76
|
});
|
|
@@ -94,7 +98,7 @@ export const isIcon = (name,iconSet)=>{
|
|
|
94
98
|
if(!isNonNullString(name) || !isNonNullString(iconSet)) return false;
|
|
95
99
|
name = name.toLowerCase();
|
|
96
100
|
iconSet = iconSet.toLowerCase().trim();
|
|
97
|
-
return name.startsWith(iconSet+"-")
|
|
101
|
+
return name.startsWith(iconSet+"-") /*|| name.startsWith(iconSet+"s"+"-")*/ ? true : false;
|
|
98
102
|
}
|
|
99
103
|
|
|
100
104
|
export default theme.withStyles(FontIcon,{displayName:FontIcon.displayName,mode:'normal'});
|
|
@@ -160,7 +160,7 @@ const TableComponent = React.forwardRef(({containerProps,renderEmpty,isRowSelect
|
|
|
160
160
|
const scrollContentContainerStyle = {flex:1,width:listWidth,minWidth:totalWidths,height:'100%'};
|
|
161
161
|
const scrollEventThrottle = isMobileNative()?200:50;
|
|
162
162
|
const scrollViewFlexGrow = {flexGrow:0};
|
|
163
|
-
const maxScrollheight = f.length && fFilters.length ? 170 : f.length
|
|
163
|
+
const maxScrollheight = f.length && fFilters.length ? 170 : f.length ?120 : fFilters.length ? 140 : 80;
|
|
164
164
|
const allScrollViewProps = {
|
|
165
165
|
scrollEventThrottle,
|
|
166
166
|
horizontal : true,
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import session from "$session";
|
|
2
|
-
import {getLoggedUserCode} from "$cauth";
|
|
3
|
-
const sKey = "FILTER-ITEM-KEY";
|
|
4
|
-
const sessionKey = ()=> defaultStr(getLoggedUserCode())+"-"+sKey;
|
|
5
|
-
import {defaultObj,defaultStr,isNonNullString} from "$utils";
|
|
6
|
-
|
|
7
|
-
export const getSessionData = (key)=>{
|
|
8
|
-
const data = defaultObj(session.get(sessionKey()));
|
|
9
|
-
return isNonNullString(key)? data [key] : data;
|
|
10
|
-
}
|
|
11
|
-
export const setSessionData = (key,value)=>{
|
|
12
|
-
const data = getSessionData();
|
|
13
|
-
if(isNonNullString(key)){
|
|
14
|
-
data[key] = value;
|
|
15
|
-
return session.set(sessionKey(),data);
|
|
16
|
-
}
|
|
17
|
-
return false;
|
|
18
|
-
}
|
|
@@ -1,552 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import {isNonNullString,defaultStr,defaultArray,isObjOrArray,isObj} from "$utils";
|
|
3
|
-
import DateLib from "$date";
|
|
4
|
-
import mangoParser from "mongo-parse";
|
|
5
|
-
|
|
6
|
-
export const filterTextTypes = ['text','number','email','search','tel','url','password',"id","idfield",'piecefield','piece'];
|
|
7
|
-
|
|
8
|
-
export const regexActions = {
|
|
9
|
-
$regexequals : 'Egal à',
|
|
10
|
-
$regexcontains : 'Contient',
|
|
11
|
-
$regexnotcontains : 'Ne contient pas',
|
|
12
|
-
$regexnotequals : 'Différent de',
|
|
13
|
-
$regexstartswith : 'Commence par',
|
|
14
|
-
$regexendswith : 'Se termine par'
|
|
15
|
-
}
|
|
16
|
-
export const escapeRegexChars = (value)=>{
|
|
17
|
-
//if(value === undefined || value ===null || value === '' || value ==='undefined') return '';
|
|
18
|
-
//value+='';
|
|
19
|
-
if(!isNonNullString(value)) return '';
|
|
20
|
-
let escapeChars = ['!', '^', '$', '(', ')', '[', ']', '{', '}', '?', '+', '*', '.', '/', '\\', '|']
|
|
21
|
-
for(var i in escapeChars){
|
|
22
|
-
value.replace(escapeChars[i],'\\'+escapeChars[i]);
|
|
23
|
-
}
|
|
24
|
-
return value.toString();
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const getFilterStateValues = (state)=>{
|
|
28
|
-
state = defaultObj(state);
|
|
29
|
-
const r = {};
|
|
30
|
-
['defaultValue','action','actions','operator','operators','ignoreCase','value','manualRun'].map((v)=>{
|
|
31
|
-
r[v] = state[v];
|
|
32
|
-
})
|
|
33
|
-
return r;
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**** si le filtre peut être pris en compte */
|
|
38
|
-
export const canHandleFilter = (f)=>{
|
|
39
|
-
if(!isObj(f)) return false;
|
|
40
|
-
if(!isNonNullString(f.operator) || !isNonNullString(f.action)) {
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
if(f.value === undefined || f.value === 'undefined' || f.value ==='' || f.value ===null) {
|
|
44
|
-
return false;
|
|
45
|
-
}
|
|
46
|
-
if(f.value instanceof RegExp){
|
|
47
|
-
return true;
|
|
48
|
-
}
|
|
49
|
-
if(isObjOrArray(f.value) && Object.size(f.value,true) <=0) return false;
|
|
50
|
-
return true;
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export const regexExpressions = {
|
|
55
|
-
notcontains : {
|
|
56
|
-
left : "^((?!(",
|
|
57
|
-
right : ")).)*$",
|
|
58
|
-
/***@see : https://www.w3schools.com/sql/sql_like.asp */
|
|
59
|
-
sql : (string)=>{
|
|
60
|
-
return "%"+defaultStr(string).ltrim("%").rtrim("%")+"%";
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
notequals : {
|
|
64
|
-
left : "^(?!",
|
|
65
|
-
right : "$).*$",
|
|
66
|
-
},
|
|
67
|
-
equals : {
|
|
68
|
-
left : "/^",
|
|
69
|
-
right : '$/'
|
|
70
|
-
},
|
|
71
|
-
startswith : {
|
|
72
|
-
left : "/^",
|
|
73
|
-
right : '/',
|
|
74
|
-
sql : (string)=>{
|
|
75
|
-
return defaultStr(string).rtrim("%")+"%";
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
endswith : {
|
|
79
|
-
left : "",
|
|
80
|
-
right : '$/',
|
|
81
|
-
sql : (string)=>{
|
|
82
|
-
return "%"+defaultStr(string).ltrim("%");
|
|
83
|
-
}
|
|
84
|
-
},
|
|
85
|
-
contains : {
|
|
86
|
-
left : "/",
|
|
87
|
-
right : '/',
|
|
88
|
-
sql : (string)=>{
|
|
89
|
-
return "%"+defaultStr(string).ltrim("%").rtrim("%")+"%";
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
}
|
|
93
|
-
/**** prend en paramètre une chaine de caractère et un nom d'opérateur et génère
|
|
94
|
-
* la chaine de caracètre mango regex correspondant
|
|
95
|
-
*/
|
|
96
|
-
const toMangoRegex = (val,operator)=>{
|
|
97
|
-
if(!isNonNullString(val) || !isNonNullString(operator) || !regexExpressions[operator]) return "";
|
|
98
|
-
const rOp = regexExpressions[operator];
|
|
99
|
-
return rOp.left+escapeRegexChars(val)+rOp.right;
|
|
100
|
-
}
|
|
101
|
-
export const regexParser = {
|
|
102
|
-
equals : (val)=> {
|
|
103
|
-
return toMangoRegex(val,"equals");
|
|
104
|
-
},
|
|
105
|
-
startswith : (val) => {
|
|
106
|
-
return toMangoRegex(val,"startswith");
|
|
107
|
-
},
|
|
108
|
-
endswith : (val) => {
|
|
109
|
-
return toMangoRegex(val,"endswith");
|
|
110
|
-
},
|
|
111
|
-
contains : (val) => {
|
|
112
|
-
return toMangoRegex(val,"contains");
|
|
113
|
-
},
|
|
114
|
-
notequals : (val) => {
|
|
115
|
-
return toMangoRegex(val,"notequals");
|
|
116
|
-
},
|
|
117
|
-
notcontains : (val) =>{
|
|
118
|
-
return toMangoRegex(val,"notcontains");
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
/*** prend une expression regulière et le convertis en operateur, valeur
|
|
122
|
-
* @param {string} la valeur otenue au format regex
|
|
123
|
-
*/
|
|
124
|
-
export const regexDeparser = (regexValue)=>{
|
|
125
|
-
if(!regexValue) return null;
|
|
126
|
-
regexValue = regexValue.toString();
|
|
127
|
-
if(regexValue.endsWith("/i")){
|
|
128
|
-
regexValue = regexValue.rtrim("/i")+"/";
|
|
129
|
-
}
|
|
130
|
-
if(!isNonNullString(regexValue)) return null;
|
|
131
|
-
for(let i in regexExpressions){
|
|
132
|
-
const p = regexExpressions[i];
|
|
133
|
-
let rVal = regexValue.ltrim("/").rtrim("/");
|
|
134
|
-
const pLeft = p.left.ltrim("/"),pRight = p.right.rtrim("/");
|
|
135
|
-
if(rVal.startsWith(pLeft) && rVal.endsWith(pRight)){
|
|
136
|
-
return {
|
|
137
|
-
operator : i,
|
|
138
|
-
value : rVal.ltrim(pLeft).rtrim(pRight),
|
|
139
|
-
regexValue : rVal,
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
|
-
export const matchPouchDBOperator = (operator,value)=>{
|
|
146
|
-
if(!isNonNullString(operator)) return null;
|
|
147
|
-
if(!(value) && !isDecimal(value)) return null;
|
|
148
|
-
switch(operator){
|
|
149
|
-
case "MATCH":
|
|
150
|
-
if(isDecimal(value)) value +="";
|
|
151
|
-
return {operator:"$regex",value:RegExp(defaultStr(regexParser.contains(value)).ltrim("/").rtrim("/"),'i')}
|
|
152
|
-
case "NOTMATCH":
|
|
153
|
-
if(isDecimal(value)) value +="";
|
|
154
|
-
return {operator:"$regex",value:RegExp(defaultStr(regexParser.notcontains(value)).ltrim("/").rtrim("/"),'i')}
|
|
155
|
-
case "EQ" :
|
|
156
|
-
return {operator:'$eq',value}
|
|
157
|
-
case "NEQ" :
|
|
158
|
-
return {operator:"$ne",value}
|
|
159
|
-
case "GT":
|
|
160
|
-
return {operator:"$gt",value}
|
|
161
|
-
case "GTE":
|
|
162
|
-
return {operator:"$gte",value}
|
|
163
|
-
case "LT":
|
|
164
|
-
return {operator:"$lt",value}
|
|
165
|
-
case "LTE":
|
|
166
|
-
return {operator:"$lte",value}
|
|
167
|
-
case "IN":
|
|
168
|
-
return {operator:"$in",value}
|
|
169
|
-
case "NOT IN":
|
|
170
|
-
return {operator:"$in",value}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
let Operators = {
|
|
175
|
-
NONE: null,
|
|
176
|
-
MATCH: {
|
|
177
|
-
name: 'contient',
|
|
178
|
-
func: function(value, term) {
|
|
179
|
-
if(value) {
|
|
180
|
-
return value.toString().search(utils.isRegExp(term) ? term : new RegExp(term, 'i')) >= 0;
|
|
181
|
-
} else {
|
|
182
|
-
return !(!!term);
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
regexpSupported: true
|
|
186
|
-
},
|
|
187
|
-
NOTMATCH: {
|
|
188
|
-
name: 'ne contient pas',
|
|
189
|
-
func: function(value, term) {
|
|
190
|
-
if(value) {
|
|
191
|
-
return value.toString().search(utils.isRegExp(term) ? term : new RegExp(term, 'i')) < 0;
|
|
192
|
-
} else {
|
|
193
|
-
return !!term;
|
|
194
|
-
}
|
|
195
|
-
},
|
|
196
|
-
regexpSupported: true
|
|
197
|
-
},
|
|
198
|
-
EQ: {
|
|
199
|
-
name: '=',
|
|
200
|
-
func: function(value, term) {
|
|
201
|
-
return value == term;
|
|
202
|
-
},
|
|
203
|
-
regexpSupported: false
|
|
204
|
-
},
|
|
205
|
-
NEQ: {
|
|
206
|
-
name: '<>',
|
|
207
|
-
func: function(value, term) {
|
|
208
|
-
return value != term;
|
|
209
|
-
},
|
|
210
|
-
regexpSupported: false
|
|
211
|
-
},
|
|
212
|
-
GT: {
|
|
213
|
-
name: '>',
|
|
214
|
-
func: function(value, term) {
|
|
215
|
-
return value > term;
|
|
216
|
-
},
|
|
217
|
-
regexpSupported: false
|
|
218
|
-
},
|
|
219
|
-
GTE: {
|
|
220
|
-
name: '>=',
|
|
221
|
-
func: function(value, term) {
|
|
222
|
-
return value >= term;
|
|
223
|
-
},
|
|
224
|
-
regexpSupported: false
|
|
225
|
-
},
|
|
226
|
-
LT: {
|
|
227
|
-
name: '<',
|
|
228
|
-
func: function(value, term) {
|
|
229
|
-
return value < term;
|
|
230
|
-
},
|
|
231
|
-
regexpSupported: false
|
|
232
|
-
},
|
|
233
|
-
LTE: {
|
|
234
|
-
name: '<=',
|
|
235
|
-
func: function(value, term) {
|
|
236
|
-
return value <= term;
|
|
237
|
-
},
|
|
238
|
-
regexpSupported: false
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
const utils = {
|
|
242
|
-
ALL: '#All#',
|
|
243
|
-
NONE: '#None#',
|
|
244
|
-
BLANK: '#Blank#"',
|
|
245
|
-
expressionFilter : function(operator, term, staticValue, excludeStatic) {
|
|
246
|
-
var self = this;
|
|
247
|
-
|
|
248
|
-
this.operator = Operators.get(operator);
|
|
249
|
-
this.regexpMode = false;
|
|
250
|
-
this.term = term || null;
|
|
251
|
-
if(this.term && this.operator && this.operator.regexpSupported) {
|
|
252
|
-
if(utils.isRegExp(this.term)) {
|
|
253
|
-
this.regexpMode = true;
|
|
254
|
-
if(!this.term.ignoreCase) {
|
|
255
|
-
this.term = new RegExp(this.term.source, 'i');
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
this.staticValue = staticValue;
|
|
261
|
-
this.excludeStatic = excludeStatic;
|
|
262
|
-
|
|
263
|
-
this.test = function(value) {
|
|
264
|
-
if(Array.isArray(self.staticValue)) {
|
|
265
|
-
var found = self.staticValue.indexOf(value) >= 0;
|
|
266
|
-
return (self.excludeStatic && !found) || (!self.excludeStatic && found);
|
|
267
|
-
} else if(self.term) {
|
|
268
|
-
return self.operator.func(value, self.term);
|
|
269
|
-
} else if(self.staticValue === true || self.staticValue === utils.ALL) {
|
|
270
|
-
return true;
|
|
271
|
-
} else if(self.staticValue === false || self.staticValue === utils.NONE) {
|
|
272
|
-
return false;
|
|
273
|
-
} else {
|
|
274
|
-
return true;
|
|
275
|
-
}
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
this.isAlwaysTrue = function() {
|
|
279
|
-
return !(self.term || Array.isArray(self.staticValue) || self.staticValue === utils.NONE || self.staticValue === false);
|
|
280
|
-
};
|
|
281
|
-
},
|
|
282
|
-
defaultOperator : 'MATCH',
|
|
283
|
-
Operators,
|
|
284
|
-
constants : {},
|
|
285
|
-
items : {
|
|
286
|
-
EQ: Operators.EQ.name,
|
|
287
|
-
MATCH : Operators.MATCH.name,
|
|
288
|
-
NOTMATCH : Operators.NOTMATCH.name,
|
|
289
|
-
NEQ : Operators.NEQ.name,
|
|
290
|
-
GT : Operators.GT.name,
|
|
291
|
-
GTE : Operators.GTE.name,
|
|
292
|
-
LT : Operators.LT.name,
|
|
293
|
-
LTE : Operators.LTE.name
|
|
294
|
-
},
|
|
295
|
-
isRegExp: function(obj) {
|
|
296
|
-
return Object.prototype.toString.apply(obj) === '[object RegExp]';
|
|
297
|
-
},
|
|
298
|
-
/**
|
|
299
|
-
* Escapes all RegExp special characters.
|
|
300
|
-
*/
|
|
301
|
-
escapeRegex: function(re) {
|
|
302
|
-
return re.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
303
|
-
},
|
|
304
|
-
/**** vérifie si la valeur {value}, match la valeur {filterText}
|
|
305
|
-
* @param {object : {
|
|
306
|
-
* value : la valeur à vérifier
|
|
307
|
-
* filterText : le texte à vérifier si value le match
|
|
308
|
-
* operateur : chaine de caractère dans la liste des opérateurs :, props Operators, ci-desous
|
|
309
|
-
* useRegex : Spécifie si l'expression régulière sera utilisée pour la recherche
|
|
310
|
-
* }}
|
|
311
|
-
*/
|
|
312
|
-
match : ({value,filterText,operator,useRegex})=>{
|
|
313
|
-
if(isNonNullString(operator)){
|
|
314
|
-
operator = Operators[operator]
|
|
315
|
-
}
|
|
316
|
-
filterText = defaultStr(filterText);
|
|
317
|
-
operator = defaultObj(operator);
|
|
318
|
-
let isSearchMode = filterText !== '';
|
|
319
|
-
if(operator && isFunction(operator.func)){
|
|
320
|
-
let opterm = operator.regexpSupported && isSearchMode ? (useRegex ? filterText : utils.escapeRegex(filterText)) : filterText;
|
|
321
|
-
return !isSearchMode || operator.func(value, opterm)
|
|
322
|
-
}
|
|
323
|
-
return !isSearchMode ? true : defaultStr(value).toLowerCase().contains(filterText.toLowerCase());
|
|
324
|
-
},
|
|
325
|
-
/**
|
|
326
|
-
* Returns the first element in the array that satisfies the given predicate
|
|
327
|
-
* @param {Array} array the array to search
|
|
328
|
-
* @param {function} predicate Function to apply to each element until it returns true
|
|
329
|
-
* @return {Object} The first object in the array that satisfies the predicate or undefined.
|
|
330
|
-
*/
|
|
331
|
-
findInArray: function(array, predicate) {
|
|
332
|
-
if (this.isArray(array) && predicate) {
|
|
333
|
-
for (var i = 0; i < array.length; i++) {
|
|
334
|
-
var item = array[i];
|
|
335
|
-
if (predicate(item)) {
|
|
336
|
-
return item;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
return undefined;
|
|
341
|
-
},
|
|
342
|
-
/**
|
|
343
|
-
* Returns a JSON string represenation of an object
|
|
344
|
-
* @param {object} obj
|
|
345
|
-
* @return {string}
|
|
346
|
-
*/
|
|
347
|
-
jsonStringify: function(obj, censorKeywords) {
|
|
348
|
-
function censor(key, value) {
|
|
349
|
-
return censorKeywords && censorKeywords.indexOf(key) > -1 ? undefined : value;
|
|
350
|
-
}
|
|
351
|
-
return JSON.stringify(obj, censor, 2);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
for(let i in utils.items){
|
|
356
|
-
utils.constants[i] = i;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
/*** prend en paramètre un objet de filtres et les prépare pour la requête distante
|
|
360
|
-
* @param {object} filtersToPrepare les filtres à exploiter pour la requête distante
|
|
361
|
-
* le tableau des filtres
|
|
362
|
-
* @param {function|object} filter|options, la méthode utilisée pour effectuer un filtre sur les les élément à prendre en compte
|
|
363
|
-
*
|
|
364
|
-
*/
|
|
365
|
-
export const prepareFilters = (filtersToPrepare,opts)=>{
|
|
366
|
-
if(typeof opts =='function'){
|
|
367
|
-
opts = {filter:opts};
|
|
368
|
-
}
|
|
369
|
-
let {filter,convertToSQL:convToSQL} = opts;
|
|
370
|
-
const filters = {}
|
|
371
|
-
filter = typeof filter =='function'? filter : x=>true;
|
|
372
|
-
Object.map(filtersToPrepare,(f,i)=>{
|
|
373
|
-
if(!isObj(f) || !filter(f) || !isNonNullString(f.operator) || !isNonNullString(f.action)) {
|
|
374
|
-
return;
|
|
375
|
-
}
|
|
376
|
-
f.field = defaultStr(f.field,i).trim();
|
|
377
|
-
f.action = defaultStr(f.action).toLowerCase().trim();
|
|
378
|
-
if(f.action =="$today"){
|
|
379
|
-
f.operator = "$and";
|
|
380
|
-
f.action = "$eq"
|
|
381
|
-
}
|
|
382
|
-
filters[f.operator] = defaultArray(filters[f.operator]);
|
|
383
|
-
const ob = {};
|
|
384
|
-
ob[f.field] = {}
|
|
385
|
-
if(f.action == "$period"){
|
|
386
|
-
let sp = defaultStr(f.value);
|
|
387
|
-
if(sp){
|
|
388
|
-
sp = sp.split("=>");
|
|
389
|
-
const isValid1 = DateLib.isValidSQLDate(sp[0]) || DateLib.isValidSQLDateTime(sp[0]);
|
|
390
|
-
const isValid2 = DateLib.isValidSQLDate(sp[1]) || DateLib.isValidSQLDateTime(sp[1]);
|
|
391
|
-
if(isValid1 && isValid2){
|
|
392
|
-
filters[f.operator].push({
|
|
393
|
-
[f.field] : {$gte:sp[0]}
|
|
394
|
-
})
|
|
395
|
-
filters[f.operator].push({
|
|
396
|
-
[f.field] : {$lte:sp[1]}
|
|
397
|
-
})
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
} else {
|
|
401
|
-
ob[f.field][f.action] = f.value;
|
|
402
|
-
filters[f.operator].push(ob)
|
|
403
|
-
}
|
|
404
|
-
});
|
|
405
|
-
return convToSQL ? convertToSQL(filters) : filters;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/*** la liste des actions supportés par les filtres
|
|
409
|
-
* @see : https://github.com/cloudant/mango from mango query mapping
|
|
410
|
-
*
|
|
411
|
-
*/
|
|
412
|
-
export const actions = ["$lt", "$gt", "$lte", "$gte", "$eq", "$exists", "$type", "$in", "$nin", "$all", "$size", "$or", "$nor", "$not", "$mod", "$regex", "$elemMatch"]
|
|
413
|
-
|
|
414
|
-
export default utils;
|
|
415
|
-
|
|
416
|
-
/*** convertis les filtres pris au format mangoesQuey, au format de sortie SQL
|
|
417
|
-
* @see : https://github.com/gordonBusyman/mongo-to-sql-converter
|
|
418
|
-
* @param {object} filters, les filtres au format mango query à convertir au format SQL
|
|
419
|
-
*/
|
|
420
|
-
export const convertToSQL = (filters)=>{
|
|
421
|
-
if(!isObjOrArray(filters)) return [];
|
|
422
|
-
const whereParsed = mangoParser.parse(filters)
|
|
423
|
-
return whereParsed.parts.reduce((prev, curr) => {
|
|
424
|
-
const c = whereClauseToSQL(curr);
|
|
425
|
-
return c ? [...prev,c] : prev;
|
|
426
|
-
}, []).map((filter)=>{
|
|
427
|
-
if(filter.field === MANGO_QUERY_OPERATOR){
|
|
428
|
-
delete filter.field;
|
|
429
|
-
}
|
|
430
|
-
return filter;
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
export const MANGO_QUERY_OPERATOR = "MANGO_QUERY_OPERATOR";
|
|
434
|
-
const whereClauseToSQL = (currentMongoParserElement) => {
|
|
435
|
-
let { field, operator, operand } = currentMongoParserElement;
|
|
436
|
-
if(!isNonNullString(operator) || !operatorsMap[operator]) return null;
|
|
437
|
-
operator = operatorsMap[operator]
|
|
438
|
-
if(operator == 'LIKE'){
|
|
439
|
-
const deparsed = regexDeparser(operand);
|
|
440
|
-
if(!isObj(deparsed)){
|
|
441
|
-
return null;
|
|
442
|
-
}
|
|
443
|
-
operand = deparsed.value;
|
|
444
|
-
const deparsedOp = deparsed.operator;
|
|
445
|
-
if(deparsedOp =='notcontains'){
|
|
446
|
-
operator = "NOT LIKE";
|
|
447
|
-
}
|
|
448
|
-
if(deparsedOp =='equals'){
|
|
449
|
-
operator = operatorsMap.$eq;
|
|
450
|
-
} else if(deparsedOp =='notequals'){
|
|
451
|
-
operator = operatorsMap.$ne;
|
|
452
|
-
} else{
|
|
453
|
-
const opMap = regexExpressions[deparsedOp];
|
|
454
|
-
if(!opMap || typeof opMap.sql !=='function') return null;
|
|
455
|
-
operand = opMap.sql(operand);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
// AND or OR operators with nested elements
|
|
459
|
-
if (typeof field === 'undefined') {
|
|
460
|
-
// parse nested elements
|
|
461
|
-
const nested = operand.reduce((prev, curr) => {
|
|
462
|
-
const parsed = mangoParser.parse(curr);
|
|
463
|
-
const prepared = whereClauseToSQL(parsed.parts[0]);
|
|
464
|
-
if(prepared){
|
|
465
|
-
return [...prev,prepared]
|
|
466
|
-
}
|
|
467
|
-
return prev;
|
|
468
|
-
}, [])
|
|
469
|
-
|
|
470
|
-
// nested WHERE element
|
|
471
|
-
return {
|
|
472
|
-
field: MANGO_QUERY_OPERATOR,
|
|
473
|
-
operator,
|
|
474
|
-
operand: nested
|
|
475
|
-
}
|
|
476
|
-
}
|
|
477
|
-
// simple WHERE element
|
|
478
|
-
return {
|
|
479
|
-
field,
|
|
480
|
-
operator,
|
|
481
|
-
operand
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
// map mongoDB -> SQL operators
|
|
486
|
-
const operatorsMap = {
|
|
487
|
-
$or: 'OR',
|
|
488
|
-
$and: 'AND',
|
|
489
|
-
$lt: '<',
|
|
490
|
-
$lte: '<=',
|
|
491
|
-
$gt: '>',
|
|
492
|
-
$gte: '>=',
|
|
493
|
-
$ne: '!=',
|
|
494
|
-
$in: 'IN',
|
|
495
|
-
$nin : 'NOT IN',
|
|
496
|
-
$eq: '=',
|
|
497
|
-
$regex : "LIKE"
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
/**
|
|
501
|
-
*
|
|
502
|
-
* @param {*} operand
|
|
503
|
-
* @param {*} operator
|
|
504
|
-
* @param {*} field
|
|
505
|
-
*
|
|
506
|
-
* Return the operand in right format
|
|
507
|
-
*/
|
|
508
|
-
export const getTyppedOperand = (operand, operator, field) => {
|
|
509
|
-
if (typeof operand === 'string') { // wrap strings in double quots
|
|
510
|
-
return "'" +(operand) + "'"
|
|
511
|
-
} else if (operator === 'IN' || operator =='NOT IN') { // wrap IN arguments in brackers
|
|
512
|
-
operand = Array.isArray(operand)? operand.map(op => getTyppedOperand(op, null, null))
|
|
513
|
-
.join(', '): operand;
|
|
514
|
-
return '(' + operand + ')'
|
|
515
|
-
} else if (!isNonNullString(field) && Array.isArray(operand)) { // AND or OR elements
|
|
516
|
-
// recursively call 'buildWhereElement' for nested elements
|
|
517
|
-
// join each element with operator AND or OR
|
|
518
|
-
return operand.reduce((prev, curr) => {
|
|
519
|
-
return [...prev, buildWhereElement(curr)]
|
|
520
|
-
}, []).join(' ' + operator + ' ')
|
|
521
|
-
} else {
|
|
522
|
-
return operand
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
/**
|
|
527
|
-
*
|
|
528
|
-
* @param {*} elem
|
|
529
|
-
*
|
|
530
|
-
* Return element of WHERE clause
|
|
531
|
-
*/
|
|
532
|
-
export const buildWhereElement = (elem) => {
|
|
533
|
-
const { field, operator, operand } = elem
|
|
534
|
-
if (!isNonNullString(field)) { // nested WHERE element
|
|
535
|
-
return '(' + getTyppedOperand(operand, operator, field) + ')'
|
|
536
|
-
} else { // simple WHERE element
|
|
537
|
-
return field + ' ' + operator + ' ' + getTyppedOperand(operand, operator, field)
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
/**** construit une requête Where à partir des filtres préparé dans le tableau whereClausePrepared
|
|
542
|
-
* @see : https://github.com/gordonBusyman/mongo-to-sql-converter
|
|
543
|
-
* @parm {array} whereClausePrepared, les filtres préparés avec la méthode prepareFilters puis convertis avec la fonction convertToSQL
|
|
544
|
-
@return {string}, la requête Where correspondante
|
|
545
|
-
*/
|
|
546
|
-
export const buildWhere = (whereClausePrepared)=>{
|
|
547
|
-
if(!Array.isArray(whereClausePrepared)) return null;
|
|
548
|
-
// build WHERE string clause by adding each element of array to it, separated with AND
|
|
549
|
-
return whereClausePrepared.reduce((prev, curr) => [
|
|
550
|
-
...prev, buildWhereElement(curr)
|
|
551
|
-
], []).join(' AND ');
|
|
552
|
-
}
|