From 8aa02022c1d1217aa4b6dd398e59c9128bb72e26 Mon Sep 17 00:00:00 2001
From: Kevin Jackson <30411845+KevinJJackson@users.noreply.github.com>
Date: Fri, 8 Sep 2023 10:40:41 -0400
Subject: [PATCH] enhancement/submittals-table (#187)
---
package-lock.json | 141 +++++------
package.json | 3 +-
src/app-bundles/chart-editor-bundle.js | 30 ++-
src/app-bundles/district-rollup-bundle.js | 11 +-
src/app-bundles/inclinometer-measurements.js | 36 ++-
src/app-bundles/submittals-bundle.js | 19 +-
.../time-series-measurements-bundle.js | 3 +-
src/app-components/button/button.jsx | 2 +-
src/app-components/chart/minify-plotly.js | 4 +
src/app-components/table/table.jsx | 150 ++++++++----
.../instrument/timeseries/timeseries.jsx | 3 +-
.../project/batch-plotting/batch-plotting.jsx | 70 +++++-
.../batch-plot-chart-settings.jsx | 121 +++++++---
.../{ => components}/batch-plot-errors.jsx | 0
.../{ => components}/configuration-panel.jsx | 4 +-
.../{ => components}/data-configuration.jsx | 10 +-
.../{ => components}/print-button.jsx | 8 +-
src/app-pages/project/batch-plotting/index.js | 2 +-
.../{ => tab-content}/batch-plot-chart.jsx | 33 +--
.../tab-content/depth-chart.jsx | 219 ++++++++++++++++++
.../components/modals/districtRollupModal.jsx | 32 ++-
.../components/modals/newEvaluationModal.jsx | 2 +-
.../components/tables/submittalsTable.jsx | 106 ++++++---
23 files changed, 779 insertions(+), 230 deletions(-)
rename src/app-pages/project/batch-plotting/{ => components}/batch-plot-chart-settings.jsx (63%)
rename src/app-pages/project/batch-plotting/{ => components}/batch-plot-errors.jsx (100%)
rename src/app-pages/project/batch-plotting/{ => components}/configuration-panel.jsx (96%)
rename src/app-pages/project/batch-plotting/{ => components}/data-configuration.jsx (93%)
rename src/app-pages/project/batch-plotting/{ => components}/print-button.jsx (92%)
rename src/app-pages/project/batch-plotting/{ => tab-content}/batch-plot-chart.jsx (79%)
create mode 100644 src/app-pages/project/batch-plotting/tab-content/depth-chart.jsx
diff --git a/package-lock.json b/package-lock.json
index 088954ab..9a143029 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,6 +15,7 @@
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.14.0",
+ "@mui/material": "^5.14.2",
"@tanstack/react-table": "^8.9.3",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
@@ -1492,15 +1493,14 @@
}
},
"node_modules/@mui/base": {
- "version": "5.0.0-beta.7",
- "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.7.tgz",
- "integrity": "sha512-Pjbwm6gjiS96kOMF7E5fjEJsenc0tZBesrLQ4rrdi3eT/c/yhSWnPbCUkHSz8bnS0l3/VQ8bA+oERSGSV2PK6A==",
- "peer": true,
+ "version": "5.0.0-beta.8",
+ "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.8.tgz",
+ "integrity": "sha512-b4vVjMZx5KzzEMf4arXKoeV5ZegAMOoPwoy1vfUBwhvXc2QtaaAyBp50U7OA2L06Leubc1A+lEp3eqwZoFn87g==",
"dependencies": {
- "@babel/runtime": "^7.22.5",
+ "@babel/runtime": "^7.22.6",
"@emotion/is-prop-valid": "^1.2.1",
"@mui/types": "^7.2.4",
- "@mui/utils": "^5.13.7",
+ "@mui/utils": "^5.14.1",
"@popperjs/core": "^2.11.8",
"clsx": "^1.2.1",
"prop-types": "^15.8.1",
@@ -1527,14 +1527,12 @@
"node_modules/@mui/base/node_modules/react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "peer": true
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
"node_modules/@mui/core-downloads-tracker": {
- "version": "5.14.0",
- "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.0.tgz",
- "integrity": "sha512-SYBOVCatVDUf/lbrLGah09bHhX5WfUXg7kSskfLILr6SvKRni0NLp0aonxQ0SMALVVK3Qwa6cW4CdWuwS0gC1w==",
- "peer": true,
+ "version": "5.14.2",
+ "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.2.tgz",
+ "integrity": "sha512-x+c/MgDL1t/IIy5lDbMlrDouFG5DYZbl3DP4dbbuhlpPFBnE9glYwmJEee/orVHQpOPwLxCAIWQs+2DKSaBVWQ==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui"
@@ -1566,17 +1564,16 @@
}
},
"node_modules/@mui/material": {
- "version": "5.14.0",
- "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.0.tgz",
- "integrity": "sha512-HP7CP71NhMkui2HUIEKl2/JfuHMuoarSUWAKlNw6s17bl/Num9rN61EM6uUzc2A2zHjj/00A66GnvDnmixEJEw==",
- "peer": true,
- "dependencies": {
- "@babel/runtime": "^7.22.5",
- "@mui/base": "5.0.0-beta.7",
- "@mui/core-downloads-tracker": "^5.14.0",
- "@mui/system": "^5.14.0",
+ "version": "5.14.2",
+ "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.2.tgz",
+ "integrity": "sha512-TgNR4/YRL11RifsnMWNhITNCkGJYVz20SCvVJBBoU5Y/KhUNSSJxjDpEB8VrnY+sUsV0NigLCkHZJglfsiS3Pw==",
+ "dependencies": {
+ "@babel/runtime": "^7.22.6",
+ "@mui/base": "5.0.0-beta.8",
+ "@mui/core-downloads-tracker": "^5.14.2",
+ "@mui/system": "^5.14.1",
"@mui/types": "^7.2.4",
- "@mui/utils": "^5.13.7",
+ "@mui/utils": "^5.14.1",
"@types/react-transition-group": "^4.4.6",
"clsx": "^1.2.1",
"csstype": "^3.1.2",
@@ -1613,14 +1610,12 @@
"node_modules/@mui/material/node_modules/react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "peer": true
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
"node_modules/@mui/private-theming": {
"version": "5.13.7",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.13.7.tgz",
"integrity": "sha512-qbSr+udcij5F9dKhGX7fEdx2drXchq7htLNr2Qg2Ma+WJ6q0ERlEqGSBiPiVDJkptcjeVL4DGmcf1wl5+vD4EA==",
- "peer": true,
"dependencies": {
"@babel/runtime": "^7.22.5",
"@mui/utils": "^5.13.7",
@@ -1647,7 +1642,6 @@
"version": "5.13.2",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.13.2.tgz",
"integrity": "sha512-VCYCU6xVtXOrIN8lcbuPmoG+u7FYuOERG++fpY74hPpEWkyFQG97F+/XfTQVYzlR2m7nPjnwVUgATcTCMEaMvw==",
- "peer": true,
"dependencies": {
"@babel/runtime": "^7.21.0",
"@emotion/cache": "^11.11.0",
@@ -1676,16 +1670,15 @@
}
},
"node_modules/@mui/system": {
- "version": "5.14.0",
- "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.0.tgz",
- "integrity": "sha512-0HZGkX8miJbiNw+rjlZ9l0Cfkz1bSqfSHQH0EH9J+nx0aAm5cBleg9piOlLdCNIWGgecCqsw4x62erGrGjjcJg==",
- "peer": true,
+ "version": "5.14.1",
+ "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.1.tgz",
+ "integrity": "sha512-u+xlsU34Jdkgx1CxmBnIC4Y08uPdVX5iEd3S/1dggDFtOGp+Lj8xmKRJAQ8PJOOJLOh8pDwaZx4AwXikL4l1QA==",
"dependencies": {
- "@babel/runtime": "^7.22.5",
+ "@babel/runtime": "^7.22.6",
"@mui/private-theming": "^5.13.7",
"@mui/styled-engine": "^5.13.2",
"@mui/types": "^7.2.4",
- "@mui/utils": "^5.13.7",
+ "@mui/utils": "^5.14.1",
"clsx": "^1.2.1",
"csstype": "^3.1.2",
"prop-types": "^15.8.1"
@@ -1719,7 +1712,6 @@
"version": "7.2.4",
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.4.tgz",
"integrity": "sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA==",
- "peer": true,
"peerDependencies": {
"@types/react": "*"
},
@@ -1730,12 +1722,11 @@
}
},
"node_modules/@mui/utils": {
- "version": "5.13.7",
- "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.13.7.tgz",
- "integrity": "sha512-/3BLptG/q0u36eYED7Nhf4fKXmcKb6LjjT7ZMwhZIZSdSxVqDqSTmATW3a56n3KEPQUXCU9TpxAfCBQhs6brVA==",
- "peer": true,
+ "version": "5.14.1",
+ "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.1.tgz",
+ "integrity": "sha512-39KHKK2JeqRmuUcLDLwM+c2XfVC136C5/yUyQXmO2PVbOb2Bol4KxtkssEqCbTwg87PSCG3f1Tb0keRsK7cVGw==",
"dependencies": {
- "@babel/runtime": "^7.22.5",
+ "@babel/runtime": "^7.22.6",
"@types/prop-types": "^15.7.5",
"@types/react-is": "^18.2.1",
"prop-types": "^15.8.1",
@@ -1755,8 +1746,7 @@
"node_modules/@mui/utils/node_modules/react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "peer": true
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
"node_modules/@nicolo-ribaudo/eslint-scope-5-internals": {
"version": "5.1.1-v1",
@@ -2216,7 +2206,6 @@
"version": "18.2.1",
"resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-18.2.1.tgz",
"integrity": "sha512-wyUkmaaSZEzFZivD8F2ftSyAfk6L+DfFliVj/mYdOXbVjRcS87fQJLTnhk6dRZPuJjI+9g6RZJO4PNCngUrmyw==",
- "peer": true,
"dependencies": {
"@types/react": "*"
}
@@ -9865,15 +9854,14 @@
"version": "3.1.0"
},
"@mui/base": {
- "version": "5.0.0-beta.7",
- "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.7.tgz",
- "integrity": "sha512-Pjbwm6gjiS96kOMF7E5fjEJsenc0tZBesrLQ4rrdi3eT/c/yhSWnPbCUkHSz8bnS0l3/VQ8bA+oERSGSV2PK6A==",
- "peer": true,
+ "version": "5.0.0-beta.8",
+ "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.8.tgz",
+ "integrity": "sha512-b4vVjMZx5KzzEMf4arXKoeV5ZegAMOoPwoy1vfUBwhvXc2QtaaAyBp50U7OA2L06Leubc1A+lEp3eqwZoFn87g==",
"requires": {
- "@babel/runtime": "^7.22.5",
+ "@babel/runtime": "^7.22.6",
"@emotion/is-prop-valid": "^1.2.1",
"@mui/types": "^7.2.4",
- "@mui/utils": "^5.13.7",
+ "@mui/utils": "^5.14.1",
"@popperjs/core": "^2.11.8",
"clsx": "^1.2.1",
"prop-types": "^15.8.1",
@@ -9883,16 +9871,14 @@
"react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "peer": true
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
}
}
},
"@mui/core-downloads-tracker": {
- "version": "5.14.0",
- "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.0.tgz",
- "integrity": "sha512-SYBOVCatVDUf/lbrLGah09bHhX5WfUXg7kSskfLILr6SvKRni0NLp0aonxQ0SMALVVK3Qwa6cW4CdWuwS0gC1w==",
- "peer": true
+ "version": "5.14.2",
+ "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.2.tgz",
+ "integrity": "sha512-x+c/MgDL1t/IIy5lDbMlrDouFG5DYZbl3DP4dbbuhlpPFBnE9glYwmJEee/orVHQpOPwLxCAIWQs+2DKSaBVWQ=="
},
"@mui/icons-material": {
"version": "5.14.0",
@@ -9903,17 +9889,16 @@
}
},
"@mui/material": {
- "version": "5.14.0",
- "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.0.tgz",
- "integrity": "sha512-HP7CP71NhMkui2HUIEKl2/JfuHMuoarSUWAKlNw6s17bl/Num9rN61EM6uUzc2A2zHjj/00A66GnvDnmixEJEw==",
- "peer": true,
- "requires": {
- "@babel/runtime": "^7.22.5",
- "@mui/base": "5.0.0-beta.7",
- "@mui/core-downloads-tracker": "^5.14.0",
- "@mui/system": "^5.14.0",
+ "version": "5.14.2",
+ "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.2.tgz",
+ "integrity": "sha512-TgNR4/YRL11RifsnMWNhITNCkGJYVz20SCvVJBBoU5Y/KhUNSSJxjDpEB8VrnY+sUsV0NigLCkHZJglfsiS3Pw==",
+ "requires": {
+ "@babel/runtime": "^7.22.6",
+ "@mui/base": "5.0.0-beta.8",
+ "@mui/core-downloads-tracker": "^5.14.2",
+ "@mui/system": "^5.14.1",
"@mui/types": "^7.2.4",
- "@mui/utils": "^5.13.7",
+ "@mui/utils": "^5.14.1",
"@types/react-transition-group": "^4.4.6",
"clsx": "^1.2.1",
"csstype": "^3.1.2",
@@ -9925,8 +9910,7 @@
"react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "peer": true
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
}
}
},
@@ -9934,7 +9918,6 @@
"version": "5.13.7",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.13.7.tgz",
"integrity": "sha512-qbSr+udcij5F9dKhGX7fEdx2drXchq7htLNr2Qg2Ma+WJ6q0ERlEqGSBiPiVDJkptcjeVL4DGmcf1wl5+vD4EA==",
- "peer": true,
"requires": {
"@babel/runtime": "^7.22.5",
"@mui/utils": "^5.13.7",
@@ -9945,7 +9928,6 @@
"version": "5.13.2",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.13.2.tgz",
"integrity": "sha512-VCYCU6xVtXOrIN8lcbuPmoG+u7FYuOERG++fpY74hPpEWkyFQG97F+/XfTQVYzlR2m7nPjnwVUgATcTCMEaMvw==",
- "peer": true,
"requires": {
"@babel/runtime": "^7.21.0",
"@emotion/cache": "^11.11.0",
@@ -9954,16 +9936,15 @@
}
},
"@mui/system": {
- "version": "5.14.0",
- "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.0.tgz",
- "integrity": "sha512-0HZGkX8miJbiNw+rjlZ9l0Cfkz1bSqfSHQH0EH9J+nx0aAm5cBleg9piOlLdCNIWGgecCqsw4x62erGrGjjcJg==",
- "peer": true,
+ "version": "5.14.1",
+ "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.1.tgz",
+ "integrity": "sha512-u+xlsU34Jdkgx1CxmBnIC4Y08uPdVX5iEd3S/1dggDFtOGp+Lj8xmKRJAQ8PJOOJLOh8pDwaZx4AwXikL4l1QA==",
"requires": {
- "@babel/runtime": "^7.22.5",
+ "@babel/runtime": "^7.22.6",
"@mui/private-theming": "^5.13.7",
"@mui/styled-engine": "^5.13.2",
"@mui/types": "^7.2.4",
- "@mui/utils": "^5.13.7",
+ "@mui/utils": "^5.14.1",
"clsx": "^1.2.1",
"csstype": "^3.1.2",
"prop-types": "^15.8.1"
@@ -9973,16 +9954,14 @@
"version": "7.2.4",
"resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.4.tgz",
"integrity": "sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA==",
- "peer": true,
"requires": {}
},
"@mui/utils": {
- "version": "5.13.7",
- "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.13.7.tgz",
- "integrity": "sha512-/3BLptG/q0u36eYED7Nhf4fKXmcKb6LjjT7ZMwhZIZSdSxVqDqSTmATW3a56n3KEPQUXCU9TpxAfCBQhs6brVA==",
- "peer": true,
+ "version": "5.14.1",
+ "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.1.tgz",
+ "integrity": "sha512-39KHKK2JeqRmuUcLDLwM+c2XfVC136C5/yUyQXmO2PVbOb2Bol4KxtkssEqCbTwg87PSCG3f1Tb0keRsK7cVGw==",
"requires": {
- "@babel/runtime": "^7.22.5",
+ "@babel/runtime": "^7.22.6",
"@types/prop-types": "^15.7.5",
"@types/react-is": "^18.2.1",
"prop-types": "^15.8.1",
@@ -9992,8 +9971,7 @@
"react-is": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "peer": true
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
}
}
},
@@ -10328,7 +10306,6 @@
"version": "18.2.1",
"resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-18.2.1.tgz",
"integrity": "sha512-wyUkmaaSZEzFZivD8F2ftSyAfk6L+DfFliVj/mYdOXbVjRcS87fQJLTnhk6dRZPuJjI+9g6RZJO4PNCngUrmyw==",
- "peer": true,
"requires": {
"@types/react": "*"
}
diff --git a/package.json b/package.json
index 90834eea..58af9a44 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "hhd-ui",
- "version": "0.13.2",
+ "version": "0.13.3",
"private": true,
"dependencies": {
"@ag-grid-community/client-side-row-model": "^30.0.3",
@@ -10,6 +10,7 @@
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@mui/icons-material": "^5.14.0",
+ "@mui/material": "^5.14.2",
"@tanstack/react-table": "^8.9.3",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
diff --git a/src/app-bundles/chart-editor-bundle.js b/src/app-bundles/chart-editor-bundle.js
index 3bffe54e..946bd459 100644
--- a/src/app-bundles/chart-editor-bundle.js
+++ b/src/app-bundles/chart-editor-bundle.js
@@ -286,6 +286,7 @@ const chartEditorBundle = {
Object.keys(dataByInstrumentId).forEach((id) => {
const { timeseries } = dataByInstrumentId[id];
+
if (!timeseries || !timeseries.length) return undefined;
timeseries.sort((a, b) => {
@@ -300,7 +301,7 @@ const chartEditorBundle = {
const x = [];
const y = [];
- let plotData = [];
+ const plotData = [];
if (isInclinometer) {
const negateDepth = val => val < 0 ? val : -val;
@@ -339,18 +340,18 @@ const chartEditorBundle = {
y.push(item.value);
});
- plotData = [{
+ plotData.push({
type: 'scattergl',
name: `${instrumentName} - ${name}`,
x: x,
y: y,
...style,
- }];
+ });
}
const domainName = getDomainName(domains, parameter_id);
- if (!chartData.find(y => y.name === parameter_id)) {
+ if (!chartData.find(x => x.name === parameter_id)) {
chartData.push({
id: series.id,
name: parameter_id,
@@ -358,10 +359,7 @@ const chartEditorBundle = {
unit: unit_id,
data: plotData,
});
- } else if (
- chartData.find(x => x.name === parameter_id).unit !== unit_id &&
- chartData.findIndex(y => y.name === parameter_id) !== -1
- ) {
+ } else if (chartData.find(x => x.name === parameter_id).unit !== unit_id && chartData.findIndex(y => y.name === parameter_id) !== -1) {
chartData.push({
id: series.id,
name: parameter_id,
@@ -370,15 +368,25 @@ const chartEditorBundle = {
data: plotData,
});
} else {
- const found = chartData.find(x => x.name === parameter_id);
- found.id = series.id;
- found.data.concat(plotData);
+ const foundIndex = chartData.findIndex(x => x.name === parameter_id);
+ const item = chartData[foundIndex];
+
+ chartData.splice(foundIndex, 1);
+
+ chartData.push({
+ id: series.id,
+ name: parameter_id,
+ domainName,
+ unit: unit_id,
+ data: [...item.data, ...plotData],
+ });
}
});
});
if (showRainfall) {
chartData.push(...rainfallData);
}
+
return chartData;
}
),
diff --git a/src/app-bundles/district-rollup-bundle.js b/src/app-bundles/district-rollup-bundle.js
index b323cfcc..0f7caaa6 100644
--- a/src/app-bundles/district-rollup-bundle.js
+++ b/src/app-bundles/district-rollup-bundle.js
@@ -24,11 +24,18 @@ export default {
selectDistrictRollupMeasurement: (state) => state.districtRollup.measurement,
// one of [`evaluation`, `measurement`]
- doFetchDistrictRollup: (type) => ({ dispatch, store, apiGet }) => {
+ doFetchDistrictRollup: (type, fromDate = '', toDate = '') => ({ dispatch, store, apiGet }) => {
dispatch({ type: 'ROLLUP_FETCH_START' });
const { projectId } = store.selectProjectsIdByRoute();
- const url = `/projects/${projectId}/district_rollup/${type}_submittals`;
+ let query = '';
+ if (fromDate && toDate) {
+ const formattedFrom = fromDate.toISOString();
+ const formattedTo = toDate.toISOString();
+ query = `?from_timestamp_month=${formattedFrom}&to_timestamp_month=${formattedTo}`;
+ }
+
+ const url = `/projects/${projectId}/district_rollup/${type}_submittals${query}`;
apiGet(url, (err, body) => {
if (err) {
diff --git a/src/app-bundles/inclinometer-measurements.js b/src/app-bundles/inclinometer-measurements.js
index 28e8c25d..dce469fd 100644
--- a/src/app-bundles/inclinometer-measurements.js
+++ b/src/app-bundles/inclinometer-measurements.js
@@ -10,7 +10,6 @@ export default createRestBundle({
// TODO: default before and after time periods should be implemented on
// the backend.
getTemplate: '/timeseries/:timeseriesId/inclinometer_measurements?before=2025-01-01T00:00:00.00Z&after=1900-01-01T00:00:00.00Z',
-
putTemplate: '',
postTemplate: '/timeseries/:timeseriesId/inclinometer_measurements',
deleteTemplate: '/timeseries/:timeseriesId/inclinometer_measurements?time={:item.date}',
@@ -33,4 +32,39 @@ export default createRestBundle({
return whitelist.includes(hash) || pathnameWhitelist.some(elem => url.pathname.includes(elem));
},
+ addons: {
+ doFetchInclinometerMeasurementsByTimeseriesId: (timeseriesId) => ({ dispatch, apiGet }) => {
+ const uri = `/timeseries/${timeseriesId}/inclinometer_measurements?before=2025-01-01T00:00:00.00Z&after=1900-01-01T00:00:00.00Z`;
+
+ apiGet(uri, (err, body) => {
+ if (err) {
+ // eslint-disable-next-line no-console
+ console.log('error: ', err);
+ } else {
+ dispatch({
+ type: 'SET_CURRENT_INCLINOMETER_MEASUREMENTS',
+ payload: {
+ timeseriesId,
+ measurements: body,
+ },
+ });
+ }
+ });
+ },
+
+ selectCurrentInclinometerMeasurements: state => state.inclinometerMeasurements.currentMeasurements,
+ },
+ reduceFurther: (state, { type, payload }) => {
+ if (type === 'SET_CURRENT_INCLINOMETER_MEASUREMENTS') {
+ return {
+ ...state,
+ 'currentMeasurements': {
+ ...state['currentMeasurements'],
+ [payload.timeseriesId]: payload.measurements,
+ },
+ };
+ } else {
+ return state;
+ }
+ },
});
diff --git a/src/app-bundles/submittals-bundle.js b/src/app-bundles/submittals-bundle.js
index 36cc0833..a9702658 100644
--- a/src/app-bundles/submittals-bundle.js
+++ b/src/app-bundles/submittals-bundle.js
@@ -95,10 +95,27 @@ export default {
} else {
store.doFetchMissingSubmittalsByProjectId();
store.doFetchProjectAlertConfigs();
- // store.doFetchAlertConfigSubmittals(alertConfigId);
}
dispatch({ type: 'PUT_VERIFY_ALL_MISSING_SUBMITTALS_FINISHED' });
});
},
+
+ doVerifySingleSubmittals: (submittalId) => ({ dispatch, store, apiPut }) => {
+ dispatch({ type: 'PUT_VERIFY_SINGLE_SUBMITTAL_START' });
+
+ const url = `/submittals/${submittalId}/verify_missing`;
+
+ apiPut(url, {}, (err, _body) => {
+ if (err) {
+ // eslint-disable-next-line no-console
+ console.log('error: ', err);
+ } else {
+ store.doFetchHistoricalSubmittalsByProjectId();
+ store.doFetchProjectAlertConfigs();
+ }
+
+ dispatch({ type: 'PUT_VERIFY_SINGLE_SUBMITTAL_FISISHED' });
+ });
+ },
};
diff --git a/src/app-bundles/time-series-measurements-bundle.js b/src/app-bundles/time-series-measurements-bundle.js
index f66e6655..d3b16424 100644
--- a/src/app-bundles/time-series-measurements-bundle.js
+++ b/src/app-bundles/time-series-measurements-bundle.js
@@ -41,6 +41,7 @@ export default createRestBundle({
doTimeseriesMeasurementsFetchById: ({
timeseriesId,
dateRange,
+ threshold = 0,
}) => ({ dispatch, store, apiGet }) => {
dispatch({ type: 'TIMESERIES_FETCH_BY_ID_START', payload: {} });
const [after, before] = dateRange;
@@ -48,7 +49,7 @@ export default createRestBundle({
const isoAfter = after ? after.toISOString() : afterDate;
const isoBefore = before ? before.toISOString() : beforeDate;
- const url = `/timeseries/${timeseriesId}/measurements?after=${isoAfter}&before=${isoBefore}`;
+ const url = `/timeseries/${timeseriesId}/measurements?after=${isoAfter}&before=${isoBefore}&threshold=${threshold}`;
const flags = store['selectTimeseriesMeasurementsFlags']();
const itemsById = store['selectTimeseriesMeasurementsItemsObject']();
let fetchCount = store['selectTimeseriesMeasurementsFetchCount']();
diff --git a/src/app-components/button/button.jsx b/src/app-components/button/button.jsx
index f82c108b..e1055816 100644
--- a/src/app-components/button/button.jsx
+++ b/src/app-components/button/button.jsx
@@ -42,6 +42,7 @@ const Button = ({
]);
const buttonProps = {
+ style: { zIndex: 'auto' },
className: classes,
role: 'button',
type,
@@ -60,7 +61,6 @@ const Button = ({
>
);
- // @ts-ignore
return React.createElement(elem, buttonProps, );
};
diff --git a/src/app-components/chart/minify-plotly.js b/src/app-components/chart/minify-plotly.js
index d0502a00..4d88ab1e 100644
--- a/src/app-components/chart/minify-plotly.js
+++ b/src/app-components/chart/minify-plotly.js
@@ -1,6 +1,8 @@
import * as Plotly from 'plotly.js/lib/core';
import * as Bar from 'plotly.js/lib/bar';
import * as Pie from 'plotly.js/lib/pie';
+import * as Surface from 'plotly.js/lib/surface';
+import * as Scatter3D from 'plotly.js/lib/scatter3d';
Plotly.register([
/*
@@ -10,6 +12,8 @@ Plotly.register([
*/
Bar,
Pie,
+ Surface,
+ Scatter3D,
]);
export default Plotly;
\ No newline at end of file
diff --git a/src/app-components/table/table.jsx b/src/app-components/table/table.jsx
index e530bbed..0d2764a4 100644
--- a/src/app-components/table/table.jsx
+++ b/src/app-components/table/table.jsx
@@ -1,4 +1,5 @@
import React, { useState } from 'react';
+import Select from 'react-select';
import {
useReactTable,
createColumnHelper,
@@ -6,9 +7,11 @@ import {
getCoreRowModel,
getSortedRowModel,
getFilteredRowModel,
+ getPaginationRowModel,
} from '@tanstack/react-table';
import { ArrowDropDown, ArrowDropUp } from '@mui/icons-material';
+import Button from '../button';
import Filter from './filter';
import { classArray } from '../../common/helpers/utils';
@@ -35,7 +38,7 @@ const multiFilterFn = (row, columnId, filterValues) => {
const Table = ({
data,
columns,
- // usePagination = false,
+ usePagination = false,
className,
}) => {
const [columnFilters, setColumnFilters] = useState([]);
@@ -68,48 +71,115 @@ const Table = ({
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
+ ...usePagination && ({
+ getPaginationRowModel: getPaginationRowModel(),
+ }),
});
+ const currentIndex = table.getState().pagination.pageIndex;
+
return (
-
-
- {table.getHeaderGroups()?.map(headerGroup => (
-
- {headerGroup.headers.map(header => (
-
-
- {header.isPlaceholder ? null : flexRender(
- header.column.columnDef.header,
- header.getContext()
- )}
-
- {{
- asc: ,
- desc: ,
- }[header.column.getIsSorted()] ?? null}
- {header.column.getCanFilter() ? (
-
- ) : null}
-
- ))}
-
- ))}
-
-
- {table.getRowModel()?.rows?.map(row => (
-
- {row.getVisibleCells().map(cell => (
-
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
-
- ))}
-
- ))}
-
-
+ <>
+
+
+ {table.getHeaderGroups()?.map(headerGroup => (
+
+ {headerGroup.headers.map(header => (
+
+
+ {header.isPlaceholder ? null : flexRender(
+ header.column.columnDef.header,
+ header.getContext()
+ )}
+
+ {{
+ asc: ,
+ desc: ,
+ }[header.column.getIsSorted()] ?? null}
+ {header.column.getCanFilter() ? (
+
+ ) : null}
+
+ ))}
+
+ ))}
+
+
+ {table.getRowModel()?.rows?.map(row => (
+
+ {row.getVisibleCells().map(cell => (
+
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
+
+ ))}
+
+ ))}
+
+
+ {usePagination ? (
+
+
+
table.setPageIndex(0)}
+ isDisabled={currentIndex === 0}
+ />
+ table.previousPage()}
+ isDisabled={currentIndex === 0}
+ />
+
+ Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()}
+
+ table.nextPage()}
+ isDisabled={currentIndex === (table.getPageCount() - 1)}
+ />
+ table.setPageIndex(table.getPageCount() - 1)}
+ isDisabled={currentIndex === (table.getPageCount() - 1)}
+ />
+
+
+ Items per page:
+
+ table.setPageSize(option.value)}
+ options={[
+ { label: '10', value: 10 },
+ { label: '20', value: 20 },
+ { label: '30', value: 30 },
+ ]}
+ />
+
+
+
+ ) : null}
+ >
);
};
diff --git a/src/app-pages/instrument/timeseries/timeseries.jsx b/src/app-pages/instrument/timeseries/timeseries.jsx
index 237e02fb..49235c9b 100644
--- a/src/app-pages/instrument/timeseries/timeseries.jsx
+++ b/src/app-pages/instrument/timeseries/timeseries.jsx
@@ -16,9 +16,10 @@ import './timeseries.css';
const doesSetHaveData = (dataSet, key, activeTimeseries) => {
const data = dataSet[activeTimeseries];
- return !!(data && data[key]);
+ return !!(data && data[key] && data[key].length);
};
+// @TODO - check this for runtime
const getInclinometerItems = inclinometers => {
const items = [];
diff --git a/src/app-pages/project/batch-plotting/batch-plotting.jsx b/src/app-pages/project/batch-plotting/batch-plotting.jsx
index 71bf4daf..c256fb7f 100644
--- a/src/app-pages/project/batch-plotting/batch-plotting.jsx
+++ b/src/app-pages/project/batch-plotting/batch-plotting.jsx
@@ -2,22 +2,70 @@ import React from 'react';
import { connect } from 'redux-bundler-react';
import { Engineering } from '@mui/icons-material';
-import BatchPlotChart from './batch-plot-chart';
+import BatchPlotChart from './tab-content/batch-plot-chart';
import Card from '../../../app-components/card';
-import DataConfiguration from './data-configuration';
+import DataConfiguration from './components/data-configuration';
+import DepthChart from './tab-content/depth-chart';
import Map from '../../../app-components/classMap';
+import TabContainer from '../../../app-components/tab/tabContainer';
import './batch-plotting.scss';
+const batchPlotContainsInclinometers = (activeId, items, timeseries, instruments, domains) => {
+ const ret = {
+ containsInclinometers: false,
+ inclinometerTimeseriesIds: [],
+ };
+ if (!Object.keys(items).length || !activeId) return ret;
+ const config = items[activeId];
+ const { timeseries_id } = config || {};
+
+ if (!timeseries_id) return ret;
+
+ const { id: inclinometerTypeId } = domains['instrument_type'].find(el => el.value === 'Inclinometer');
+
+ timeseries_id.forEach(id => {
+ const { instrument_id } = timeseries.find(ts => ts.id === id) || {};
+ const { type_id } = instruments.find(i => i.id === instrument_id) || {};
+
+ if (type_id === inclinometerTypeId) {
+ ret.containsInclinometers = true;
+ ret.inclinometerTimeseriesIds = [...ret.inclinometerTimeseriesIds, id];
+ }
+ });
+
+ return ret;
+};
+
const BatchPlotting = connect(
'doMapsInitialize',
'doMapsShutdown',
'selectMapsObject',
'selectHashQuery',
- ({ doMapsInitialize, doMapsShutdown, mapsObject, hashQuery }) => {
+ 'selectBatchPlotConfigurationsActiveId',
+ 'selectBatchPlotConfigurationsItemsObject',
+ 'selectInstrumentTimeseriesItemsByRoute',
+ 'selectInstrumentsItems',
+ 'selectDomainsItemsByGroup',
+ ({
+ doMapsInitialize,
+ doMapsShutdown,
+ mapsObject,
+ hashQuery,
+ batchPlotConfigurationsActiveId: batchPlotId,
+ batchPlotConfigurationsItemsObject: batchPlotItems,
+ instrumentTimeseriesItemsByRoute: timeseries,
+ instrumentsItems: instruments,
+ domainsItemsByGroup: domains,
+ }) => {
const crossSectionReady = import.meta.env.VITE_CROSS_SECTION === 'true';
const userConfigId = hashQuery ? hashQuery['c'] : '';
+ const {
+ containsInclinometers,
+ inclinometerTimeseriesIds,
+ } = batchPlotContainsInclinometers(batchPlotId, batchPlotItems, timeseries, instruments, domains);
+
return (
<>
@@ -54,9 +102,19 @@ const BatchPlotting = connect(
)}
-
-
-
+
+ ,
+ },
+ containsInclinometers && {
+ title: 'Depth Based Plot',
+ content:
+ },
+ ]}
+ />
>
diff --git a/src/app-pages/project/batch-plotting/batch-plot-chart-settings.jsx b/src/app-pages/project/batch-plotting/components/batch-plot-chart-settings.jsx
similarity index 63%
rename from src/app-pages/project/batch-plotting/batch-plot-chart-settings.jsx
rename to src/app-pages/project/batch-plotting/components/batch-plot-chart-settings.jsx
index 848df7ba..7dafcdb9 100644
--- a/src/app-pages/project/batch-plotting/batch-plot-chart-settings.jsx
+++ b/src/app-pages/project/batch-plotting/components/batch-plot-chart-settings.jsx
@@ -3,9 +3,11 @@ import DatePicker from 'react-datepicker';
import { DateTime } from 'luxon';
import { subDays, startOfDay } from 'date-fns';
import { CSVLink } from 'react-csv';
+import { Slider } from '@mui/material';
+import { toast } from 'react-toastify';
-import Button from '../../../app-components/button';
-import HelperTooltip from '../../../app-components/helper-tooltip';
+import Button from '../../../../app-components/button';
+import HelperTooltip from '../../../../app-components/helper-tooltip';
import PrintButton from './print-button';
const dateAgo = days => subDays(new Date(), days);
@@ -19,15 +21,45 @@ const customDateFormat = (fromTime, endTime) => {
return `${fromDate} - ${endDate}`;
};
+// @TODO - this function is atrocious. fix it.
+const generatePlottedCSV = async (chartData = [], setCsvData) => {
+ const res = await (
+ chartData
+ .map(({ name, x, y }) => x.map((time, index) => ({ Time:time, [name + ' Value']: y[index] })))
+ .reduce((acc, curr) => [...acc, ...curr], [])
+ .reduce((acc, {Time, ...rest}) => {
+ const lookup = acc.reduce((lookup, { Time }, index) => {
+ lookup[Time] = index;
+ return lookup;
+ }, {});
+
+ if (lookup[Time]) {
+ acc[lookup[Time]] = { ...acc[lookup[Time]], ...rest };
+ return acc;
+ } else {
+ return [...acc, {Time, ...rest}];
+ }
+ }, [])
+ // Remove characters from ISO 8601 strings for common spreadsheet software to recognize dates
+ .sort((a, b) => new Date(a.Time).getTime() - new Date(b.Time).getTime())
+ .map(({ Time, ...rest }) => ({ Time: Time.replace('T', ' ').replace('Z', ''), ...rest }))
+ );
+
+ setCsvData(res);
+};
+
const BatchPlotChartSettings = ({
chartSettings,
setChartSettings,
dateRange = [],
setDateRange,
+ threshold = 3000,
+ setThreshold,
savePlotSettings,
chartData,
}) => {
const [fromTime, endTime] = dateRange;
+ const [csvData, setCsvData] = useState([]);
const [activeButton, setActiveButton] = useState('1 year');
const { auto_range, show_comments, show_masked, show_nonvalidated } = chartSettings;
@@ -45,8 +77,6 @@ const BatchPlotChartSettings = ({
e.preventDefault();
};
- const isChartDataDownloadable = () => chartData && chartData.every(({x, y}) => x && y && x.length == y.length);
-
return (
Plot Settings:
@@ -115,6 +145,37 @@ const BatchPlotChartSettings = ({
dateFormat='MMMM d, yyyy'
/>
)}
+
+
+ Display Point Threshold:
+
+ The Display Point Threshold value determines the number of data points to downsample the plot to.
+ The higher this value is, the more accurate the data will be to actual and similarly, the lower the
+ this value is, the less accurate it will be to actual. To turn off downsampling and use all data points,
+ set the Display Point Threshold to 0 . The number of data points will considerably change the
+ loading time of the plot, the lower the value the faster it will load.
+
+ It is recommended to only use a high value, or 0, if your date range is small or need extremely
+ accurate data representation.
+
+ )}
+ />
+
+ setThreshold(newVal)}
+ />
+
@@ -132,7 +193,8 @@ const BatchPlotChartSettings = ({
place='right'
content={
- Selecting this option will allow the plot to attempt a 'best-fit' view for the data selected.
+ Selecting this option will allow the plot to
+ attempt a 'best-fit' view for the data selected.
}
/>
@@ -147,6 +209,7 @@ const BatchPlotChartSettings = ({
show_masked: !isDisplayAllActive(),
show_nonvalidated: !isDisplayAllActive(),
show_comments: !isDisplayAllActive(),
+ threshold,
})}
onChange={() => {}}
/>
@@ -205,34 +268,38 @@ const BatchPlotChartSettings = ({
})}
/>
x.map((time, index) => ({ Time:time, [name + ' Value']: y[index] })))
- .reduce((acc, curr) => [...acc, ...curr], [])
- .reduce((acc, {Time, ...rest}) => {
- const lookup = acc.reduce((lookup, { Time }, index) => {
- lookup[Time] = index;
- return lookup;
- }, {});
-
- if (lookup[Time]) {
- acc[lookup[Time]] = { ...acc[lookup[Time]], ...rest };
- return acc;
- } else {
- return [...acc, {Time, ...rest}];
- }
- }, [])
- // Remove characters from ISO 8601 strings for common spreadsheet software to recognize dates
- .sort((a, b) => new Date(a.Time).getTime() - new Date(b.Time).getTime())
- .map(({ Time, ...rest }) => ({ Time: Time.replace('T', ' ').replace('Z', ''), ...rest }))
- : {} }
+ asyncOnClick
filename={chartSettings.name + '.csv'}
+ data={csvData}
+ onClick={(_e, done) => {
+ toast.promise(
+ Promise.resolve(generatePlottedCSV(chartData, setCsvData)),
+ {
+ pending: {
+ render: () => 'Generating CSV file. Please wait...',
+ },
+ success: {
+ render: () => {
+ done();
+ return 'Your file is ready!';
+ }
+ },
+ error: {
+ render: ({ data }) => {
+ done(false);
+ return `Failed to generate file... \n${data?.message}`;
+ }
+ },
+ }
+ )
+ }}
>
diff --git a/src/app-pages/project/batch-plotting/batch-plot-errors.jsx b/src/app-pages/project/batch-plotting/components/batch-plot-errors.jsx
similarity index 100%
rename from src/app-pages/project/batch-plotting/batch-plot-errors.jsx
rename to src/app-pages/project/batch-plotting/components/batch-plot-errors.jsx
diff --git a/src/app-pages/project/batch-plotting/configuration-panel.jsx b/src/app-pages/project/batch-plotting/components/configuration-panel.jsx
similarity index 96%
rename from src/app-pages/project/batch-plotting/configuration-panel.jsx
rename to src/app-pages/project/batch-plotting/components/configuration-panel.jsx
index 0590183c..45072bbb 100644
--- a/src/app-pages/project/batch-plotting/configuration-panel.jsx
+++ b/src/app-pages/project/batch-plotting/components/configuration-panel.jsx
@@ -1,8 +1,8 @@
import React, { useState, useEffect, useMemo } from 'react';
import { connect } from 'redux-bundler-react';
-import Button from '../../../app-components/button';
-import MultiSelect from '../../../app-components/multi-select';
+import Button from '../../../../app-components/button';
+import MultiSelect from '../../../../app-components/multi-select';
const formatOptions = timeseries => (
timeseries.map(ts => ({
diff --git a/src/app-pages/project/batch-plotting/data-configuration.jsx b/src/app-pages/project/batch-plotting/components/data-configuration.jsx
similarity index 93%
rename from src/app-pages/project/batch-plotting/data-configuration.jsx
rename to src/app-pages/project/batch-plotting/components/data-configuration.jsx
index 63a2eaee..e5056531 100644
--- a/src/app-pages/project/batch-plotting/data-configuration.jsx
+++ b/src/app-pages/project/batch-plotting/components/data-configuration.jsx
@@ -2,13 +2,13 @@ import React, { useEffect, useState } from 'react';
import { connect } from 'redux-bundler-react';
import { Delete, Edit } from '@mui/icons-material';
-import Button from '../../../app-components/button';
+import Button from '../../../../app-components/button';
import ConfigurationPanel from './configuration-panel';
-import DeleteButton from '../../../app-components/delete-confirm';
-import Select from '../../../app-components/select';
-import usePrevious from '../../../customHooks/usePrevious';
+import DeleteButton from '../../../../app-components/delete-confirm';
+import Select from '../../../../app-components/select';
+import usePrevious from '../../../../customHooks/usePrevious';
-import './batch-plotting.scss';
+import '../batch-plotting.scss';
const DataConfiguration = connect(
'selectBatchPlotConfigurationsItems',
diff --git a/src/app-pages/project/batch-plotting/print-button.jsx b/src/app-pages/project/batch-plotting/components/print-button.jsx
similarity index 92%
rename from src/app-pages/project/batch-plotting/print-button.jsx
rename to src/app-pages/project/batch-plotting/components/print-button.jsx
index a8162fd3..e21a2e5b 100644
--- a/src/app-pages/project/batch-plotting/print-button.jsx
+++ b/src/app-pages/project/batch-plotting/components/print-button.jsx
@@ -13,10 +13,10 @@ import { connect } from 'redux-bundler-react';
// Font,
// } from '@react-pdf/renderer';
-import Button from '../../../app-components/button';
-import Plotly from '../../../app-components/chart/minify-plotly';
-import latoBoldSource from '../../../css/google-fonts/fonts/Lato-Bold.ttf';
-import latoSource from '../../../css/google-fonts/fonts/Lato-Regular.ttf';
+import Button from '../../../../app-components/button';
+import Plotly from '../../../../app-components/chart/minify-plotly';
+import latoBoldSource from '../../../../css/google-fonts/fonts/Lato-Bold.ttf';
+import latoSource from '../../../../css/google-fonts/fonts/Lato-Regular.ttf';
// Font.register({ family: 'Lato', src: latoSource });
// Font.register({ family: 'Lato-Bold', src: latoBoldSource });
diff --git a/src/app-pages/project/batch-plotting/index.js b/src/app-pages/project/batch-plotting/index.js
index ae651fb3..2fcfd535 100644
--- a/src/app-pages/project/batch-plotting/index.js
+++ b/src/app-pages/project/batch-plotting/index.js
@@ -1 +1 @@
-export { default } from './batch-plotting';
\ No newline at end of file
+export { default } from './batch-plotting';
diff --git a/src/app-pages/project/batch-plotting/batch-plot-chart.jsx b/src/app-pages/project/batch-plotting/tab-content/batch-plot-chart.jsx
similarity index 79%
rename from src/app-pages/project/batch-plotting/batch-plot-chart.jsx
rename to src/app-pages/project/batch-plotting/tab-content/batch-plot-chart.jsx
index 72977ea7..ff71b4f3 100644
--- a/src/app-pages/project/batch-plotting/batch-plot-chart.jsx
+++ b/src/app-pages/project/batch-plotting/tab-content/batch-plot-chart.jsx
@@ -2,10 +2,10 @@ import React, { useEffect, useState } from 'react';
import { connect } from 'redux-bundler-react';
import { subDays } from 'date-fns';
-import Chart from '../../../app-components/chart/chart';
-import ChartErrors from './batch-plot-errors';
-import ChartSettings from './batch-plot-chart-settings';
-import { generateNewChartData } from './helper';
+import Chart from '../../../../app-components/chart/chart';
+import ChartErrors from '../components/batch-plot-errors';
+import ChartSettings from '../components/batch-plot-chart-settings';
+import { generateNewChartData } from '../helper';
const BatchPlotChart = connect(
'doPrintSetData',
@@ -30,6 +30,7 @@ const BatchPlotChart = connect(
const [measurements, setMeasurements] = useState([]);
const [chartData, setChartData] = useState([]);
const [dateRange, setDateRange] = useState([subDays(new Date(), 365), new Date()]);
+ const [threshold, setThreshold] = useState(3000);
const [withPrecipitation, setWithPrecipitation] = useState(false);
const [chartSettings, setChartSettings] = useState({ auto_range: false });
@@ -61,6 +62,11 @@ const BatchPlotChart = connect(
height: 600,
};
+ const savePlotSettings = (params) => {
+ timeseriesIds.forEach(id => doTimeseriesMeasurementsFetchById({ timeseriesId: id, dateRange, threshold }));
+ doBatchPlotConfigurationsSave(...params);
+ };
+
/** Load specific timeseries ids into state when new configurations are loaded */
useEffect(() => {
const config = batchPlotConfigurationsItemsObject[batchPlotConfigurationsActiveId];
@@ -75,8 +81,8 @@ const BatchPlotChart = connect(
/** Fetch the timeseries measurements in regards to date range */
useEffect(() => {
- timeseriesIds.forEach(id => doTimeseriesMeasurementsFetchById({ timeseriesId: id, dateRange }));
- }, [timeseriesIds, dateRange, doInstrumentTimeseriesSetActiveId]);
+ timeseriesIds.forEach(id => doTimeseriesMeasurementsFetchById({ timeseriesId: id, dateRange, threshold })); // @TODO - allow slider fo threshold
+ }, [timeseriesIds, doInstrumentTimeseriesSetActiveId]);
/** Extract specific measurements from the store that relate to our set timeseries */
useEffect(() => {
@@ -88,14 +94,11 @@ const BatchPlotChart = connect(
}, [timeseriesIds, timeseriesMeasurementsItems, setMeasurements]);
/** When we get new measurements, update chart data */
- useEffect(
- () => {
- const newData = generateNewChartData(measurements, instrumentTimeseriesItemsByRoute, chartSettings);
+ useEffect(() => {
+ const newData = generateNewChartData(measurements, instrumentTimeseriesItemsByRoute, chartSettings);
- setChartData(newData);
- },
- [measurements, instrumentTimeseriesItemsByRoute, withPrecipitation, chartSettings]
- );
+ setChartData(newData);
+ }, [measurements, instrumentTimeseriesItemsByRoute, withPrecipitation, chartSettings]);
/** When chart data changes, see if there is precip data to adjust plot */
useEffect(() => {
@@ -132,11 +135,13 @@ const BatchPlotChart = connect(
<>
>
diff --git a/src/app-pages/project/batch-plotting/tab-content/depth-chart.jsx b/src/app-pages/project/batch-plotting/tab-content/depth-chart.jsx
new file mode 100644
index 00000000..d6e21fda
--- /dev/null
+++ b/src/app-pages/project/batch-plotting/tab-content/depth-chart.jsx
@@ -0,0 +1,219 @@
+import React, { useEffect, useState } from 'react';
+import { connect } from 'redux-bundler-react';
+import { Slider } from '@mui/material';
+import { DateTime } from 'luxon';
+
+import Chart from '../../../../app-components/chart/chart';
+
+const colors = [
+ '#800000',
+ '#000075',
+ '#e6194B',
+ '#3cb44b',
+ '#911eb4',
+ '#fabed4',
+];
+
+const formatData = (data = [], indexes = []) => {
+ const inclinometerIds = Object.keys(data);
+ if (!inclinometerIds.length) return {};
+
+ const workingData = data[inclinometerIds[0]].inclinometers;
+
+ const depthIncrements = workingData.map((datum, i) => {
+ const { time, values } = datum;
+
+ const valueDisplacement = values.sort((a, b) => b.nDepth - a.nDepth);
+
+ return { time, valueDisplacement, colorIndex: i };
+ }).sort((a, b) => DateTime.fromISO(a.time).toMillis() - DateTime.fromISO(b.time).toMillis());
+
+ const relevantData = depthIncrements.slice(indexes[0], indexes[1] + 1);
+ const dataArray = [];
+
+ for (let i = 0; i < relevantData.length; i++) {
+ const { valueDisplacement, time, colorIndex } = relevantData[i];
+
+ dataArray.push(
+ valueDisplacement.reduce((accum, current, ind) => {
+ const { depth, aIncrement, bIncrement } = current;
+
+ if (ind === 0) {
+ accum.nDepth.push(depth);
+ accum.aIncrement.push(aIncrement);
+ accum.bIncrement.push(bIncrement);
+ accum.time = DateTime.fromISO(time).toFormat('MMM dd, yyyy hh:mm:ss');
+ accum.colorIndex = colorIndex;
+ } else {
+ accum.nDepth.push(depth);
+ accum.aIncrement.push(accum.aIncrement[ind - 1] + aIncrement);
+ accum.bIncrement.push(accum.bIncrement[ind - 1] + bIncrement);
+ accum.time = DateTime.fromISO(time).toFormat('MMM dd, yyyy hh:mm:ss');
+ accum.colorIndex = colorIndex;
+ }
+
+ return accum;
+ }, {
+ nDepth: [],
+ aIncrement: [],
+ bIncrement: [],
+ time: '',
+ colorIndex: '',
+ })
+ )
+ }
+
+ return { depthIncrements, dataArray, relevantData };
+};
+
+const build3dTraces = (dataArray, unit) => dataArray.map(data => (
+ {
+ x: data.aIncrement,
+ y: data.bIncrement,
+ z: data.nDepth,
+ mode: 'markers+lines',
+ marker: { size: 3, color: colors[data.colorIndex % colors.length] },
+ line: { width: 1 },
+ type: 'scatter3d',
+ name: `${data.time} Cumulative Displacement (in ${unit})`,
+ }
+
+ // If client wants A and B Displacement on the 3-D plot, add these back in and adjust function to a forEach using push logic.
+ // , {
+ // x: data.aIncrement,
+ // y: new Array(data.bIncrement.length).fill(0),
+ // z: data.nDepth,
+ // mode: 'markers+lines',
+ // marker: { size: 5, color: 'green' },
+ // type: 'scatter3d',
+ // name: `A Displacement (in ${unit})`,
+ // }, {
+ // x: new Array(data.aIncrement.length).fill(0),
+ // y: data.bIncrement,
+ // z: data.nDepth,
+ // mode: 'markers+lines',
+ // marker: { size: 5, color: 'orange' },
+ // type: 'scatter3d',
+ // name: `B Displacement (in ${unit})`
+ // }
+));
+
+const build2dTrace = (dataArray, key, unit) => dataArray.map(data => (
+ {
+ x: data[key],
+ y: data.nDepth,
+ mode: 'markers+lines',
+ marker: { size: 5, color: colors[data.colorIndex % colors.length] },
+ line: { width: 1 },
+ type: 'scatter',
+ name: `${key} Displacement (in ${unit})`,
+ hovertemplate: `
+ ${data.time}
+ Depth: %{y}
+ Displacement: %{x}
+
+ `,
+ }
+));
+
+const DepthChart = connect(
+ 'doFetchInclinometerMeasurementsByTimeseriesId',
+ 'selectCurrentInclinometerMeasurements',
+ ({
+ doFetchInclinometerMeasurementsByTimeseriesId,
+ currentInclinometerMeasurements,
+ inclinometerTimeseriesIds,
+ }) => {
+ const [sliderVal, setSliderVal] = useState([0, 0]);
+
+ useEffect(() => {
+ inclinometerTimeseriesIds.forEach(id => {
+ doFetchInclinometerMeasurementsByTimeseriesId(id);
+ });
+ }, [inclinometerTimeseriesIds, doFetchInclinometerMeasurementsByTimeseriesId]);
+
+ const inclinometerIds = Object.keys(currentInclinometerMeasurements || {});
+ const isMetric = false;
+ const unit = isMetric ? 'mm' : 'inches';
+ const { dataArray = [], depthIncrements = [] } = formatData(currentInclinometerMeasurements, sliderVal, isMetric);
+
+ const config = {
+ repsonsive: true,
+ displaylogo: false,
+ displayModeBar: true,
+ scrollZoom: true,
+ };
+
+ const layout3d = {
+ autosize: true,
+ height: 800,
+ scene: {
+ xaxis: { title: `A-Displacement (in ${unit})` },
+ yaxis: { title: `B-Displacement (in ${unit})` },
+ zaxis: { title: 'Depth', autorange: 'reversed' },
+ },
+ legend: {
+ 'orientation': 'h',
+ },
+ };
+
+ const layoutTall = (key) => ({
+ showlegend: false,
+ autosize: true,
+ height: 800,
+ yaxis: {
+ autorange: 'reversed',
+ title: `Depth in Feet`,
+ },
+ xaxis: {
+ title: `${key}-Displacement in ${unit}`,
+ },
+ });
+
+ const incrementData = build3dTraces(dataArray, unit);
+
+ return inclinometerIds.length ? (
+ <>
+
+
+
+ {DateTime.fromISO(depthIncrements[val]?.time).toFormat('MMM dd, yyyy hh:mm:ss')} }
+ onChange={(_e, newVal) => setSliderVal(newVal)}
+ />
+
+
+ >
+ ) : Loading Chart Data.... ;
+ },
+);
+
+export default DepthChart;
diff --git a/src/app-pages/project/qa-qc/components/modals/districtRollupModal.jsx b/src/app-pages/project/qa-qc/components/modals/districtRollupModal.jsx
index 36441d2e..83906384 100644
--- a/src/app-pages/project/qa-qc/components/modals/districtRollupModal.jsx
+++ b/src/app-pages/project/qa-qc/components/modals/districtRollupModal.jsx
@@ -4,6 +4,7 @@ import { connect } from 'redux-bundler-react';
import { subDays } from 'date-fns';
import { DateTime } from 'luxon';
+import Button from '../../../../../app-components/button';
import Chart from '../../../../../app-components/chart/chart';
import TabContainer from '../../../../../app-components/tab/tabContainer';
import { ModalContent, ModalBody, ModalFooter, ModalHeader } from '../../../../../app-components/modal';
@@ -27,10 +28,10 @@ const generateDataTraces = (data = []) => {
month,
red_submittals,
yellow_submittals,
- // project_id, @TODO - use to filter by own project
+ // project_id,
} = current;
- const monthDT = DateTime.fromISO(month);
+ const monthDT = DateTime.fromISO(month, { setZone: 'UTC' });
const displayString = (index) => {
if (index === 0 || monthDT.month === 1) {
@@ -86,6 +87,7 @@ const DistrictRollupModal = connect(
}) => {
const { evaluation, measurement } = districtRollupRaw;
+ const [showCurrentProjectOnly, setShowCurrentProjectOnly] = useState(false);
const [dateRange, setDateRange] = useState([subDays(new Date(), 365), new Date()]);
const [fromTime, endTime] = dateRange;
@@ -97,6 +99,11 @@ const DistrictRollupModal = connect(
doFetchDistrictRollup('measurement');
}, [doFetchDistrictRollup]);
+ const handleSettingsChange = () => {
+ doFetchDistrictRollup('evaluation', fromTime, endTime);
+ doFetchDistrictRollup('measurement', fromTime, endTime);
+ };
+
const evaluationChartData = [evaluationTraces.red, evaluationTraces.yellow, evaluationTraces.green];
const measurementChartData = [measurementTraces.red, measurementTraces.yellow, measurementTraces.green];
@@ -178,6 +185,27 @@ const DistrictRollupModal = connect(
dateFormat='MMMM d, yyyy'
/>
+
+ Show Only Current Project Data?
+ setShowCurrentProjectOnly(prev => !prev)}
+ />
+
+
+
+
+ handleSettingsChange()}
+ />
+
diff --git a/src/app-pages/project/qa-qc/components/modals/newEvaluationModal.jsx b/src/app-pages/project/qa-qc/components/modals/newEvaluationModal.jsx
index e73e728f..3d0de53a 100644
--- a/src/app-pages/project/qa-qc/components/modals/newEvaluationModal.jsx
+++ b/src/app-pages/project/qa-qc/components/modals/newEvaluationModal.jsx
@@ -2,10 +2,10 @@ import React, { useReducer } from 'react';
import { connect } from 'redux-bundler-react';
import ReactDatePicker from 'react-datepicker';
import Select from 'react-select';
+import { DateTime } from 'luxon';
import { ModalContent, ModalBody, ModalFooter, ModalHeader } from '../../../../../app-components/modal';
import { isSaveDisabled, reduceState, initState } from '../../../../../common/helpers/form-helpers';
-import { DateTime } from 'luxon';
const buildInstrumentOptions = (instruments = []) => (
instruments.map(instrument => {
diff --git a/src/app-pages/project/qa-qc/components/tables/submittalsTable.jsx b/src/app-pages/project/qa-qc/components/tables/submittalsTable.jsx
index c7350b87..87f3c95a 100644
--- a/src/app-pages/project/qa-qc/components/tables/submittalsTable.jsx
+++ b/src/app-pages/project/qa-qc/components/tables/submittalsTable.jsx
@@ -1,46 +1,98 @@
-import React, { useEffect } from 'react';
+import React, { useState, useEffect } from 'react';
import { connect } from 'redux-bundler-react';
+import { DateTime } from 'luxon';
+import { Circle, Check } from '@mui/icons-material';
+import Searchbar from '../../../../home/search-bar';
import Table from '../../../../../app-components/table';
-import { Circle } from '@mui/icons-material';
+import Button from '../../../../../app-components/button';
+
+const filterItems = (filter, items) => {
+ const filtered = items.filter(item => (
+ Object.values(item)
+ .join(' ')
+ .toUpperCase()
+ .indexOf(filter.toUpperCase()) !== -1
+ ));
+
+ return filtered;
+};
const SubmittalsTable = connect(
'doFetchHistoricalSubmittalsByProjectId',
'selectSubmittalsHistory',
+ 'doVerifySingleSubmittals',
({
doFetchHistoricalSubmittalsByProjectId,
submittalsHistory,
+ doVerifySingleSubmittals,
}) => {
+ const [filter, setFilter] = useState('');
+ const [filteredSubmittals, setFilteredSubmittals] = useState(submittalsHistory);
+
useEffect(() => {
doFetchHistoricalSubmittalsByProjectId();
}, [doFetchHistoricalSubmittalsByProjectId]);
+ useEffect(() => {
+ if (filter) {
+ setFilteredSubmittals(filterItems(filter, submittalsHistory));
+ } else {
+ setFilteredSubmittals(submittalsHistory);
+ }
+ }, [filter, submittalsHistory, filterItems, setFilteredSubmittals]);
+
return (
- (
-
- ),
- }, {
- key: 'alert_config_name',
- header: 'Alert Config Name',
- isSortable: true,
- }, {
- key: 'alert_type_name',
- header: 'Alert Type Name',
- isSortable: true,
- }, {
- key: 'create_date',
- header: 'Submittal Create Date'
- }, {
- key: 'due_date',
- header: 'Submittla Due Date',
- }]}
- />
+ <>
+ setFilter(e)} placeholder='Filter History...' />
+ (
+
+ ),
+ }, {
+ key: 'alert_config_name',
+ header: 'Alert Configuration Name',
+ isSortable: true,
+ }, {
+ key: 'alert_type_name',
+ header: 'Alert Type',
+ isSortable: true,
+ }, {
+ key: 'create_date',
+ header: 'Submittal Create Date',
+ render: data => (
+ {DateTime.fromISO(data?.create_date).toFormat('MMM dd, yyyy HH:mm:ss')}
+ ),
+ }, {
+ key: 'due_date',
+ header: 'Submittal Due Date',
+ render: data => (
+ {DateTime.fromISO(data?.due_date).toFormat('MMM dd, yyyy HH:mm:ss')}
+ ),
+ }, {
+ key: 'mark_missing',
+ header: Verify Missing ,
+ render: data => (
+
+ {data?.submittal_status_name === 'red' && !data?.marked_as_missing ? (
+ }
+ handleClick={() => doVerifySingleSubmittals(data?.id)}
+ />
+ ) : null}
+
+ )
+ }]}
+ />
+ >
);
}
);