Make maps and curves read only (#346)

* Refactor Table and Curve to be non-editable

* Refactor Map component, remove dependency

* Update dependencies
This commit is contained in:
Piotr Rogowski 2021-12-25 13:39:01 +01:00 committed by GitHub
parent 8eceff928f
commit a293e95979
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 106 additions and 788 deletions

266
package-lock.json generated
View File

@ -22,7 +22,6 @@
"react-redux": "^7.2.6",
"react-router-dom": "^5.2.1",
"react-scripts": "^4.0.3",
"react-table-drag-select": "^0.3.1",
"uplot": "^1.6.18",
"uplot-react": "^1.1.1"
},
@ -31,10 +30,10 @@
"@speedy-tuner/eslint-config": "^0.1.3",
"@types/d3": "^7.0.0",
"@types/node": "^17.0.4",
"@types/pako": "^1.0.2",
"@types/pako": "^1.0.3",
"@types/react": "^17.0.38",
"@types/react-dom": "^17.0.11",
"@types/react-redux": "^7.1.20",
"@types/react-redux": "^7.1.21",
"@types/react-router-dom": "^5.3.2",
"eslint-plugin-modules-newline": "^0.0.6",
"eslint-plugin-prettier": "^4.0.0",
@ -3767,9 +3766,9 @@
"integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw=="
},
"node_modules/@types/pako": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.2.tgz",
"integrity": "sha512-8UJl2MjkqqS6ncpLZqRZ5LmGiFBkbYxocD4e4jmBqGvfRG1RS23gKsBQbdtV9O9GvRyjFTiRHRByjSlKCLlmZw==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.3.tgz",
"integrity": "sha512-EDxOsHAD5dqjbjEUM1xwa7rpKPFb8ECBE5irONTQU7/OsO3thI5YrNEWSPNMvYmvFM0l/OLQJ6Mgw7PEdXSjhg==",
"dev": true
},
"node_modules/@types/parse-json": {
@ -3812,9 +3811,9 @@
}
},
"node_modules/@types/react-redux": {
"version": "7.1.20",
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.20.tgz",
"integrity": "sha512-q42es4c8iIeTgcnB+yJgRTTzftv3eYYvCZOh1Ckn2eX/3o5TdsQYKUWpLoLuGlcY/p+VAhV9IOEZJcWk/vfkXw==",
"version": "7.1.21",
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.21.tgz",
"integrity": "sha512-bLdglUiBSQNzWVVbmNPKGYYjrzp3/YDPwfOH3nLEz99I4awLlaRAPWjo6bZ2POpxztFWtDDXIPxBLVykXqBt+w==",
"dependencies": {
"@types/hoist-non-react-statics": "^3.3.0",
"@types/react": "*",
@ -6179,6 +6178,7 @@
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
"integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
"dev": true,
"engines": {
"node": ">=0.8"
}
@ -6586,15 +6586,6 @@
"sha.js": "^2.4.8"
}
},
"node_modules/create-react-class": {
"version": "15.7.0",
"resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.7.0.tgz",
"integrity": "sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==",
"dependencies": {
"loose-envify": "^1.3.1",
"object-assign": "^4.1.1"
}
},
"node_modules/create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
@ -7747,14 +7738,6 @@
"node": ">= 0.8"
}
},
"node_modules/encoding": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
"dependencies": {
"iconv-lite": "^0.6.2"
}
},
"node_modules/end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
@ -9263,34 +9246,6 @@
"bser": "2.1.1"
}
},
"node_modules/fbjs": {
"version": "0.8.18",
"resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.18.tgz",
"integrity": "sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA==",
"dependencies": {
"core-js": "^1.0.0",
"isomorphic-fetch": "^2.1.1",
"loose-envify": "^1.0.0",
"object-assign": "^4.1.0",
"promise": "^7.1.1",
"setimmediate": "^1.0.5",
"ua-parser-js": "^0.7.30"
}
},
"node_modules/fbjs/node_modules/core-js": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=",
"deprecated": "core-js@<3.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js."
},
"node_modules/fbjs/node_modules/promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
"dependencies": {
"asap": "~2.0.3"
}
},
"node_modules/figgy-pudding": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz",
@ -10583,17 +10538,6 @@
"node": ">=8.12.0"
}
},
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/icss-utils": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz",
@ -11372,15 +11316,6 @@
"node": ">=0.10.0"
}
},
"node_modules/isomorphic-fetch": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
"integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
"dependencies": {
"node-fetch": "^1.0.1",
"whatwg-fetch": ">=0.10.0"
}
},
"node_modules/istanbul-lib-coverage": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
@ -14186,23 +14121,6 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
},
"node_modules/node-fetch": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
"integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
"dependencies": {
"encoding": "^0.1.11",
"is-stream": "^1.0.1"
}
},
"node_modules/node-fetch/node_modules/is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/node-forge": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
@ -17740,31 +17658,6 @@
"node": ">=10"
}
},
"node_modules/react-table-drag-select": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/react-table-drag-select/-/react-table-drag-select-0.3.1.tgz",
"integrity": "sha512-+aOYkpbQ1YlEpDoMhdD+S+GVY5lG1+YN60YIt6pVRuEkU24G8BgGAy9+R+JXX+Izw3Nv7Jq8+kKoCPhBrKgaiw==",
"dependencies": {
"clone": "^2.1.1",
"deep-is": "^0.1.3",
"react": "^15.5.4"
}
},
"node_modules/react-table-drag-select/node_modules/react": {
"version": "15.7.0",
"resolved": "https://registry.npmjs.org/react/-/react-15.7.0.tgz",
"integrity": "sha512-5/MMRYmpmM0sMTHGLossnJCrmXQIiJilD6y3YN3TzAwGFj6zdnMtFv6xmi65PHKRV+pehIHpT7oy67Sr6s9AHA==",
"dependencies": {
"create-react-class": "^15.6.0",
"fbjs": "^0.8.9",
"loose-envify": "^1.1.0",
"object-assign": "^4.1.0",
"prop-types": "^15.5.10"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/read-pkg": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
@ -20912,24 +20805,6 @@
"node": ">=4.2.0"
}
},
"node_modules/ua-parser-js": {
"version": "0.7.31",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz",
"integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/ua-parser-js"
},
{
"type": "paypal",
"url": "https://paypal.me/faisalman"
}
],
"engines": {
"node": "*"
}
},
"node_modules/unbox-primitive": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
@ -26036,9 +25911,9 @@
"integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw=="
},
"@types/pako": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.2.tgz",
"integrity": "sha512-8UJl2MjkqqS6ncpLZqRZ5LmGiFBkbYxocD4e4jmBqGvfRG1RS23gKsBQbdtV9O9GvRyjFTiRHRByjSlKCLlmZw==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@types/pako/-/pako-1.0.3.tgz",
"integrity": "sha512-EDxOsHAD5dqjbjEUM1xwa7rpKPFb8ECBE5irONTQU7/OsO3thI5YrNEWSPNMvYmvFM0l/OLQJ6Mgw7PEdXSjhg==",
"dev": true
},
"@types/parse-json": {
@ -26081,9 +25956,9 @@
}
},
"@types/react-redux": {
"version": "7.1.20",
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.20.tgz",
"integrity": "sha512-q42es4c8iIeTgcnB+yJgRTTzftv3eYYvCZOh1Ckn2eX/3o5TdsQYKUWpLoLuGlcY/p+VAhV9IOEZJcWk/vfkXw==",
"version": "7.1.21",
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.21.tgz",
"integrity": "sha512-bLdglUiBSQNzWVVbmNPKGYYjrzp3/YDPwfOH3nLEz99I4awLlaRAPWjo6bZ2POpxztFWtDDXIPxBLVykXqBt+w==",
"requires": {
"@types/hoist-non-react-statics": "^3.3.0",
"@types/react": "*",
@ -27988,7 +27863,8 @@
"clone": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
"integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18="
"integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
"dev": true
},
"co": {
"version": "4.6.0",
@ -28329,15 +28205,6 @@
"sha.js": "^2.4.8"
}
},
"create-react-class": {
"version": "15.7.0",
"resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.7.0.tgz",
"integrity": "sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==",
"requires": {
"loose-envify": "^1.3.1",
"object-assign": "^4.1.1"
}
},
"create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
@ -29234,14 +29101,6 @@
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"encoding": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
"requires": {
"iconv-lite": "^0.6.2"
}
},
"end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
@ -30356,35 +30215,6 @@
"bser": "2.1.1"
}
},
"fbjs": {
"version": "0.8.18",
"resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.18.tgz",
"integrity": "sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA==",
"requires": {
"core-js": "^1.0.0",
"isomorphic-fetch": "^2.1.1",
"loose-envify": "^1.0.0",
"object-assign": "^4.1.0",
"promise": "^7.1.1",
"setimmediate": "^1.0.5",
"ua-parser-js": "^0.7.30"
},
"dependencies": {
"core-js": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
},
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
"requires": {
"asap": "~2.0.3"
}
}
}
},
"figgy-pudding": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz",
@ -31382,14 +31212,6 @@
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
"integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw=="
},
"iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
}
},
"icss-utils": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz",
@ -31923,15 +31745,6 @@
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
},
"isomorphic-fetch": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
"integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
"requires": {
"node-fetch": "^1.0.1",
"whatwg-fetch": ">=0.10.0"
}
},
"istanbul-lib-coverage": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
@ -34063,22 +33876,6 @@
}
}
},
"node-fetch": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
"integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
"requires": {
"encoding": "^0.1.11",
"is-stream": "^1.0.1"
},
"dependencies": {
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
}
}
},
"node-forge": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
@ -36826,30 +36623,6 @@
}
}
},
"react-table-drag-select": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/react-table-drag-select/-/react-table-drag-select-0.3.1.tgz",
"integrity": "sha512-+aOYkpbQ1YlEpDoMhdD+S+GVY5lG1+YN60YIt6pVRuEkU24G8BgGAy9+R+JXX+Izw3Nv7Jq8+kKoCPhBrKgaiw==",
"requires": {
"clone": "^2.1.1",
"deep-is": "^0.1.3",
"react": "^15.5.4"
},
"dependencies": {
"react": {
"version": "15.7.0",
"resolved": "https://registry.npmjs.org/react/-/react-15.7.0.tgz",
"integrity": "sha512-5/MMRYmpmM0sMTHGLossnJCrmXQIiJilD6y3YN3TzAwGFj6zdnMtFv6xmi65PHKRV+pehIHpT7oy67Sr6s9AHA==",
"requires": {
"create-react-class": "^15.6.0",
"fbjs": "^0.8.9",
"loose-envify": "^1.1.0",
"object-assign": "^4.1.0",
"prop-types": "^15.5.10"
}
}
}
},
"read-pkg": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
@ -39305,11 +39078,6 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz",
"integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg=="
},
"ua-parser-js": {
"version": "0.7.31",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz",
"integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ=="
},
"unbox-primitive": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",

View File

@ -43,7 +43,6 @@
"react-redux": "^7.2.6",
"react-router-dom": "^5.2.1",
"react-scripts": "^4.0.3",
"react-table-drag-select": "^0.3.1",
"uplot": "^1.6.18",
"uplot-react": "^1.1.1"
},
@ -52,10 +51,10 @@
"@speedy-tuner/eslint-config": "^0.1.3",
"@types/d3": "^7.0.0",
"@types/node": "^17.0.4",
"@types/pako": "^1.0.2",
"@types/pako": "^1.0.3",
"@types/react": "^17.0.38",
"@types/react-dom": "^17.0.11",
"@types/react-redux": "^7.1.20",
"@types/react-redux": "^7.1.21",
"@types/react-router-dom": "^5.3.2",
"eslint-plugin-modules-newline": "^0.0.6",
"eslint-plugin-prettier": "^4.0.0",

View File

@ -1 +0,0 @@
declare module 'react-table-drag-select';

View File

@ -75,7 +75,6 @@ html, body {
text-align: center;
border: 1px solid @main-light;
height: 50px;
user-select: none;
// transition: all 0.1s;
&.value {

View File

@ -38,10 +38,7 @@ import {
parseZ,
} from '../utils/tune/table';
import Map from './Dialog/Map';
import {
evaluateExpression,
isExpression,
} from '../utils/tune/expression';
import { evaluateExpression } from '../utils/tune/expression';
import useStorage from '../hooks/useStorage';
import useConfig from '../hooks/useConfig';
@ -153,7 +150,6 @@ const Dialog = ({
return (
<Curve
name={curve.yBins[0]}
width={canvasWidth}
key={curve.yBins[0]}
disabled={false} // TODO: evaluate condition
@ -162,10 +158,6 @@ const Dialog = ({
yLabel={curve.labels[1]}
xUnits={xConstant.units}
yUnits={yConstant.units}
xMin={xConstant.min as number}
xMax={xConstant.max as number}
yMin={yConstant.min as number}
yMax={yConstant.max as number}
xData={parseXy(x.value as string)}
yData={parseXy(y.value as string)}
/>
@ -176,30 +168,15 @@ const Dialog = ({
const x = tune.constants[table.xBins[0]];
const y = tune.constants[table.yBins[0]];
const z = tune.constants[table.zBins[0]];
const zConstant = findConstantOnPage(table.zBins[0]) as ScalarConstantType;
let max = zConstant.max as number;
if (isExpression(zConstant.max)) {
max = evaluateExpression(zConstant.max as string, tune.constants, config);
}
let min = zConstant.min as number;
if (isExpression(zConstant.min)) {
min = evaluateExpression(zConstant.min as string, tune.constants, config);
}
return <div>
{renderHelp(table.help)}
<Map
name={table.map}
key={table.map}
xData={parseXy(x.value as string)}
yData={parseXy(y.value as string).reverse()}
zData={parseZ(z.value as string)}
disabled={false}
zMin={min}
zMax={max}
digits={zConstant.digits as number}
xUnits={x.units as string}
yUnits={y.units as string}
/>

View File

@ -10,12 +10,11 @@ import UplotReact from 'uplot-react';
import uPlot from 'uplot';
import { Colors } from '../../utils/colors';
import LandscapeNotice from './LandscapeNotice';
import Table from './Table';
import Table from './Curve/Table';
const { useBreakpoint } = Grid;
const Curve = ({
name,
width,
xLabel,
yLabel,
@ -23,14 +22,9 @@ const Curve = ({
yData,
disabled,
help,
xMin,
xMax,
yMin,
yMax,
xUnits = '',
yUnits = '',
}: {
name: string,
width: number,
xLabel: string,
yLabel: string,
@ -38,10 +32,6 @@ const Curve = ({
yData: number[],
disabled: boolean,
help: string,
xMin: number,
xMax: number,
yMin: number,
yMax: number,
xUnits?: string,
yUnits?: string,
}) => {
@ -99,17 +89,11 @@ const Curve = ({
</Typography.Paragraph>
<UplotReact options={options!} data={plotData!} />
<Table
name={name}
key={name}
xLabel={xLabel}
yLabel={yLabel}
xData={xData}
yData={yData}
disabled={disabled}
xMin={xMin}
xMax={xMax}
yMin={yMin}
yMax={yMax}
xUnits={xUnits}
yUnits={yUnits}
/>

View File

@ -0,0 +1,60 @@
/* eslint-disable react/no-array-index-key */
import { useCallback } from 'react';
import { colorHsl } from '../../../utils/number';
const titleProps = { disabled: true };
type AxisType = 'x' | 'y';
const Table = ({
xLabel,
yLabel,
xData,
yData,
disabled,
xUnits,
yUnits,
}: {
xLabel: string,
yLabel: string,
xData: number[],
yData: number[],
disabled: boolean,
xUnits: string,
yUnits: string,
}) => {
const renderRow = useCallback((axis: AxisType, input: number[]) => input
.map((value, index) => {
const [hue, sat, light] = colorHsl(Math.min(...input), Math.max(...input), value);
return (
<td
className="value"
key={`${axis}-${index}-${value}-${hue}${sat}${light}`}
style={{ backgroundColor: `hsl(${hue}, ${sat}%, ${light}%)` }}
>
{`${value}`}
</td>
);
}), []);
return (
<div className="table">
<table>
<tbody>
<tr>
<td {...titleProps} className="title-curve" key={yLabel}>{`${yLabel} (${yUnits})`}</td>
{renderRow('y', yData)}
</tr>
<tr>
<td {...titleProps} className="title-curve" key={xLabel}>{`${xLabel} (${xUnits})`}</td>
{renderRow('x', xData)}
</tr>
</tbody>
</table>
</div>
);
};
export default Table;

View File

@ -1,182 +1,31 @@
/* eslint-disable react/no-array-index-key */
import {
useEffect,
useRef,
useState,
} from 'react';
import {
Button,
InputNumber,
Modal,
Popover,
Space,
Grid,
} from 'antd';
import {
PlusCircleOutlined,
MinusCircleOutlined,
EditOutlined,
} from '@ant-design/icons';
import TableDragSelect from 'react-table-drag-select';
import {
isDecrement,
isEscape,
isIncrement,
isReplace,
} from '../../utils/keyboard/shortcuts';
import { Grid } from 'antd';
import LandscapeNotice from './LandscapeNotice';
import { colorHsl } from '../../utils/number';
type CellsType = boolean[][];
type DataType = number[][];
type OnChangeType = (data: DataType) => void;
enum Operations {
INC,
DEC,
REPLACE,
}
const { useBreakpoint } = Grid;
const Map = ({
name,
xData,
yData,
zData,
disabled,
onChange,
zMin,
zMax,
digits,
xUnits,
yUnits,
}: {
name: string,
xData: number[],
yData: number[],
zData: number[][],
disabled: boolean,
onChange?: OnChangeType,
zMin: number,
zMax: number,
digits: number,
xUnits: string,
yUnits: string,
}) => {
const { sm } = useBreakpoint();
const titleProps = { disabled: true };
const [isModalVisible, setIsModalVisible] = useState(false);
const [modalValue, setModalValue] = useState<number | undefined>();
const [data, _setData] = useState<DataType>(zData);
const generateCells = () => Array.from(
Array(yData.length + 1).fill(false),
() => new Array(xData.length + 1).fill(false),
);
const [cells, _setCells] = useState<CellsType>(generateCells());
const cellsRef = useRef(cells);
const dataRef = useRef(data);
const modalInputRef = useRef<HTMLInputElement | null>(null);
const setCells = (currentCells: CellsType) => {
cellsRef.current = currentCells;
_setCells(currentCells);
};
const setData = (currentData: DataType) => {
dataRef.current = currentData;
_setData(currentData);
if (onChange) {
onChange(currentData);
}
};
const modifyData = (operation: Operations, currentCells: CellsType, currentData: DataType, value = 0): DataType => {
const newData = [...currentData.map((row) => [...row])];
currentCells.forEach((_, rowIndex) => {
currentCells[rowIndex].forEach((selected, valueIndex) => {
if (!selected) {
return;
}
const current = newData[rowIndex][valueIndex - 1];
switch (operation) {
case Operations.INC:
if (current < zMax) {
newData[rowIndex][valueIndex - 1] = Number((newData[rowIndex][valueIndex - 1] + 10**-digits).toFixed(digits));
}
break;
case Operations.DEC:
if (current > zMin) {
newData[rowIndex][valueIndex - 1] = Number((newData[rowIndex][valueIndex - 1] - 10**-digits).toFixed(digits));
}
break;
case Operations.REPLACE:
if (value > zMax) {
newData[rowIndex][valueIndex - 1] = zMax;
break;
}
if (value < zMin) {
newData[rowIndex][valueIndex - 1] = zMin;
break;
}
newData[rowIndex][valueIndex - 1] = value;
break;
default:
break;
}
});
});
return [...newData];
};
const oneModalOk = () => {
setData(modifyData(Operations.REPLACE, cellsRef.current, dataRef.current, modalValue));
setIsModalVisible(false);
setModalValue(undefined);
};
const onModalCancel = () => {
setIsModalVisible(false);
setModalValue(undefined);
};
const resetCells = () => setCells(generateCells());
const increment = () => setData(modifyData(Operations.INC, cellsRef.current, dataRef.current));
const decrement = () => setData(modifyData(Operations.DEC, cellsRef.current, dataRef.current));
const replace = () => {
// don't show modal when no cell is selected
if (cellsRef.current.flat().find((val) => val === true)) {
setModalValue(undefined);
setIsModalVisible(true);
setInterval(() => modalInputRef.current?.focus(), 1);
}
};
useEffect(() => {
const keyboardListener = (e: KeyboardEvent) => {
if (isIncrement(e)) {
increment();
}
if (isDecrement(e)) {
decrement();
}
if (isReplace(e)) {
e.preventDefault();
replace();
}
if (isEscape(e)) {
resetCells();
}
};
document.addEventListener('keydown', keyboardListener);
return () => {
document.removeEventListener('keydown', keyboardListener);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const min = Math.min(...data.map((row) => Math.min(...row)));
const max = Math.max(...data.map((row) => Math.max(...row)));
const min = Math.min(...zData.map((row) => Math.min(...row)));
const max = Math.max(...zData.map((row) => Math.max(...row)));
const renderRow = (rowIndex: number, input: number[]) => input
.map((value, index) => {
@ -210,58 +59,27 @@ const Map = ({
}
return (
<>
<div className="table">
<Popover
visible={cells.flat().find((val) => val === true) === true}
content={
<Space>
<Button onClick={decrement} icon={<MinusCircleOutlined />} />
<Button onClick={increment} icon={<PlusCircleOutlined />} />
<Button onClick={replace} icon={<EditOutlined />} />
</Space>
}
>
<TableDragSelect
key={name}
value={cells}
onChange={setCells}
>
{data.map((row, i) => (
<tr key={`row-${i}`}>
{renderRow(i, row)}
</tr>
))}
<tr>
<td {...titleProps} className="title-map">
{yUnits} / {xUnits}
</td>
{xData.map((xValue) => (
<td {...titleProps} key={`x-${xValue}`}>
{`${xValue}`}
</td>
))}
<div className="table">
<table>
<tbody>
{zData.map((row, i) => (
<tr key={`row-${i}`}>
{renderRow(i, row)}
</tr>
</TableDragSelect>
</Popover>
</div>
<Modal
title="Set cell values"
visible={isModalVisible}
onOk={oneModalOk}
onCancel={onModalCancel}
centered
forceRender
>
<InputNumber
ref={modalInputRef}
value={modalValue}
onChange={(val) => setModalValue(Number(val))}
onPressEnter={oneModalOk}
style={{ width: '20%' }}
/>
</Modal>
</>
))}
<tr>
<td {...titleProps} className="title-map">
{yUnits} / {xUnits}
</td>
{xData.map((xValue, l) => (
<td {...titleProps} key={`x-${l}-${xValue}`}>
{`${xValue}`}
</td>
))}
</tr>
</tbody>
</table>
</div>
);
};

View File

@ -50,7 +50,6 @@ const SmartSelect = ({
return (
<Select
defaultValue={values.indexOf(defaultValue)}
showSearch
optionFilterProp="label"
disabled={disabled}
style={{ maxWidth: 250 }}

View File

@ -1,260 +0,0 @@
/* eslint-disable react/no-array-index-key */
import {
useCallback,
useEffect,
useRef,
useState,
} from 'react';
import {
Button,
InputNumber,
Modal,
Popover,
Space,
} from 'antd';
import {
PlusCircleOutlined,
MinusCircleOutlined,
EditOutlined,
} from '@ant-design/icons';
import TableDragSelect from 'react-table-drag-select';
import {
isDecrement,
isEscape,
isIncrement,
isReplace,
} from '../../utils/keyboard/shortcuts';
import { colorHsl } from '../../utils/number';
type AxisType = 'x' | 'y';
type CellsType = boolean[][];
type DataType = number[][];
type OnChangeType = (data: DataType) => void;
enum Operations {
INC,
DEC,
REPLACE,
}
const Table = ({
name,
xLabel,
yLabel,
xData,
yData,
disabled,
onChange,
xMin,
xMax,
yMin,
yMax,
xUnits,
yUnits,
}: {
name: string,
xLabel: string,
yLabel: string,
xData: number[],
yData: number[],
disabled: boolean,
onChange?: OnChangeType,
xMin: number,
xMax: number,
yMin: number,
yMax: number,
xUnits: string,
yUnits: string,
}) => {
const titleProps = { disabled: true };
const [isModalVisible, setIsModalVisible] = useState(false);
const [modalValue, setModalValue] = useState<number | undefined>();
const [data, _setData] = useState<DataType>([yData, xData]);
// data starts from `1` index, 0 is title / name
const rowsCount = data[1].length + 1;
const generateCells = () => [
Array(rowsCount).fill(false),
Array(rowsCount).fill(false),
];
const [cells, _setCells] = useState<CellsType>(generateCells());
const cellsRef = useRef(cells);
const dataRef = useRef(data);
const modalInputRef = useRef<HTMLInputElement | null>(null);
const setCells = (currentCells: CellsType) => {
cellsRef.current = currentCells;
_setCells(currentCells);
};
const setData = (currentData: DataType) => {
dataRef.current = currentData;
_setData(currentData);
if (onChange) {
onChange(currentData);
}
};
const modifyData = useCallback((operation: Operations, currentCells: CellsType, currentData: DataType, value = 0): DataType => {
const newData = [...currentData.map((row) => [...row])];
// rowIndex: [0 => Y, 1 => X]
const isY = (row: number) => row === 0;
const isX = (row: number) => row === 1;
const isNotGreater = (row: number, val: number) => (isY(row) && val < yMax) || (isX(row) && val < xMax);
const isNotLess = (row: number, val: number) => (isY(row) && val > yMin) || (isX(row) && val > xMin);
currentCells.forEach((_, rowIndex) => {
currentCells[rowIndex].forEach((selected, valueIndex) => {
if (!selected) {
return;
}
const current = newData[rowIndex][valueIndex - 1];
switch (operation) {
case Operations.INC:
if (isNotGreater(rowIndex, current)) {
newData[rowIndex][valueIndex - 1] += 1;
}
break;
case Operations.DEC:
if (isNotLess(rowIndex, current)) {
newData[rowIndex][valueIndex - 1] -= 1;
}
break;
case Operations.REPLACE:
if (isX(rowIndex) && value > xMax) {
newData[rowIndex][valueIndex - 1] = xMax;
break;
}
if (isX(rowIndex) && value < xMin) {
newData[rowIndex][valueIndex - 1] = xMin;
break;
}
if (isY(rowIndex) && value < yMin) {
newData[rowIndex][valueIndex - 1] = yMin;
break;
}
if (isY(rowIndex) && value > yMax) {
newData[rowIndex][valueIndex - 1] = yMax;
break;
}
newData[rowIndex][valueIndex - 1] = value;
break;
default:
break;
}
});
});
return [...newData];
}, [xMax, xMin, yMax, yMin]);
const oneModalOk = () => {
setData(modifyData(Operations.REPLACE, cellsRef.current, dataRef.current, modalValue));
setIsModalVisible(false);
setModalValue(undefined);
};
const onModalCancel = () => {
setIsModalVisible(false);
setModalValue(undefined);
};
const resetCells = () => setCells(generateCells());
const increment = () => setData(modifyData(Operations.INC, cellsRef.current, dataRef.current));
const decrement = () => setData(modifyData(Operations.DEC, cellsRef.current, dataRef.current));
const replace = () => {
// don't show modal when no cell is selected
if (cellsRef.current.flat().find((val) => val === true)) {
setModalValue(undefined);
setIsModalVisible(true);
setInterval(() => modalInputRef.current?.focus(), 1);
}
};
useEffect(() => {
const keyboardListener = (e: KeyboardEvent) => {
if (isIncrement(e)) {
increment();
}
if (isDecrement(e)) {
decrement();
}
if (isReplace(e)) {
e.preventDefault();
replace();
}
if (isEscape(e)) {
resetCells();
}
};
document.addEventListener('keydown', keyboardListener);
return () => {
document.removeEventListener('keydown', keyboardListener);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const renderRow = (axis: AxisType, input: number[]) => input
.map((value, index) => {
const [hue, sat, light] = colorHsl(Math.min(...input), Math.max(...input), value);
return (
<td
className="value"
key={`${axis}-${index}-${value}-${hue}${sat}${light}`}
style={{ backgroundColor: `hsl(${hue}, ${sat}%, ${light}%)` }}
>
{`${value}`}
</td>
);
});
return (
<>
<div className="table table-2d">
<Popover
visible={cells.flat().find((val) => val === true) === true}
content={
<Space>
<Button onClick={decrement} icon={<MinusCircleOutlined />} />
<Button onClick={increment} icon={<PlusCircleOutlined />} />
<Button onClick={replace} icon={<EditOutlined />} />
</Space>
}
>
<TableDragSelect
key={name}
value={cells}
onChange={setCells}
>
<tr>
<td {...titleProps} className="title-curve" key={yLabel}>{`${yLabel} (${yUnits})`}</td>
{renderRow('y', data[0])}
</tr>
<tr>
<td {...titleProps} className="title-curve" key={xLabel}>{`${xLabel} (${xUnits})`}</td>
{renderRow('x', data[1])}
</tr>
</TableDragSelect>
</Popover>
</div>
<Modal
title="Set cell values"
visible={isModalVisible}
onOk={oneModalOk}
onCancel={onModalCancel}
centered
forceRender
>
<InputNumber
ref={modalInputRef}
value={modalValue}
onChange={(val) => setModalValue(Number(val))}
onPressEnter={oneModalOk}
style={{ width: '20%' }}
/>
</Modal>
</>
);
};
export default Table;

View File

@ -5,10 +5,7 @@ import {
Row,
Col,
} from 'antd';
import {
CarOutlined,
InfoCircleOutlined,
} from '@ant-design/icons';
import { InfoCircleOutlined } from '@ant-design/icons';
import { connect } from 'react-redux';
import {
AppState,
@ -32,12 +29,7 @@ const firmware = (signature: string) => (
const StatusBar = ({ status, config }: { status: StatusState, config: ConfigState }) => (
<Footer className="app-status-bar">
<Row>
<Col span={8}>
<Space>
<CarOutlined />
default
</Space>
</Col>
<Col span={8} />
<Col span={8} style={{ textAlign: 'center' }}>
{config.megaTune && firmware(config.megaTune.signature)}
</Col>

View File

@ -3,28 +3,11 @@ import React from 'react';
type KeyEvent = KeyboardEvent | React.KeyboardEvent<HTMLInputElement>;
enum Keys {
INCREMENT = '.',
DECREMENT = ',',
COMMAND = 'p',
SIDEBAR = '\\',
ESCAPE = 'Escape',
REPLACE = '=',
UP = 'ArrowUp',
DOWN = 'ArrowDown',
LEFT = 'ArrowLeft',
RIGHT = 'ArrowRight',
}
const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
export const isCommand = (e: KeyEvent) => (e.metaKey || e.ctrlKey) && e.key === Keys.COMMAND;
export const isToggleSidebar = (e: KeyEvent) => (e.metaKey || e.ctrlKey) && e.key === Keys.SIDEBAR;
export const isIncrement = (e: KeyEvent) => e.key === Keys.INCREMENT;
export const isDecrement = (e: KeyEvent) => e.key === Keys.DECREMENT;
export const isReplace = (e: KeyEvent) => e.key === Keys.REPLACE;
export const isEscape = (e: KeyEvent) => e.key === Keys.ESCAPE;
export const isUp = (e: KeyEvent) => e.key === Keys.UP;
export const isDown = (e: KeyEvent) => e.key === Keys.DOWN;
export const isLeft = (e: KeyEvent) => e.key === Keys.LEFT;
export const isRight = (e: KeyEvent) => e.key === Keys.RIGHT;
export const useDigits = (e: KeyEvent): [boolean, number] => [digits.includes(Number(e.key)), Number(e.key)];