add eslint airbnb rules
parent
0956687fbb
commit
d70e46583a
|
@ -1,9 +1,39 @@
|
|||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true
|
||||
},
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
"react-app/jest",
|
||||
"airbnb",
|
||||
"airbnb/hooks"
|
||||
],
|
||||
"rules": {
|
||||
"no-trailing-spaces": "warn"
|
||||
// disallow use of unary operators, ++ and --
|
||||
// http://eslint.org/docs/rules/no-plusplus
|
||||
// retropilot: we allow them in the for loop
|
||||
"no-plusplus": ["error", { "allowForLoopAfterthoughts": true }],
|
||||
|
||||
// disallow use of the continue statement
|
||||
// https://eslint.org/docs/rules/no-continue
|
||||
// retropilot: we allow use of the continue statement
|
||||
"no-continue": "off",
|
||||
|
||||
// disallow use of variables before they are defined
|
||||
// http://eslint.org/docs/rules/no-use-before-define
|
||||
// retropilot: permit referencing functions before they're defined
|
||||
"no-use-before-define": ["error", { "functions": false }],
|
||||
|
||||
// specify the maximum length of a line in your program
|
||||
// https://eslint.org/docs/rules/max-len
|
||||
// retropilot: ignore comments
|
||||
"max-len": ["error", 100, 2, {
|
||||
"ignoreUrls": true,
|
||||
"ignoreComments": true,
|
||||
"ignoreRegExpLiterals": true,
|
||||
"ignoreStrings": true,
|
||||
"ignoreTemplateLiterals": true
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"name": "app",
|
||||
"name": "retropilot-client",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "app",
|
||||
"name": "retropilot-client",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.7.1",
|
||||
|
@ -30,6 +30,9 @@
|
|||
"react-scripts": "4.0.3",
|
||||
"styled-components": "^5.3.3",
|
||||
"web-vitals": "^1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint-config-airbnb": "^19.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
|
@ -5256,9 +5259,9 @@
|
|||
"integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA=="
|
||||
},
|
||||
"node_modules/axe-core": {
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.3.tgz",
|
||||
"integrity": "sha512-/lqqLAmuIPi79WYfRpy2i8z+x+vxU3zX2uAm0gs1q52qTuKwolOj1P8XbufpXcsydrpKx2yGn2wzAnxCMV86QA==",
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz",
|
||||
"integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
|
@ -8374,6 +8377,55 @@
|
|||
"url": "https://opencollective.com/eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-airbnb": {
|
||||
"version": "19.0.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz",
|
||||
"integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"object.assign": "^4.1.2",
|
||||
"object.entries": "^1.1.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10.12.0 || ^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^7.32.0 || ^8.2.0",
|
||||
"eslint-plugin-import": "^2.25.3",
|
||||
"eslint-plugin-jsx-a11y": "^6.5.1",
|
||||
"eslint-plugin-react": "^7.28.0",
|
||||
"eslint-plugin-react-hooks": "^4.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-airbnb-base": {
|
||||
"version": "15.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz",
|
||||
"integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"confusing-browser-globals": "^1.0.10",
|
||||
"object.assign": "^4.1.2",
|
||||
"object.entries": "^1.1.5",
|
||||
"semver": "^6.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10.12.0 || >=12.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^7.32.0 || ^8.2.0",
|
||||
"eslint-plugin-import": "^2.25.2"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-airbnb-base/node_modules/semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-react-app": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-6.0.0.tgz",
|
||||
|
@ -8436,13 +8488,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/eslint-module-utils": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz",
|
||||
"integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==",
|
||||
"version": "2.7.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.2.tgz",
|
||||
"integrity": "sha512-zquepFnWCY2ISMFwD/DqzaM++H+7PDzOpUvotJWm/y1BAFt5R4oeULgdrTejKqLkz7MA/tgstsUMNYc7wNdTrg==",
|
||||
"dependencies": {
|
||||
"debug": "^3.2.7",
|
||||
"find-up": "^2.1.0",
|
||||
"pkg-dir": "^2.0.0"
|
||||
"find-up": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
|
@ -8517,17 +8568,6 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-module-utils/node_modules/pkg-dir": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz",
|
||||
"integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=",
|
||||
"dependencies": {
|
||||
"find-up": "^2.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-flowtype": {
|
||||
"version": "5.10.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.10.0.tgz",
|
||||
|
@ -8544,23 +8584,23 @@
|
|||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-import": {
|
||||
"version": "2.25.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.2.tgz",
|
||||
"integrity": "sha512-qCwQr9TYfoBHOFcVGKY9C9unq05uOxxdklmBXLVvcwo68y5Hta6/GzCZEMx2zQiu0woKNEER0LE7ZgaOfBU14g==",
|
||||
"version": "2.25.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz",
|
||||
"integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==",
|
||||
"dependencies": {
|
||||
"array-includes": "^3.1.4",
|
||||
"array.prototype.flat": "^1.2.5",
|
||||
"debug": "^2.6.9",
|
||||
"doctrine": "^2.1.0",
|
||||
"eslint-import-resolver-node": "^0.3.6",
|
||||
"eslint-module-utils": "^2.7.0",
|
||||
"eslint-module-utils": "^2.7.2",
|
||||
"has": "^1.0.3",
|
||||
"is-core-module": "^2.7.0",
|
||||
"is-core-module": "^2.8.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "^3.0.4",
|
||||
"object.values": "^1.1.5",
|
||||
"resolve": "^1.20.0",
|
||||
"tsconfig-paths": "^3.11.0"
|
||||
"tsconfig-paths": "^3.12.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
|
@ -8626,27 +8666,28 @@
|
|||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-jsx-a11y": {
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz",
|
||||
"integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==",
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz",
|
||||
"integrity": "sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.11.2",
|
||||
"@babel/runtime": "^7.16.3",
|
||||
"aria-query": "^4.2.2",
|
||||
"array-includes": "^3.1.1",
|
||||
"array-includes": "^3.1.4",
|
||||
"ast-types-flow": "^0.0.7",
|
||||
"axe-core": "^4.0.2",
|
||||
"axe-core": "^4.3.5",
|
||||
"axobject-query": "^2.2.0",
|
||||
"damerau-levenshtein": "^1.0.6",
|
||||
"emoji-regex": "^9.0.0",
|
||||
"damerau-levenshtein": "^1.0.7",
|
||||
"emoji-regex": "^9.2.2",
|
||||
"has": "^1.0.3",
|
||||
"jsx-ast-utils": "^3.1.0",
|
||||
"language-tags": "^1.0.5"
|
||||
"jsx-ast-utils": "^3.2.1",
|
||||
"language-tags": "^1.0.5",
|
||||
"minimatch": "^3.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^3 || ^4 || ^5 || ^6 || ^7"
|
||||
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-jsx-a11y/node_modules/emoji-regex": {
|
||||
|
@ -8655,41 +8696,41 @@
|
|||
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
|
||||
},
|
||||
"node_modules/eslint-plugin-react": {
|
||||
"version": "7.26.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.26.1.tgz",
|
||||
"integrity": "sha512-Lug0+NOFXeOE+ORZ5pbsh6mSKjBKXDXItUD2sQoT+5Yl0eoT82DqnXeTMfUare4QVCn9QwXbfzO/dBLjLXwVjQ==",
|
||||
"version": "7.28.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz",
|
||||
"integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==",
|
||||
"dependencies": {
|
||||
"array-includes": "^3.1.3",
|
||||
"array.prototype.flatmap": "^1.2.4",
|
||||
"array-includes": "^3.1.4",
|
||||
"array.prototype.flatmap": "^1.2.5",
|
||||
"doctrine": "^2.1.0",
|
||||
"estraverse": "^5.2.0",
|
||||
"estraverse": "^5.3.0",
|
||||
"jsx-ast-utils": "^2.4.1 || ^3.0.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"object.entries": "^1.1.4",
|
||||
"object.fromentries": "^2.0.4",
|
||||
"object.hasown": "^1.0.0",
|
||||
"object.values": "^1.1.4",
|
||||
"object.entries": "^1.1.5",
|
||||
"object.fromentries": "^2.0.5",
|
||||
"object.hasown": "^1.1.0",
|
||||
"object.values": "^1.1.5",
|
||||
"prop-types": "^15.7.2",
|
||||
"resolve": "^2.0.0-next.3",
|
||||
"semver": "^6.3.0",
|
||||
"string.prototype.matchall": "^4.0.5"
|
||||
"string.prototype.matchall": "^4.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^3 || ^4 || ^5 || ^6 || ^7"
|
||||
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-react-hooks": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz",
|
||||
"integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==",
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz",
|
||||
"integrity": "sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
|
||||
"eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-react/node_modules/doctrine": {
|
||||
|
@ -8704,9 +8745,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/eslint-plugin-react/node_modules/estraverse": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
|
||||
"integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
|
||||
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
}
|
||||
|
@ -19939,9 +19980,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/tsconfig-paths": {
|
||||
"version": "3.11.0",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz",
|
||||
"integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==",
|
||||
"version": "3.12.0",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz",
|
||||
"integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==",
|
||||
"dependencies": {
|
||||
"@types/json5": "^0.0.29",
|
||||
"json5": "^1.0.1",
|
||||
|
@ -25990,9 +26031,9 @@
|
|||
}
|
||||
},
|
||||
"axe-core": {
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.3.tgz",
|
||||
"integrity": "sha512-/lqqLAmuIPi79WYfRpy2i8z+x+vxU3zX2uAm0gs1q52qTuKwolOj1P8XbufpXcsydrpKx2yGn2wzAnxCMV86QA=="
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz",
|
||||
"integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA=="
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.24.0",
|
||||
|
@ -28635,6 +28676,37 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"eslint-config-airbnb": {
|
||||
"version": "19.0.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz",
|
||||
"integrity": "sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"object.assign": "^4.1.2",
|
||||
"object.entries": "^1.1.5"
|
||||
}
|
||||
},
|
||||
"eslint-config-airbnb-base": {
|
||||
"version": "15.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz",
|
||||
"integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"confusing-browser-globals": "^1.0.10",
|
||||
"object.assign": "^4.1.2",
|
||||
"object.entries": "^1.1.5",
|
||||
"semver": "^6.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"eslint-config-react-app": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-6.0.0.tgz",
|
||||
|
@ -28672,13 +28744,12 @@
|
|||
}
|
||||
},
|
||||
"eslint-module-utils": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz",
|
||||
"integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==",
|
||||
"version": "2.7.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.2.tgz",
|
||||
"integrity": "sha512-zquepFnWCY2ISMFwD/DqzaM++H+7PDzOpUvotJWm/y1BAFt5R4oeULgdrTejKqLkz7MA/tgstsUMNYc7wNdTrg==",
|
||||
"requires": {
|
||||
"debug": "^3.2.7",
|
||||
"find-up": "^2.1.0",
|
||||
"pkg-dir": "^2.0.0"
|
||||
"find-up": "^2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
|
@ -28731,14 +28802,6 @@
|
|||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
|
||||
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
|
||||
},
|
||||
"pkg-dir": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz",
|
||||
"integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=",
|
||||
"requires": {
|
||||
"find-up": "^2.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -28752,23 +28815,23 @@
|
|||
}
|
||||
},
|
||||
"eslint-plugin-import": {
|
||||
"version": "2.25.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.2.tgz",
|
||||
"integrity": "sha512-qCwQr9TYfoBHOFcVGKY9C9unq05uOxxdklmBXLVvcwo68y5Hta6/GzCZEMx2zQiu0woKNEER0LE7ZgaOfBU14g==",
|
||||
"version": "2.25.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz",
|
||||
"integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==",
|
||||
"requires": {
|
||||
"array-includes": "^3.1.4",
|
||||
"array.prototype.flat": "^1.2.5",
|
||||
"debug": "^2.6.9",
|
||||
"doctrine": "^2.1.0",
|
||||
"eslint-import-resolver-node": "^0.3.6",
|
||||
"eslint-module-utils": "^2.7.0",
|
||||
"eslint-module-utils": "^2.7.2",
|
||||
"has": "^1.0.3",
|
||||
"is-core-module": "^2.7.0",
|
||||
"is-core-module": "^2.8.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "^3.0.4",
|
||||
"object.values": "^1.1.5",
|
||||
"resolve": "^1.20.0",
|
||||
"tsconfig-paths": "^3.11.0"
|
||||
"tsconfig-paths": "^3.12.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
|
@ -28812,21 +28875,22 @@
|
|||
}
|
||||
},
|
||||
"eslint-plugin-jsx-a11y": {
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz",
|
||||
"integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==",
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz",
|
||||
"integrity": "sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.11.2",
|
||||
"@babel/runtime": "^7.16.3",
|
||||
"aria-query": "^4.2.2",
|
||||
"array-includes": "^3.1.1",
|
||||
"array-includes": "^3.1.4",
|
||||
"ast-types-flow": "^0.0.7",
|
||||
"axe-core": "^4.0.2",
|
||||
"axe-core": "^4.3.5",
|
||||
"axobject-query": "^2.2.0",
|
||||
"damerau-levenshtein": "^1.0.6",
|
||||
"emoji-regex": "^9.0.0",
|
||||
"damerau-levenshtein": "^1.0.7",
|
||||
"emoji-regex": "^9.2.2",
|
||||
"has": "^1.0.3",
|
||||
"jsx-ast-utils": "^3.1.0",
|
||||
"language-tags": "^1.0.5"
|
||||
"jsx-ast-utils": "^3.2.1",
|
||||
"language-tags": "^1.0.5",
|
||||
"minimatch": "^3.0.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"emoji-regex": {
|
||||
|
@ -28837,24 +28901,24 @@
|
|||
}
|
||||
},
|
||||
"eslint-plugin-react": {
|
||||
"version": "7.26.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.26.1.tgz",
|
||||
"integrity": "sha512-Lug0+NOFXeOE+ORZ5pbsh6mSKjBKXDXItUD2sQoT+5Yl0eoT82DqnXeTMfUare4QVCn9QwXbfzO/dBLjLXwVjQ==",
|
||||
"version": "7.28.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz",
|
||||
"integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==",
|
||||
"requires": {
|
||||
"array-includes": "^3.1.3",
|
||||
"array.prototype.flatmap": "^1.2.4",
|
||||
"array-includes": "^3.1.4",
|
||||
"array.prototype.flatmap": "^1.2.5",
|
||||
"doctrine": "^2.1.0",
|
||||
"estraverse": "^5.2.0",
|
||||
"estraverse": "^5.3.0",
|
||||
"jsx-ast-utils": "^2.4.1 || ^3.0.0",
|
||||
"minimatch": "^3.0.4",
|
||||
"object.entries": "^1.1.4",
|
||||
"object.fromentries": "^2.0.4",
|
||||
"object.hasown": "^1.0.0",
|
||||
"object.values": "^1.1.4",
|
||||
"object.entries": "^1.1.5",
|
||||
"object.fromentries": "^2.0.5",
|
||||
"object.hasown": "^1.1.0",
|
||||
"object.values": "^1.1.5",
|
||||
"prop-types": "^15.7.2",
|
||||
"resolve": "^2.0.0-next.3",
|
||||
"semver": "^6.3.0",
|
||||
"string.prototype.matchall": "^4.0.5"
|
||||
"string.prototype.matchall": "^4.0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"doctrine": {
|
||||
|
@ -28866,9 +28930,9 @@
|
|||
}
|
||||
},
|
||||
"estraverse": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
|
||||
"integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ=="
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
|
||||
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="
|
||||
},
|
||||
"resolve": {
|
||||
"version": "2.0.0-next.3",
|
||||
|
@ -28887,9 +28951,9 @@
|
|||
}
|
||||
},
|
||||
"eslint-plugin-react-hooks": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz",
|
||||
"integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==",
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz",
|
||||
"integrity": "sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==",
|
||||
"requires": {}
|
||||
},
|
||||
"eslint-plugin-testing-library": {
|
||||
|
@ -37426,9 +37490,9 @@
|
|||
"integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw=="
|
||||
},
|
||||
"tsconfig-paths": {
|
||||
"version": "3.11.0",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz",
|
||||
"integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==",
|
||||
"version": "3.12.0",
|
||||
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz",
|
||||
"integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==",
|
||||
"requires": {
|
||||
"@types/json5": "^0.0.29",
|
||||
"json5": "^1.0.1",
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
"eject": "react-scripts eject",
|
||||
"lint": "eslint src --ext .js,.jsx",
|
||||
"lint:fix": "npm run lint -- --fix"
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.7.1",
|
||||
|
@ -32,6 +34,9 @@
|
|||
"styled-components": "^5.3.3",
|
||||
"web-vitals": "^1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint-config-airbnb": "^19.0.4"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
|
|
41
src/App.js
41
src/App.js
|
@ -1,42 +1,29 @@
|
|||
import CssBaseline from '@mui/material/CssBaseline';
|
||||
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
||||
import React, { useState } from 'react';
|
||||
import Login from "./components/views/login";
|
||||
import UserAdmin from "./components/views/useradmin";
|
||||
import Login from './components/views/login';
|
||||
import UserAdmin from './components/views/useradmin';
|
||||
import GlobalSnack from './components/widgets/globalSnack';
|
||||
import DeviceStore from "./context/devices";
|
||||
import ToastStore from "./context/toast";
|
||||
import { UserProvider } from "./context/users";
|
||||
import * as authenticationController from "./controllers/authentication";
|
||||
|
||||
|
||||
import DeviceStore from './context/devices';
|
||||
import ToastStore from './context/toast';
|
||||
import { UserProvider } from './context/users';
|
||||
import * as authenticationController from './controllers/authentication';
|
||||
|
||||
// Connection opened
|
||||
|
||||
|
||||
|
||||
|
||||
function App() {
|
||||
|
||||
|
||||
const [session, setSession] = useState(false)
|
||||
const [session, setSession] = useState(false);
|
||||
|
||||
authenticationController.getSession().then((res) => {
|
||||
setSession(res.data.authenticated)
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
setSession(res.data.authenticated);
|
||||
});
|
||||
|
||||
const theme = React.useMemo(
|
||||
() =>
|
||||
createTheme({
|
||||
palette: {
|
||||
mode: window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light',
|
||||
},
|
||||
}),
|
||||
() => createTheme({
|
||||
palette: {
|
||||
mode: window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light',
|
||||
},
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
|
|
|
@ -2,5 +2,5 @@ import { render, screen } from '@testing-library/react';
|
|||
import App from './App';
|
||||
|
||||
test('renders learn react link', () => {
|
||||
render(<p></p>);
|
||||
render(<p />);
|
||||
});
|
||||
|
|
|
@ -6,123 +6,119 @@ import DrivesTable from './tabPane';
|
|||
|
||||
function DeviceLastSeenMap() {
|
||||
return (
|
||||
<div style={{ height: "500px", width: 'calc(100%)' }}>
|
||||
<div style={{ height: '500px', width: 'calc(100%)' }}>
|
||||
|
||||
<GoogleMapReact
|
||||
height="100px"
|
||||
bootstrapURLKeys={{ key: process.env.REACT_APP_GMAPS_API_KEY }}
|
||||
defaultCenter={{
|
||||
lat: 51.501134,
|
||||
lng: -0.142318
|
||||
}}
|
||||
defaultZoom={17}
|
||||
options={{
|
||||
styles: [
|
||||
{ elementType: "geometry", stylers: [{ color: "#242f3e" }] },
|
||||
{ elementType: "labels.text.stroke", stylers: [{ color: "#242f3e" }] },
|
||||
{ elementType: "labels.text.fill", stylers: [{ color: "#746855" }] },
|
||||
{
|
||||
featureType: "administrative.locality",
|
||||
elementType: "labels.text.fill",
|
||||
stylers: [{ color: "#d59563" }],
|
||||
},
|
||||
{
|
||||
featureType: "poi",
|
||||
elementType: "labels.text.fill",
|
||||
stylers: [{ color: "#d59563" }],
|
||||
},
|
||||
{
|
||||
featureType: "poi.park",
|
||||
elementType: "geometry",
|
||||
stylers: [{ color: "#263c3f" }],
|
||||
},
|
||||
{
|
||||
featureType: "poi.park",
|
||||
elementType: "labels.text.fill",
|
||||
stylers: [{ color: "#6b9a76" }],
|
||||
},
|
||||
{
|
||||
featureType: "road",
|
||||
elementType: "geometry",
|
||||
stylers: [{ color: "#38414e" }],
|
||||
},
|
||||
{
|
||||
featureType: "road",
|
||||
elementType: "geometry.stroke",
|
||||
stylers: [{ color: "#212a37" }],
|
||||
},
|
||||
{
|
||||
featureType: "road",
|
||||
elementType: "labels.text.fill",
|
||||
stylers: [{ color: "#9ca5b3" }],
|
||||
},
|
||||
{
|
||||
featureType: "road.highway",
|
||||
elementType: "geometry",
|
||||
stylers: [{ color: "#746855" }],
|
||||
},
|
||||
{
|
||||
featureType: "road.highway",
|
||||
elementType: "geometry.stroke",
|
||||
stylers: [{ color: "#1f2835" }],
|
||||
},
|
||||
{
|
||||
featureType: "road.highway",
|
||||
elementType: "labels.text.fill",
|
||||
stylers: [{ color: "#f3d19c" }],
|
||||
},
|
||||
{
|
||||
featureType: "transit",
|
||||
elementType: "geometry",
|
||||
stylers: [{ color: "#2f3948" }],
|
||||
},
|
||||
{
|
||||
featureType: "transit.station",
|
||||
elementType: "labels.text.fill",
|
||||
stylers: [{ color: "#d59563" }],
|
||||
},
|
||||
{
|
||||
featureType: "water",
|
||||
elementType: "geometry",
|
||||
stylers: [{ color: "#17263c" }],
|
||||
},
|
||||
{
|
||||
featureType: "water",
|
||||
elementType: "labels.text.fill",
|
||||
stylers: [{ color: "#515c6d" }],
|
||||
},
|
||||
{
|
||||
featureType: "water",
|
||||
elementType: "labels.text.stroke",
|
||||
stylers: [{ color: "#17263c" }],
|
||||
},
|
||||
],
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
<GoogleMapReact
|
||||
height="100px"
|
||||
bootstrapURLKeys={{ key: process.env.REACT_APP_GMAPS_API_KEY }}
|
||||
defaultCenter={{
|
||||
lat: 51.501134,
|
||||
lng: -0.142318,
|
||||
}}
|
||||
defaultZoom={17}
|
||||
options={{
|
||||
styles: [
|
||||
{ elementType: 'geometry', stylers: [{ color: '#242f3e' }] },
|
||||
{ elementType: 'labels.text.stroke', stylers: [{ color: '#242f3e' }] },
|
||||
{ elementType: 'labels.text.fill', stylers: [{ color: '#746855' }] },
|
||||
{
|
||||
featureType: 'administrative.locality',
|
||||
elementType: 'labels.text.fill',
|
||||
stylers: [{ color: '#d59563' }],
|
||||
},
|
||||
{
|
||||
featureType: 'poi',
|
||||
elementType: 'labels.text.fill',
|
||||
stylers: [{ color: '#d59563' }],
|
||||
},
|
||||
{
|
||||
featureType: 'poi.park',
|
||||
elementType: 'geometry',
|
||||
stylers: [{ color: '#263c3f' }],
|
||||
},
|
||||
{
|
||||
featureType: 'poi.park',
|
||||
elementType: 'labels.text.fill',
|
||||
stylers: [{ color: '#6b9a76' }],
|
||||
},
|
||||
{
|
||||
featureType: 'road',
|
||||
elementType: 'geometry',
|
||||
stylers: [{ color: '#38414e' }],
|
||||
},
|
||||
{
|
||||
featureType: 'road',
|
||||
elementType: 'geometry.stroke',
|
||||
stylers: [{ color: '#212a37' }],
|
||||
},
|
||||
{
|
||||
featureType: 'road',
|
||||
elementType: 'labels.text.fill',
|
||||
stylers: [{ color: '#9ca5b3' }],
|
||||
},
|
||||
{
|
||||
featureType: 'road.highway',
|
||||
elementType: 'geometry',
|
||||
stylers: [{ color: '#746855' }],
|
||||
},
|
||||
{
|
||||
featureType: 'road.highway',
|
||||
elementType: 'geometry.stroke',
|
||||
stylers: [{ color: '#1f2835' }],
|
||||
},
|
||||
{
|
||||
featureType: 'road.highway',
|
||||
elementType: 'labels.text.fill',
|
||||
stylers: [{ color: '#f3d19c' }],
|
||||
},
|
||||
{
|
||||
featureType: 'transit',
|
||||
elementType: 'geometry',
|
||||
stylers: [{ color: '#2f3948' }],
|
||||
},
|
||||
{
|
||||
featureType: 'transit.station',
|
||||
elementType: 'labels.text.fill',
|
||||
stylers: [{ color: '#d59563' }],
|
||||
},
|
||||
{
|
||||
featureType: 'water',
|
||||
elementType: 'geometry',
|
||||
stylers: [{ color: '#17263c' }],
|
||||
},
|
||||
{
|
||||
featureType: 'water',
|
||||
elementType: 'labels.text.fill',
|
||||
stylers: [{ color: '#515c6d' }],
|
||||
},
|
||||
{
|
||||
featureType: 'water',
|
||||
elementType: 'labels.text.stroke',
|
||||
stylers: [{ color: '#17263c' }],
|
||||
},
|
||||
],
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export default function SignIn(props) {
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
}}>
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
|
||||
<Scrollbars autoHeightMin="100%" autoHeightMax="100%">
|
||||
<Grid container style={{padding: 30}}>
|
||||
<Grid container style={{ padding: 30 }}>
|
||||
<Grid item xs={12}>
|
||||
<DeviceLastSeenMap />
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12}>
|
||||
<DrivesTable dongleId={props.device.dongle_id}/>
|
||||
<DrivesTable dongleId={props.device.dongle_id} />
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
@ -131,5 +127,3 @@ export default function SignIn(props) {
|
|||
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -5,35 +5,26 @@ import Grid from '@mui/material/Grid';
|
|||
import Typography from '@mui/material/Typography';
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
|
||||
|
||||
const stylezz = {
|
||||
margin: '0px 2px 0px 0px',
|
||||
}
|
||||
};
|
||||
|
||||
function timeSince(date) {
|
||||
|
||||
|
||||
|
||||
var seconds = Math.floor((new Date() - date) / 1000);
|
||||
const seconds = Math.floor((new Date() - date) / 1000);
|
||||
|
||||
if (seconds / 86400 > 1) {
|
||||
return Math.floor(seconds / 86400) + `d`;
|
||||
} else if (seconds / 3600 > 1) {
|
||||
return Math.floor(seconds / 3600) + `h`;
|
||||
} else if (seconds / 60 > 1) {
|
||||
return Math.floor(seconds / 60) + `m`;
|
||||
} else {
|
||||
return "just now";
|
||||
return `${Math.floor(seconds / 86400)}d`;
|
||||
} if (seconds / 3600 > 1) {
|
||||
return `${Math.floor(seconds / 3600)}h`;
|
||||
} if (seconds / 60 > 1) {
|
||||
return `${Math.floor(seconds / 60)}m`;
|
||||
}
|
||||
|
||||
return 'just now';
|
||||
}
|
||||
|
||||
|
||||
export default function SignIn(props) {
|
||||
|
||||
const [state, setState] = React.useState({ count: 0, last_seen: 0 });
|
||||
const device = props.device;
|
||||
const { device } = props;
|
||||
|
||||
// Reloads component to update X time ago
|
||||
// TODO prevent X time ago from being refreshed when the device has been
|
||||
|
@ -41,21 +32,18 @@ export default function SignIn(props) {
|
|||
|
||||
useEffect(() => {
|
||||
setInterval(() => {
|
||||
setState({ ...state, count: state.count + 1 })
|
||||
}, 60 * 1000)
|
||||
setState({ ...state, count: state.count + 1 });
|
||||
}, 60 * 1000);
|
||||
});
|
||||
|
||||
|
||||
const deviceLastSeen = timeSince(new Date(device.last_seen));
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ButtonBase style={{ padding: '10px' }}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={4}>
|
||||
<img src="/c3.webp" style={{ width: "100%" }} alt="device icon"/>
|
||||
<img src="/c3.webp" style={{ width: '100%' }} alt="device icon" />
|
||||
</Grid>
|
||||
<Grid item xs={8} style={{ textAlign: 'left' }}>
|
||||
{/* <TextField
|
||||
|
@ -77,16 +65,17 @@ export default function SignIn(props) {
|
|||
}}
|
||||
fullWidth
|
||||
|
||||
|
||||
/>*/}
|
||||
<Typography variant="body2" align={"left"} gutterBottom>Dongle: {device.dongle_id}</Typography>
|
||||
/> */}
|
||||
<Typography variant="body2" align="left" gutterBottom>
|
||||
Dongle:
|
||||
{device.dongle_id}
|
||||
</Typography>
|
||||
|
||||
<div>
|
||||
|
||||
{device.online ?
|
||||
<Chip style={{ background: '#004d40', ...stylezz }} label="Online" size="small" variant="outlined" /> :
|
||||
<Chip style={{ background: '#b71c1c', ...stylezz }} label={`Offline ${deviceLastSeen}`} size="small" variant="outlined" />
|
||||
}
|
||||
{device.online
|
||||
? <Chip style={{ background: '#004d40', ...stylezz }} label="Online" size="small" variant="outlined" />
|
||||
: <Chip style={{ background: '#b71c1c', ...stylezz }} label={`Offline ${deviceLastSeen}`} size="small" variant="outlined" />}
|
||||
|
||||
<Chip style={{ background: '#004d40', ...stylezz }} label="Active" size="small" variant="outlined" />
|
||||
</div>
|
||||
|
@ -98,5 +87,3 @@ export default function SignIn(props) {
|
|||
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -13,39 +13,36 @@ import TableHead from '@mui/material/TableHead';
|
|||
import TableRow from '@mui/material/TableRow';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import React, { useContext, useEffect } from 'react';
|
||||
import { context as DeviceContext } from "./../../../context/devices";
|
||||
import { context as SnackbarContext } from "./../../../context/toast";
|
||||
import * as deviceController from "./../../../controllers/devices";
|
||||
import * as helpers from "./../../../controllers/helpers"
|
||||
|
||||
import { context as DeviceContext } from '../../../context/devices';
|
||||
import { context as SnackbarContext } from '../../../context/toast';
|
||||
import * as deviceController from '../../../controllers/devices';
|
||||
import * as helpers from '../../../controllers/helpers';
|
||||
|
||||
function loading() {
|
||||
return (
|
||||
<TableRow>
|
||||
<TableCell ><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell ><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell ><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell ><Skeleton animation="wave" /></TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
<TableCell><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell><Skeleton animation="wave" /></TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
|
||||
export default function EnhancedTable(props) {
|
||||
const [state, dispatch] = useContext(DeviceContext)
|
||||
const [state, dispatch] = useContext(DeviceContext);
|
||||
|
||||
const [, notifDispatch] = useContext(SnackbarContext)
|
||||
const [, notifDispatch] = useContext(SnackbarContext);
|
||||
|
||||
useEffect(() => {
|
||||
deviceController.getBootlogs(props.dongleId).then((res) => {
|
||||
setTimeout(() => {
|
||||
dispatch({ type: "update_dongle_bootlogs", dongle_id: props.dongleId, bootlogs: res.data })
|
||||
}, 1)
|
||||
dispatch({ type: 'update_dongle_bootlogs', dongle_id: props.dongleId, bootlogs: res.data });
|
||||
}, 1);
|
||||
}).catch(() => {
|
||||
notifDispatch({type: "NEW_TOAST", msg: 'Failed to load bootlogs'})
|
||||
})
|
||||
|
||||
}, [dispatch, notifDispatch, props.dongleId])
|
||||
notifDispatch({ type: 'NEW_TOAST', msg: 'Failed to load bootlogs' });
|
||||
});
|
||||
}, [dispatch, notifDispatch, props.dongleId]);
|
||||
|
||||
return (
|
||||
<Box sx={{ width: '100%' }}>
|
||||
|
@ -54,51 +51,48 @@ export default function EnhancedTable(props) {
|
|||
<Table
|
||||
sx={{ minWidth: 750 }}
|
||||
aria-labelledby="tableTitle"
|
||||
size={'small'}
|
||||
size="small"
|
||||
>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell >Date</TableCell>
|
||||
<TableCell >File</TableCell>
|
||||
<TableCell >File size</TableCell>
|
||||
<TableCell >Actions</TableCell>
|
||||
<TableCell>Date</TableCell>
|
||||
<TableCell>File</TableCell>
|
||||
<TableCell>File size</TableCell>
|
||||
<TableCell>Actions</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
|
||||
<TableBody>
|
||||
{/* if you don't need to support IE11, you can replace the `stableSort` call with:
|
||||
rows.slice().sort(getComparator(order, orderBy)) */}
|
||||
{state.dongles[props.dongleId].boot ? state.dongles[props.dongleId].boot.map((row) => {
|
||||
return (
|
||||
<TableRow hover>
|
||||
<TableCell >{helpers.formatDate(row.date)}</TableCell>
|
||||
<TableCell >{row.name}</TableCell>
|
||||
<TableCell >{Math.round(row.size / 1024) + ' MiB'}</TableCell>
|
||||
<TableCell>
|
||||
{state.dongles[props.dongleId].boot ? state.dongles[props.dongleId].boot.map((row) => (
|
||||
<TableRow hover>
|
||||
<TableCell>{helpers.formatDate(row.date)}</TableCell>
|
||||
<TableCell>{row.name}</TableCell>
|
||||
<TableCell>{`${Math.round(row.size / 1024)} MiB`}</TableCell>
|
||||
<TableCell>
|
||||
<Tooltip title="Open in new window">
|
||||
|
||||
<IconButton size="small" onClick={() => window.open(row.permalink, "_blank")}>
|
||||
<OpenInNewIcon fontSize="inherit"/>
|
||||
<IconButton size="small" onClick={() => window.open(row.permalink, '_blank')}>
|
||||
<OpenInNewIcon fontSize="inherit" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="Preserve">
|
||||
<IconButton size="small">
|
||||
<FavoriteBorderIcon fontSize="inherit"/>
|
||||
<FavoriteBorderIcon fontSize="inherit" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip title="Delete">
|
||||
<IconButton size="small">
|
||||
<DeleteIcon fontSize="inherit"/>
|
||||
</IconButton>
|
||||
<DeleteIcon fontSize="inherit" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
|
||||
}) : [1, 1, 1, 1, 1].map(loading) }
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)) : [1, 1, 1, 1, 1].map(loading) }
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
|
@ -106,4 +100,3 @@ export default function EnhancedTable(props) {
|
|||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
|
||||
|
@ -15,13 +15,9 @@ import TableHead from '@mui/material/TableHead';
|
|||
import TableRow from '@mui/material/TableRow';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import React, { useContext, useEffect } from 'react';
|
||||
import { context as DeviceContext } from "./../../../context/devices";
|
||||
import * as deviceController from "./../../../controllers/devices";
|
||||
import * as helpers from "./../../../controllers/helpers"
|
||||
|
||||
|
||||
|
||||
|
||||
import { context as DeviceContext } from '../../../context/devices';
|
||||
import * as deviceController from '../../../controllers/devices';
|
||||
import * as helpers from '../../../controllers/helpers';
|
||||
|
||||
function buildContent(row) {
|
||||
return (
|
||||
|
@ -29,15 +25,13 @@ function buildContent(row) {
|
|||
hover
|
||||
>
|
||||
|
||||
|
||||
<TableCell >{helpers.formatDate(row.date)}</TableCell>
|
||||
<TableCell >{row.name}</TableCell>
|
||||
<TableCell >{Math.round(row.size / 1024) + ' MiB'}</TableCell>
|
||||
|
||||
<TableCell>{helpers.formatDate(row.date)}</TableCell>
|
||||
<TableCell>{row.name}</TableCell>
|
||||
<TableCell>{`${Math.round(row.size / 1024)} MiB`}</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<Tooltip title="Open in new window">
|
||||
<IconButton size="small" onClick={() => window.open(row.permalink, "_blank")}>
|
||||
<IconButton size="small" onClick={() => window.open(row.permalink, '_blank')}>
|
||||
<OpenInNewIcon fontSize="inherit" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
|
@ -56,31 +50,31 @@ function buildContent(row) {
|
|||
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function loading() {
|
||||
return (
|
||||
<TableRow>
|
||||
<TableCell ><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell ><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell ><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell ><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell><Skeleton animation="wave" /></TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default function EnhancedTable(props) {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const [state, dispatch] = useContext(DeviceContext)
|
||||
const [state, dispatch] = useContext(DeviceContext);
|
||||
useEffect(() => {
|
||||
deviceController.getCrashlogs(props.dongleId).then((res) => {
|
||||
dispatch({ type: "update_dongle_bootlogs", dongle_id: props.dongleId, bootlogs: res.data })
|
||||
})
|
||||
dispatch({ type: 'update_dongle_bootlogs', dongle_id: props.dongleId, bootlogs: res.data });
|
||||
});
|
||||
}, [dispatch, props.dongleId]);
|
||||
|
||||
console.log("drives", state.dongles[props.dongleId])
|
||||
console.log("drives", typeof state.dongles[props.dongleId])
|
||||
console.log('drives', state.dongles[props.dongleId]);
|
||||
console.log('drives', typeof state.dongles[props.dongleId]);
|
||||
|
||||
return (
|
||||
<Box sx={{ width: '100%' }}>
|
||||
|
@ -89,23 +83,21 @@ export default function EnhancedTable(props) {
|
|||
<Table
|
||||
sx={{ minWidth: 750 }}
|
||||
aria-labelledby="tableTitle"
|
||||
size={'small'}
|
||||
size="small"
|
||||
>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell >Date</TableCell>
|
||||
<TableCell >File</TableCell>
|
||||
<TableCell >File size</TableCell>
|
||||
<TableCell >Actions</TableCell>
|
||||
<TableCell>Date</TableCell>
|
||||
<TableCell>File</TableCell>
|
||||
<TableCell>File size</TableCell>
|
||||
<TableCell>Actions</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
|
||||
<TableBody>
|
||||
{state.dongles[props.dongleId].crash ?
|
||||
state.dongles[props.dongleId].crash.length > 0 ? state.dongles[props.dongleId].crash.map(buildContent) : <p> No drives </p>
|
||||
:
|
||||
[1, 1, 1, 1, 1].map(loading)
|
||||
}
|
||||
{state.dongles[props.dongleId].crash
|
||||
? state.dongles[props.dongleId].crash.length > 0 ? state.dongles[props.dongleId].crash.map(buildContent) : <p> No drives </p>
|
||||
: [1, 1, 1, 1, 1].map(loading)}
|
||||
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
@ -115,4 +107,3 @@ export default function EnhancedTable(props) {
|
|||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,47 +1,37 @@
|
|||
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import Skeleton from "@mui/material/Skeleton";
|
||||
import Skeleton from '@mui/material/Skeleton';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import React, { useContext } from 'react';
|
||||
import { context as DeviceContext } from "./../../../context/devices";
|
||||
import { context as SnackbarContext } from "./../../../context/toast";
|
||||
import * as helpers from "./../../../controllers/helpers"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
import { context as DeviceContext } from '../../../context/devices';
|
||||
import { context as SnackbarContext } from '../../../context/toast';
|
||||
import * as helpers from '../../../controllers/helpers';
|
||||
|
||||
export default function SignIn(props) {
|
||||
|
||||
const [state] = useContext(DeviceContext)
|
||||
const [, notifDispatch] = useContext(SnackbarContext)
|
||||
const [state] = useContext(DeviceContext);
|
||||
const [, notifDispatch] = useContext(SnackbarContext);
|
||||
|
||||
function pubKeyClipboard(newClip) {
|
||||
navigator.clipboard.writeText(newClip).then(function () {
|
||||
navigator.clipboard.writeText(newClip).then(() => {
|
||||
notifDispatch({
|
||||
type: "NEW_TOAST",
|
||||
type: 'NEW_TOAST',
|
||||
open: true,
|
||||
msg: "Successfully copied to clipboard!"
|
||||
})
|
||||
}, function () {
|
||||
msg: 'Successfully copied to clipboard!',
|
||||
});
|
||||
}, () => {
|
||||
notifDispatch({
|
||||
type: "NEW_TOAST",
|
||||
type: 'NEW_TOAST',
|
||||
open: true,
|
||||
msg: "Failed to write to clipboard!"
|
||||
})
|
||||
msg: 'Failed to write to clipboard!',
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (!state.dongles[props.dongleId]) { return (<p>no</p>) }
|
||||
if (!state.dongles[props.dongleId]) { return (<p>no</p>); }
|
||||
const dongle = state.dongles[props.dongleId];
|
||||
|
||||
|
||||
if (!dongle) {
|
||||
return (
|
||||
<Grid container>
|
||||
|
@ -53,7 +43,7 @@ export default function SignIn(props) {
|
|||
|
||||
</Grid>
|
||||
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -63,29 +53,47 @@ export default function SignIn(props) {
|
|||
<Grid container>
|
||||
<Grid item xs={3}>
|
||||
|
||||
|
||||
<b>Nickname:</b> {dongle.nick_name ? dongle.nick_name : `My ${dongle.device_type}`}<br></br>
|
||||
<b>Type:</b> {dongle.device_type}<br></br>
|
||||
<b>Serial:</b> {dongle.serial}<br></br>
|
||||
<b>IMEI:</b> {dongle.imei}<br></br>
|
||||
<b>Registered:</b> {helpers.formatDate(dongle.created)}<br></br>
|
||||
<b>Last Ping:</b> {helpers.formatDate(dongle.last_ping)}<br></br>
|
||||
<b>Public Key:</b> -----BEGIN PUBLIC KEY-----
|
||||
<b>Nickname:</b>
|
||||
{' '}
|
||||
{dongle.nick_name ? dongle.nick_name : `My ${dongle.device_type}`}
|
||||
<br />
|
||||
<b>Type:</b>
|
||||
{' '}
|
||||
{dongle.device_type}
|
||||
<br />
|
||||
<b>Serial:</b>
|
||||
{' '}
|
||||
{dongle.serial}
|
||||
<br />
|
||||
<b>IMEI:</b>
|
||||
{' '}
|
||||
{dongle.imei}
|
||||
<br />
|
||||
<b>Registered:</b>
|
||||
{' '}
|
||||
{helpers.formatDate(dongle.created)}
|
||||
<br />
|
||||
<b>Last Ping:</b>
|
||||
{' '}
|
||||
{helpers.formatDate(dongle.last_ping)}
|
||||
<br />
|
||||
<b>Public Key:</b>
|
||||
{' '}
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
<Tooltip title="Copy public key">
|
||||
<IconButton onClick={() => pubKeyClipboard(dongle.public_key)}>
|
||||
<ContentCopyIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<br></br>
|
||||
<br />
|
||||
|
||||
|
||||
<b>Quota Storage: </b>{dongle.storage_used} MB / 200000 MB
|
||||
<b>Quota Storage: </b>
|
||||
{dongle.storage_used}
|
||||
{' '}
|
||||
MB / 200000 MB
|
||||
</Grid>
|
||||
|
||||
|
||||
</Grid>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -13,26 +13,26 @@ import TableHead from '@mui/material/TableHead';
|
|||
import TableRow from '@mui/material/TableRow';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { context as DeviceContext } from "./../../../context/devices";
|
||||
import { context as SnackbarContext } from "./../../../context/toast";
|
||||
import * as deviceController from "./../../../controllers/devices";
|
||||
import * as helpers from "./../../../controllers/helpers"
|
||||
import ViewDrive from "./view_drive"
|
||||
import { context as DeviceContext } from '../../../context/devices';
|
||||
import { context as SnackbarContext } from '../../../context/toast';
|
||||
import * as deviceController from '../../../controllers/devices';
|
||||
import * as helpers from '../../../controllers/helpers';
|
||||
import ViewDrive from './view_drive';
|
||||
|
||||
export default function EnhancedTable(props) {
|
||||
const [deviceState, dispatch] = useContext(DeviceContext)
|
||||
const [, notifDispatch] = useContext(SnackbarContext)
|
||||
const [state, setState] = useState({selectedSegment: null})
|
||||
const [deviceState, dispatch] = useContext(DeviceContext);
|
||||
const [, notifDispatch] = useContext(SnackbarContext);
|
||||
const [state, setState] = useState({ selectedSegment: null });
|
||||
|
||||
useEffect(() => {
|
||||
deviceController.getDrives(props.dongleId).then((res) => {
|
||||
setTimeout(() => {
|
||||
dispatch({ type: "update_dongle_drive", dongle_id: props.dongleId, drives: res.data })
|
||||
}, 1)
|
||||
dispatch({ type: 'update_dongle_drive', dongle_id: props.dongleId, drives: res.data });
|
||||
}, 1);
|
||||
}).catch(() => {
|
||||
notifDispatch({type: "NEW_TOAST", msg: 'Failed to load drives'})
|
||||
})
|
||||
}, [dispatch, notifDispatch, props.dongleId])
|
||||
notifDispatch({ type: 'NEW_TOAST', msg: 'Failed to load drives' });
|
||||
});
|
||||
}, [dispatch, notifDispatch, props.dongleId]);
|
||||
|
||||
return (
|
||||
<Box sx={{ width: '100%' }}>
|
||||
|
@ -41,7 +41,7 @@ export default function EnhancedTable(props) {
|
|||
<Table
|
||||
sx={{ minWidth: 750 }}
|
||||
aria-labelledby="tableTitle"
|
||||
size={'small'}
|
||||
size="small"
|
||||
>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
|
@ -65,25 +65,27 @@ export default function EnhancedTable(props) {
|
|||
let metadata;
|
||||
|
||||
try {
|
||||
metadata = JSON.parse(row.metadata)
|
||||
} catch (err) { metadata = {} }
|
||||
metadata = JSON.parse(row.metadata);
|
||||
} catch (err) { metadata = {}; }
|
||||
return (
|
||||
<TableRow
|
||||
hover
|
||||
onClick={()=>{state.selectedSegment === index ? setState({...state, selectedSegment: null }) : setState({...state, selectedSegment: index })}}
|
||||
onClick={() => { state.selectedSegment === index ? setState({ ...state, selectedSegment: null }) : setState({ ...state, selectedSegment: index }); }}
|
||||
>
|
||||
<TableCell
|
||||
scope="row"
|
||||
>{row.identifier}</TableCell>
|
||||
>
|
||||
{row.identifier}
|
||||
</TableCell>
|
||||
|
||||
<TableCell >{metadata.hasOwnProperty('CarParams1') ? metadata.CarParams['CarName'] : "Glorious Skoda"}</TableCell>
|
||||
<TableCell >{metadata.hasOwnProperty('InitData1') ? metadata.InitData['Version'] : "Lemon boy"}</TableCell>
|
||||
<TableCell >{Math.round(row.filesize / 1024) + ' MiB'}</TableCell>
|
||||
<TableCell >{helpers.formatDuration(row.duration)}</TableCell>
|
||||
<TableCell >{Math.round(row.distance_meters / 1000)}</TableCell>
|
||||
<TableCell >{row.upload_complete.toString()}</TableCell>
|
||||
<TableCell >{row.is_processed.toString()}</TableCell>
|
||||
<TableCell >{helpers.formatDate(row.drive_date)}</TableCell>
|
||||
<TableCell>{metadata.hasOwnProperty('CarParams1') ? metadata.CarParams.CarName : 'Glorious Skoda'}</TableCell>
|
||||
<TableCell>{metadata.hasOwnProperty('InitData1') ? metadata.InitData.Version : 'Lemon boy'}</TableCell>
|
||||
<TableCell>{`${Math.round(row.filesize / 1024)} MiB`}</TableCell>
|
||||
<TableCell>{helpers.formatDuration(row.duration)}</TableCell>
|
||||
<TableCell>{Math.round(row.distance_meters / 1000)}</TableCell>
|
||||
<TableCell>{row.upload_complete.toString()}</TableCell>
|
||||
<TableCell>{row.is_processed.toString()}</TableCell>
|
||||
<TableCell>{helpers.formatDate(row.drive_date)}</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<Tooltip title="Open in new window">
|
||||
|
@ -106,13 +108,11 @@ export default function EnhancedTable(props) {
|
|||
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)
|
||||
);
|
||||
})
|
||||
|
||||
}) :
|
||||
|
||||
[1, 1, 1, 1, 1].map((v) => (
|
||||
<TableRow
|
||||
>
|
||||
: [1, 1, 1, 1, 1].map((v) => (
|
||||
<TableRow>
|
||||
<TableCell padding="checkbox">
|
||||
<Skeleton animation="wave" />
|
||||
</TableCell>
|
||||
|
@ -122,19 +122,16 @@ export default function EnhancedTable(props) {
|
|||
<Skeleton animation="wave" />
|
||||
</TableCell>
|
||||
|
||||
<TableCell ><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell ><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell ><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell ><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell ><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell ><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell ><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell ><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell><Skeleton animation="wave" /></TableCell>
|
||||
<TableCell><Skeleton animation="wave" /></TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
|
||||
|
||||
}
|
||||
))}
|
||||
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
@ -145,4 +142,3 @@ export default function EnhancedTable(props) {
|
|||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,17 +2,16 @@ import Box from '@mui/material/Box';
|
|||
import Tab from '@mui/material/Tab';
|
||||
import Tabs from '@mui/material/Tabs';
|
||||
import React from 'react';
|
||||
import BootLogsTable from "./boot";
|
||||
import BootLogsTable from './boot';
|
||||
import Console from './console';
|
||||
import CrashLogsTable from "./crash";
|
||||
import CrashLogsTable from './crash';
|
||||
import DeviceInfo from './device';
|
||||
import DrivesLogTable from "./drives";
|
||||
|
||||
|
||||
|
||||
import DrivesLogTable from './drives';
|
||||
|
||||
function TabPanel(props) {
|
||||
const { children, value, index, ...other } = props;
|
||||
const {
|
||||
children, value, index, ...other
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -31,10 +30,7 @@ function TabPanel(props) {
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default function SignIn(props) {
|
||||
|
||||
const [value, setValue] = React.useState(0);
|
||||
|
||||
const handleChange = (event, newValue) => {
|
||||
|
@ -45,8 +41,13 @@ export default function SignIn(props) {
|
|||
<div className="wrapper">
|
||||
|
||||
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
|
||||
<Tabs value={value} onChange={handleChange} aria-label="basic tabs example" variant="scrollable"
|
||||
scrollButtons="auto">
|
||||
<Tabs
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
aria-label="basic tabs example"
|
||||
variant="scrollable"
|
||||
scrollButtons="auto"
|
||||
>
|
||||
<Tab label="Device" />
|
||||
<Tab label="Drives" />
|
||||
<Tab label="Crashes" />
|
||||
|
@ -72,10 +73,7 @@ export default function SignIn(props) {
|
|||
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -10,177 +10,178 @@ import TableHead from '@mui/material/TableHead';
|
|||
import TableRow from '@mui/material/TableRow';
|
||||
import Tooltip from '@mui/material/Tooltip';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { context as DeviceContext } from "./../../../context/devices";
|
||||
import * as deviceController from "./../../../controllers/devices";
|
||||
import Typography from "@mui/material/Typography"
|
||||
|
||||
|
||||
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { context as DeviceContext } from '../../../context/devices';
|
||||
import * as deviceController from '../../../controllers/devices';
|
||||
|
||||
export default function EnhancedTable(props) {
|
||||
const [deviceState] = useContext(DeviceContext)
|
||||
const [deviceState] = useContext(DeviceContext);
|
||||
|
||||
const [state, setState] = useState({ loading: true, firstReqSent: false, segment: null, drive: null })
|
||||
const [state, setState] = useState({
|
||||
loading: true, firstReqSent: false, segment: null, drive: null,
|
||||
});
|
||||
|
||||
if (state.drive === null) {
|
||||
setState({ ...state, drive: props.drive })
|
||||
if (state.drive === null) {
|
||||
setState({ ...state, drive: props.drive });
|
||||
}
|
||||
|
||||
if (props.drive !== state.drive) {
|
||||
setState({
|
||||
...state, loading: true, firstReqSent: false, segment: null, drive: props.drive,
|
||||
});
|
||||
}
|
||||
|
||||
const dongle_id = props.dongleId;
|
||||
const drive_id = props.drive;
|
||||
const dongle = deviceState.dongles[dongle_id];
|
||||
console.log('view drive', dongle);
|
||||
console.log('drives', dongle.drives);
|
||||
if (!dongle || !dongle.drives) return (<p>loading</p>);
|
||||
|
||||
if (state.segment === null) {
|
||||
// TODO Make this not run multiple times
|
||||
deviceController.getDriveSegments(dongle_id, dongle.drives[drive_id].identifier).then((res) => {
|
||||
console.log('my res', res.data);
|
||||
if (res.data === null) {
|
||||
setState({
|
||||
...state, loading: false, firstReqSent: true, segment: [],
|
||||
});
|
||||
} else {
|
||||
setState({
|
||||
...state, loading: false, firstReqSent: true, segment: res.data,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// test
|
||||
|
||||
const drive = dongle.drives[drive_id];
|
||||
|
||||
let vehicle = '';
|
||||
let version = '';
|
||||
let gitRemote = '';
|
||||
let gitBranch = '';
|
||||
let gitCommit = '';
|
||||
let metadata = {};
|
||||
|
||||
try {
|
||||
metadata = JSON.parse(drive.metadata);
|
||||
|
||||
if (metadata.InitData) {
|
||||
version = metadata.InitData.Version || 'Unknown';
|
||||
gitRemote = metadata.InitData.GitRemote || 'Unknown';
|
||||
gitBranch = metadata.InitData.GitBranch || 'Unknown';
|
||||
gitCommit = metadata.InitData.GitCommit || 'Unknown';
|
||||
}
|
||||
|
||||
if (props.drive !== state.drive) {
|
||||
setState({ ...state, loading: true, firstReqSent: false, segment: null, drive: props.drive })
|
||||
if (metadata.CarParams) {
|
||||
if (metadata.CarParams.CarName !== undefined) vehicle += `${metadata.CarParams.CarName.toUpperCase()} `;
|
||||
if (metadata.CarParams.CarFingerprint !== undefined) vehicle += (metadata.CarParams.CarFingerprint.toUpperCase());
|
||||
}
|
||||
} catch (exception) { console.log(exception); }
|
||||
|
||||
// const directoryTree = dirTree(config.storagePath + device.dongle_id + "/" + dongleIdHash + "/" + driveIdentifierHash + "/" + drive.identifier);
|
||||
const directoryTree = state.segment;
|
||||
const driveUrl = 'driveurl';
|
||||
const directorySegments = {};
|
||||
|
||||
if (directoryTree) {
|
||||
for (const i in directoryTree.children) {
|
||||
// skip any non-directory entries (for example m3u8 file in the drive directory)
|
||||
if (directoryTree.children[i].type !== 'directory') continue;
|
||||
|
||||
const segment = directoryTree.children[i].name;
|
||||
|
||||
const logSegment = {};
|
||||
for (const c in directoryTree.children[i].children) {
|
||||
logSegment[directoryTree.children[i].children[c].name] = {
|
||||
url: `${driveUrl}/${segment}/${directoryTree.children[i].children[c].name}`,
|
||||
name: directoryTree.children[i].children[c].name,
|
||||
fileSize: directoryTree.children[i].children[c].size,
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
directorySegments[segment] = logSegment;
|
||||
}
|
||||
|
||||
const dongle_id = props.dongleId;
|
||||
const drive_id = props.drive;
|
||||
const dongle = deviceState.dongles[dongle_id];
|
||||
console.log("view drive", dongle)
|
||||
console.log("drives", dongle.drives)
|
||||
if (!dongle || !dongle.drives) return (<p>loading</p>)
|
||||
console.log('output is', directorySegments);
|
||||
}
|
||||
|
||||
if (state.segment === null) {
|
||||
// TODO Make this not run multiple times
|
||||
deviceController.getDriveSegments(dongle_id, dongle.drives[drive_id].identifier).then((res) => {
|
||||
console.log("my res", res.data)
|
||||
if (res.data === null) {
|
||||
setState({ ...state, loading: false, firstReqSent: true, segment: [] })
|
||||
} else {
|
||||
setState({ ...state, loading: false, firstReqSent: true, segment: res.data })
|
||||
}
|
||||
return (
|
||||
<Box sx={{ width: '100%' }}>
|
||||
<Paper sx={{ width: '100%', mb: 2, padding: '20px' }}>
|
||||
|
||||
})
|
||||
<Typography variant="body1">
|
||||
<b>Vehicle:</b>
|
||||
{' '}
|
||||
{vehicle}
|
||||
</Typography>
|
||||
<Typography variant="body1">
|
||||
<b>Version:</b>
|
||||
{' '}
|
||||
{version}
|
||||
</Typography>
|
||||
<Typography variant="body1">
|
||||
<b>gitRemote:</b>
|
||||
{' '}
|
||||
{gitRemote}
|
||||
</Typography>
|
||||
<Typography variant="body1">
|
||||
<b>gitBranch:</b>
|
||||
{' '}
|
||||
{gitBranch}
|
||||
</Typography>
|
||||
<Typography variant="body1">
|
||||
<b>gitCommit:</b>
|
||||
{' '}
|
||||
{gitCommit}
|
||||
</Typography>
|
||||
|
||||
}
|
||||
<Typography variant="body2"><b>Fingerprint: </b></Typography>
|
||||
|
||||
// test
|
||||
<TableContainer>
|
||||
<Table
|
||||
sx={{ minWidth: 750 }}
|
||||
aria-labelledby="tableTitle"
|
||||
size="small"
|
||||
>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Segment ID</TableCell>
|
||||
<TableCell>File</TableCell>
|
||||
<TableCell>File size</TableCell>
|
||||
<TableCell>Actions</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{
|
||||
directorySegments ? Object.keys(directorySegments).map((key, index) => Object.keys(directorySegments[key]).map((key1, index1) => (
|
||||
<TableRow hover>
|
||||
<TableCell>{key}</TableCell>
|
||||
<TableCell>{directorySegments[key][key1].name}</TableCell>
|
||||
<TableCell>{`${Math.round(directorySegments[key][key1].fileSize / 1024)} MiB`}</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<Tooltip title="Open in new window">
|
||||
<IconButton size="small" onClick={() => window.open(directorySegments[key][key1].url, '_blank')}>
|
||||
<OpenInNewIcon fontSize="inherit" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
|
||||
|
||||
|
||||
const drive = dongle.drives[drive_id];
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
let vehicle = "";
|
||||
let version = "";
|
||||
let gitRemote = "";
|
||||
let gitBranch = "";
|
||||
let gitCommit = "";
|
||||
let metadata = {};
|
||||
|
||||
|
||||
try {
|
||||
metadata = JSON.parse(drive.metadata);
|
||||
|
||||
if (metadata['InitData']) {
|
||||
version = metadata['InitData']['Version'] || "Unknown";
|
||||
gitRemote = metadata['InitData']['GitRemote'] || "Unknown";
|
||||
gitBranch = metadata['InitData']['GitBranch'] || "Unknown";
|
||||
gitCommit = metadata['InitData']['GitCommit'] || "Unknown";
|
||||
}
|
||||
|
||||
|
||||
if (metadata['CarParams']) {
|
||||
if (metadata['CarParams']['CarName'] !== undefined) vehicle += (metadata['CarParams']['CarName'].toUpperCase()) + " ";
|
||||
if (metadata['CarParams']['CarFingerprint'] !== undefined) vehicle += (metadata['CarParams']['CarFingerprint'].toUpperCase())
|
||||
|
||||
}
|
||||
} catch (exception) { console.log(exception) }
|
||||
|
||||
//const directoryTree = dirTree(config.storagePath + device.dongle_id + "/" + dongleIdHash + "/" + driveIdentifierHash + "/" + drive.identifier);
|
||||
const directoryTree = state.segment;
|
||||
const driveUrl = "driveurl"
|
||||
var directorySegments = {};
|
||||
|
||||
if (directoryTree) {
|
||||
for (var i in directoryTree.children) {
|
||||
// skip any non-directory entries (for example m3u8 file in the drive directory)
|
||||
if (directoryTree.children[i].type !== 'directory') continue;
|
||||
|
||||
var segment = directoryTree.children[i].name;
|
||||
|
||||
let logSegment = {}
|
||||
for (var c in directoryTree.children[i].children) {
|
||||
logSegment[directoryTree.children[i].children[c].name] = {
|
||||
url: `${driveUrl}/${segment}/${directoryTree.children[i].children[c].name}`,
|
||||
name: directoryTree.children[i].children[c].name,
|
||||
fileSize: directoryTree.children[i].children[c].size
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
directorySegments[segment] = logSegment;
|
||||
}
|
||||
|
||||
console.log("output is", directorySegments)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<Box sx={{ width: '100%' }}>
|
||||
<Paper sx={{ width: '100%', mb: 2, padding: '20px' }}>
|
||||
|
||||
<Typography variant="body1"><b>Vehicle:</b> {vehicle}</Typography>
|
||||
<Typography variant="body1"><b>Version:</b> {version}</Typography>
|
||||
<Typography variant="body1"><b>gitRemote:</b> {gitRemote}</Typography>
|
||||
<Typography variant="body1"><b>gitBranch:</b> {gitBranch}</Typography>
|
||||
<Typography variant="body1"><b>gitCommit:</b> {gitCommit}</Typography>
|
||||
|
||||
<Typography variant="body2"><b>Fingerprint: </b></Typography>
|
||||
|
||||
|
||||
|
||||
<TableContainer>
|
||||
<Table
|
||||
sx={{ minWidth: 750 }}
|
||||
aria-labelledby="tableTitle"
|
||||
size={'small'}
|
||||
>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell >Segment ID</TableCell>
|
||||
<TableCell >File</TableCell>
|
||||
<TableCell >File size</TableCell>
|
||||
<TableCell >Actions</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{
|
||||
directorySegments ? Object.keys(directorySegments).map((key, index) => {
|
||||
|
||||
|
||||
return Object.keys(directorySegments[key]).map((key1, index1) => (
|
||||
<TableRow hover>
|
||||
<TableCell >{key}</TableCell>
|
||||
<TableCell >{directorySegments[key][key1].name}</TableCell>
|
||||
<TableCell>{Math.round(directorySegments[key][key1].fileSize / 1024) + ' MiB'}</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<Tooltip title="Open in new window">
|
||||
<IconButton size="small" onClick={() => window.open(directorySegments[key][key1].url, "_blank")}>
|
||||
<OpenInNewIcon fontSize="inherit" />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
</TableCell>
|
||||
|
||||
|
||||
</TableRow>
|
||||
))
|
||||
|
||||
|
||||
}) : null
|
||||
</TableRow>
|
||||
))) : null
|
||||
}
|
||||
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
|
||||
</Paper>
|
||||
</Box >
|
||||
);
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -195,8 +196,6 @@ var dongleIdHash = crypto.createHmac('sha256', config.applicationSalt).update(de
|
|||
cabanaUrl = config.cabanaUrl + '?retropilotIdentifier=' + device.dongle_id + '|' + dongleIdHash + '|' + drive.identifier + '|' + driveIdentifierHash + '&retropilotHost=' + encodeURIComponent(config.baseUrl) + '&demo=1"';
|
||||
}
|
||||
|
||||
|
||||
|
||||
var response = `<html style="font-family: monospace">
|
||||
<head>
|
||||
<link href="https://vjs.zencdn.net/7.11.4/video-js.css" rel="stylesheet" />
|
||||
|
@ -290,7 +289,6 @@ var dongleIdHash = crypto.createHmac('sha256', config.applicationSalt).update(de
|
|||
<tr><th>segment</th><th>qcamera</th><th>qlog</th><th>fcamera</th><th>rlog</th><th>dcamera</th><th>processed</th><th>stalled</th></tr>
|
||||
`;
|
||||
|
||||
|
||||
var directorySegments = {};
|
||||
for (var i in directoryTree.children) {
|
||||
// skip any non-directory entries (for example m3u8 file in the drive directory)
|
||||
|
@ -298,7 +296,6 @@ var dongleIdHash = crypto.createHmac('sha256', config.applicationSalt).update(de
|
|||
|
||||
var segment = directoryTree.children[i].name;
|
||||
|
||||
|
||||
var qcamera = '--';
|
||||
var fcamera = '--';
|
||||
var dcamera = '--';
|
||||
|
@ -345,4 +342,4 @@ var dongleIdHash = crypto.createHmac('sha256', config.applicationSalt).update(de
|
|||
<hr/>
|
||||
<a href="/useradmin/signout">Sign Out</a></body></html>`;
|
||||
|
||||
*/
|
||||
*/
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { Link } from "react-router-dom";
|
||||
import { UserContext } from "./../../context/users";
|
||||
import { Link } from 'react-router-dom';
|
||||
import { UserContext } from '../../context/users';
|
||||
|
||||
const theme = createTheme();
|
||||
const theme = createTheme();
|
||||
|
||||
export default function SignIn() {
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [ state, dispatch ] = useContext(UserContext)
|
||||
console.log("component", state)
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [state, dispatch] = useContext(UserContext);
|
||||
console.log('component', state);
|
||||
const handleSubmit = (event) => {
|
||||
dispatch({ type: "toggle_button" })
|
||||
dispatch({ type: 'toggle_button' });
|
||||
|
||||
event.preventDefault();
|
||||
const data = new FormData(event.currentTarget);
|
||||
|
@ -20,19 +20,15 @@ export default function SignIn() {
|
|||
password: data.get('password'),
|
||||
});
|
||||
|
||||
setLoading(true)
|
||||
|
||||
|
||||
setLoading(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<p>hello</p>
|
||||
<Link to="/login" variant="body2">
|
||||
{"login?"}
|
||||
</Link>
|
||||
<p>hello</p>
|
||||
<Link to="/login" variant="body2">
|
||||
login?
|
||||
</Link>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -7,14 +7,14 @@ import Paper from '@mui/material/Paper';
|
|||
import TextField from '@mui/material/TextField';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import { UserContext } from "./../../context/users";
|
||||
import { UserContext } from '../../context/users';
|
||||
|
||||
export default function SignIn() {
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [state, dispatch] = useContext(UserContext)
|
||||
console.log("component", state)
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [state, dispatch] = useContext(UserContext);
|
||||
console.log('component', state);
|
||||
const handleSubmit = (event) => {
|
||||
dispatch({ type: "toggle_button" })
|
||||
dispatch({ type: 'toggle_button' });
|
||||
|
||||
event.preventDefault();
|
||||
const data = new FormData(event.currentTarget);
|
||||
|
@ -24,7 +24,7 @@ export default function SignIn() {
|
|||
password: data.get('password'),
|
||||
});
|
||||
|
||||
setLoading(true)
|
||||
setLoading(true);
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -41,13 +41,10 @@ export default function SignIn() {
|
|||
alignItems: 'center',
|
||||
}}
|
||||
style={{
|
||||
padding: '15px'
|
||||
padding: '15px',
|
||||
}}
|
||||
>
|
||||
|
||||
|
||||
|
||||
|
||||
<Typography component="h1" variant="h5" align="left">
|
||||
Sign in
|
||||
</Typography>
|
||||
|
@ -85,20 +82,15 @@ export default function SignIn() {
|
|||
</LoadingButton>
|
||||
|
||||
<Link href="#" variant="body2">
|
||||
{"New Here or Forgotten password?"}
|
||||
New Here or Forgotten password?
|
||||
</Link>
|
||||
</Box>
|
||||
</Paper>
|
||||
|
||||
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
</Grid>
|
||||
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,52 +2,41 @@ import Grid from '@mui/material/Grid';
|
|||
import Paper from '@mui/material/Paper';
|
||||
import { Scrollbars } from 'rc-scrollbars';
|
||||
import React, { useContext } from 'react';
|
||||
import { context as DeviceContext } from "./../../context/devices";
|
||||
import DeviceData from './../device/deviceData';
|
||||
import DeviceOverview from "./../device/overview";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
import { context as DeviceContext } from '../../context/devices';
|
||||
import DeviceData from '../device/deviceData';
|
||||
import DeviceOverview from '../device/overview';
|
||||
|
||||
export default function SignIn() {
|
||||
|
||||
|
||||
|
||||
const [deviceState] = useContext(DeviceContext);
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div className="wrapper">
|
||||
|
||||
<Grid container spacing={0} style={{ height: '100%', justify: 'space-around', minHeight: "100%", maxHeight: "100%" }} >
|
||||
<Grid item xs={12} md={4} lg={3} sm={6} xl={2} style={{ minHeight: "100%", maxHeight: "100%" }}>
|
||||
<Paper style={{ minHeight: "100%", maxHeight: "100%", margin: "0" }}>
|
||||
<Scrollbars autoHeight={true} autoHeightMin="calc(100vh - 14px)" autoHeightMax="calc(100% - 14px)">
|
||||
<Grid
|
||||
container
|
||||
spacing={0}
|
||||
style={{
|
||||
height: '100%', justify: 'space-around', minHeight: '100%', maxHeight: '100%',
|
||||
}}
|
||||
>
|
||||
<Grid item xs={12} md={4} lg={3} sm={6} xl={2} style={{ minHeight: '100%', maxHeight: '100%' }}>
|
||||
<Paper style={{ minHeight: '100%', maxHeight: '100%', margin: '0' }}>
|
||||
<Scrollbars autoHeight autoHeightMin="calc(100vh - 14px)" autoHeightMax="calc(100% - 14px)">
|
||||
<div style={{ padding: '5px' }}>
|
||||
{deviceState ? Object.keys(deviceState.dongles).map(key => <DeviceOverview device={deviceState.dongles[key]} />) : <p>no</p>}
|
||||
|
||||
{deviceState ? Object.keys(deviceState.dongles).map((key) => <DeviceOverview device={deviceState.dongles[key]} />) : <p>no</p>}
|
||||
|
||||
</div>
|
||||
|
||||
</Scrollbars>
|
||||
|
||||
|
||||
|
||||
|
||||
</Paper>
|
||||
|
||||
</Grid>
|
||||
<Grid item xs={12} md={8} lg={9} sm={6} xl={10}>
|
||||
{deviceState.dongles['53331425'] ? <DeviceData device={deviceState.dongles['53331425']} /> : <p>no</p>}
|
||||
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,19 +1,12 @@
|
|||
import Snackbar from '@mui/material/Snackbar';
|
||||
import React, { useContext } from 'react';
|
||||
import { context as DeviceContext } from "./../../context/toast";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
import { context as DeviceContext } from '../../context/toast';
|
||||
|
||||
export default function Toast(props) {
|
||||
const [state, dispatch] = useContext(DeviceContext)
|
||||
|
||||
|
||||
const [state, dispatch] = useContext(DeviceContext);
|
||||
|
||||
const handleClose = () => {
|
||||
dispatch({ type: 'CLOSE_TOAST' })
|
||||
dispatch({ type: 'CLOSE_TOAST' });
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
@ -1,131 +1,125 @@
|
|||
import React, { createContext, useEffect, useReducer } from "react";
|
||||
import * as deviceController from "./../../controllers/devices";
|
||||
import React, { createContext, useEffect, useReducer } from 'react';
|
||||
import * as deviceController from '../../controllers/devices';
|
||||
|
||||
function process(state, action) {
|
||||
if (action.type !== "ADD_DATA") { return state }
|
||||
if (action.type !== 'ADD_DATA') { return state; }
|
||||
|
||||
switch (action.data.command) {
|
||||
|
||||
case "dongle_status":
|
||||
return {
|
||||
...state,
|
||||
dongles: {
|
||||
...state.dongles,
|
||||
[action.data.data.dongle_id]: {
|
||||
...state.dongles[action.data.data.dongle_id],
|
||||
online: action.data.data.online,
|
||||
last_seen: action.data.data.time,
|
||||
dongle_id: action.data.data.dongle_id
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
switch (action.data.command) {
|
||||
case 'dongle_status':
|
||||
return {
|
||||
...state,
|
||||
dongles: {
|
||||
...state.dongles,
|
||||
[action.data.data.dongle_id]: {
|
||||
...state.dongles[action.data.data.dongle_id],
|
||||
online: action.data.data.online,
|
||||
last_seen: action.data.data.time,
|
||||
dongle_id: action.data.data.dongle_id,
|
||||
},
|
||||
},
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const Reducer = (state, action) => {
|
||||
console.log("input", state, action)
|
||||
switch (action.type) {
|
||||
case 'ADD_DATA':
|
||||
return process(state, action);
|
||||
case "fetch_all_dongles":
|
||||
console.log("fetch", action)
|
||||
return {
|
||||
...state,
|
||||
dongles: action.data
|
||||
}
|
||||
console.log('input', state, action);
|
||||
switch (action.type) {
|
||||
case 'ADD_DATA':
|
||||
return process(state, action);
|
||||
case 'fetch_all_dongles':
|
||||
console.log('fetch', action);
|
||||
return {
|
||||
...state,
|
||||
dongles: action.data,
|
||||
};
|
||||
|
||||
case "update_dongle_drive":
|
||||
return {
|
||||
...state,
|
||||
dongles: {
|
||||
...state.dongles,
|
||||
[action.dongle_id]: {
|
||||
...state.dongles[action.dongle_id],
|
||||
drives: action.drives
|
||||
}
|
||||
}
|
||||
}
|
||||
case 'update_dongle_drive':
|
||||
return {
|
||||
...state,
|
||||
dongles: {
|
||||
...state.dongles,
|
||||
[action.dongle_id]: {
|
||||
...state.dongles[action.dongle_id],
|
||||
drives: action.drives,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
case "update_dongle_bootlogs":
|
||||
return {
|
||||
...state,
|
||||
dongles: {
|
||||
...state.dongles,
|
||||
[action.dongle_id]: {
|
||||
...state.dongles[action.dongle_id],
|
||||
boot: action.bootlogs
|
||||
}
|
||||
}
|
||||
}
|
||||
case 'update_dongle_bootlogs':
|
||||
return {
|
||||
...state,
|
||||
dongles: {
|
||||
...state.dongles,
|
||||
[action.dongle_id]: {
|
||||
...state.dongles[action.dongle_id],
|
||||
boot: action.bootlogs,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
case "update_dongle_crashlogs":
|
||||
return {
|
||||
...state,
|
||||
dongles: {
|
||||
...state.dongles,
|
||||
[action.dongle_id]: {
|
||||
...state.dongles[action.dongle_id],
|
||||
crash: action.crashlogs
|
||||
}
|
||||
}
|
||||
}
|
||||
case 'update_dongle_crashlogs':
|
||||
return {
|
||||
...state,
|
||||
dongles: {
|
||||
...state.dongles,
|
||||
[action.dongle_id]: {
|
||||
...state.dongles[action.dongle_id],
|
||||
crash: action.crashlogs,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
case "user_authentication":
|
||||
return {
|
||||
...state,
|
||||
user: action.user
|
||||
}
|
||||
case 'user_authentication':
|
||||
return {
|
||||
...state,
|
||||
user: action.user,
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
const initialState = {
|
||||
dongles: {}
|
||||
dongles: {},
|
||||
};
|
||||
|
||||
const Store = ({ children }) => {
|
||||
console.log("STORE HAS BEEN RERENDERED")
|
||||
const [state, dispatch] = useReducer(Reducer, initialState);
|
||||
function Store({ children }) {
|
||||
console.log('STORE HAS BEEN RERENDERED');
|
||||
const [state, dispatch] = useReducer(Reducer, initialState);
|
||||
|
||||
useEffect(() => {
|
||||
const ws = new WebSocket('ws://localhost:81');
|
||||
useEffect(() => {
|
||||
const ws = new WebSocket('ws://localhost:81');
|
||||
|
||||
ws.onmessage = ({ data }) => {
|
||||
data = JSON.parse(data)
|
||||
console.log("Message")
|
||||
if (data.id) {
|
||||
dispatch({ type: "ADD_DATA", id: data.id, data: data })
|
||||
}
|
||||
};
|
||||
ws.onmessage = ({ data }) => {
|
||||
data = JSON.parse(data);
|
||||
console.log('Message');
|
||||
if (data.id) {
|
||||
dispatch({ type: 'ADD_DATA', id: data.id, data });
|
||||
}
|
||||
};
|
||||
|
||||
deviceController.getAllDevices().then((devices) => {
|
||||
console.log("store", devices)
|
||||
deviceController.getAllDevices().then((devices) => {
|
||||
console.log('store', devices);
|
||||
|
||||
dispatch({ type: "fetch_all_dongles", data: devices })
|
||||
})
|
||||
dispatch({ type: 'fetch_all_dongles', data: devices });
|
||||
});
|
||||
|
||||
return () => {
|
||||
try {
|
||||
ws.close();
|
||||
} catch (e) { }
|
||||
};
|
||||
}, []);
|
||||
return () => {
|
||||
try {
|
||||
ws.close();
|
||||
} catch (e) { }
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
return (
|
||||
<context.Provider value={[state, dispatch]}>
|
||||
{children}
|
||||
</context.Provider>
|
||||
)
|
||||
};
|
||||
return (
|
||||
<context.Provider value={[state, dispatch]}>
|
||||
{children}
|
||||
</context.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export const context = createContext(initialState);
|
||||
export default Store;
|
||||
export default Store;
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
import React, {createContext, useReducer} from "react";
|
||||
import Reducer from './reducer'
|
||||
|
||||
import React, { createContext, useReducer } from 'react';
|
||||
import Reducer from './reducer';
|
||||
|
||||
const initialState = {
|
||||
open: false,
|
||||
message: null
|
||||
open: false,
|
||||
message: null,
|
||||
};
|
||||
|
||||
const Store = ({children}) => {
|
||||
const [state, dispatch] = useReducer(Reducer, initialState);
|
||||
return (
|
||||
<context.Provider value={[state, dispatch]}>
|
||||
{children}
|
||||
</context.Provider>
|
||||
)
|
||||
};
|
||||
function Store({ children }) {
|
||||
const [state, dispatch] = useReducer(Reducer, initialState);
|
||||
return (
|
||||
<context.Provider value={[state, dispatch]}>
|
||||
{children}
|
||||
</context.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export const context = createContext(initialState);
|
||||
export default Store;
|
||||
export default Store;
|
||||
|
|
|
@ -4,17 +4,17 @@ const Reducer = (state, action) => {
|
|||
return {
|
||||
...state,
|
||||
open: action.open,
|
||||
msg: action.message
|
||||
msg: action.message,
|
||||
};
|
||||
case 'CLOSE_TOAST':
|
||||
return {
|
||||
...state,
|
||||
open: false
|
||||
}
|
||||
open: false,
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default Reducer;
|
||||
export default Reducer;
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import React from "react"
|
||||
import { reducer, initialState } from "./reducer"
|
||||
import React from 'react';
|
||||
import { reducer, initialState } from './reducer';
|
||||
|
||||
export const UserContext = React.createContext({
|
||||
state: initialState,
|
||||
dispatch: () => null
|
||||
})
|
||||
dispatch: () => null,
|
||||
});
|
||||
|
||||
export const UserProvider = ({ children }) => {
|
||||
const [state, dispatch] = React.useReducer(reducer, initialState)
|
||||
export function UserProvider({ children }) {
|
||||
const [state, dispatch] = React.useReducer(reducer, initialState);
|
||||
|
||||
return (
|
||||
<UserContext.Provider value={[ state, dispatch ]}>
|
||||
{ children }
|
||||
<UserContext.Provider value={[state, dispatch]}>
|
||||
{ children }
|
||||
</UserContext.Provider>
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
export const reducer = (state, action) => {
|
||||
switch (action.type) {
|
||||
case "sign_out":
|
||||
case 'sign_out':
|
||||
|
||||
return {
|
||||
...state,
|
||||
active: !state.active
|
||||
}
|
||||
active: !state.active,
|
||||
};
|
||||
|
||||
default:
|
||||
return state
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const initialState = {
|
||||
signedIn: false,
|
||||
|
@ -19,4 +19,4 @@ export const initialState = {
|
|||
username: null,
|
||||
JWT: null,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
import axios from "axios";
|
||||
|
||||
import axios from 'axios';
|
||||
|
||||
export async function getSession() {
|
||||
|
||||
const req = await axios.get(`http://localhost/retropilot/0/useradmin/session`, {withCredentials: true});
|
||||
return req.data
|
||||
|
||||
}
|
||||
const req = await axios.get('http://localhost/retropilot/0/useradmin/session', { withCredentials: true });
|
||||
return req.data;
|
||||
}
|
||||
|
|
|
@ -1,50 +1,44 @@
|
|||
import axios from "axios";
|
||||
import axios from 'axios';
|
||||
|
||||
export async function getDrives(dongleId) {
|
||||
const req = await axios.get(`http://localhost/retropilot/0/device/${dongleId}/drives/false`, { withCredentials: true });
|
||||
return req.data
|
||||
const req = await axios.get(`http://localhost/retropilot/0/device/${dongleId}/drives/false`, { withCredentials: true });
|
||||
return req.data;
|
||||
}
|
||||
|
||||
export async function getBootlogs(dongleId) {
|
||||
const req = await axios.get(`http://localhost/retropilot/0/device/${dongleId}/bootlogs`, { withCredentials: true });
|
||||
return req.data
|
||||
const req = await axios.get(`http://localhost/retropilot/0/device/${dongleId}/bootlogs`, { withCredentials: true });
|
||||
return req.data;
|
||||
}
|
||||
|
||||
export async function getCrashlogs(dongleId) {
|
||||
const req = await axios.get(`http://localhost/retropilot/0/device/${dongleId}/crashlogs`, { withCredentials: true });
|
||||
return req.data
|
||||
const req = await axios.get(`http://localhost/retropilot/0/device/${dongleId}/crashlogs`, { withCredentials: true });
|
||||
return req.data;
|
||||
}
|
||||
|
||||
export async function getDriveSegments(dongleId, drive_identifier) {
|
||||
const req = await axios.get(`http://localhost/retropilot/0/device/${dongleId}/drives/${drive_identifier}/segment`, { withCredentials: true });
|
||||
return req.data
|
||||
const req = await axios.get(`http://localhost/retropilot/0/device/${dongleId}/drives/${drive_identifier}/segment`, { withCredentials: true });
|
||||
return req.data;
|
||||
}
|
||||
|
||||
export async function getAllDevices() {
|
||||
const req = await axios.get(`http://localhost/retropilot/0/devices`, { withCredentials: true });
|
||||
const responseData = req.data
|
||||
const req = await axios.get('http://localhost/retropilot/0/devices', { withCredentials: true });
|
||||
const responseData = req.data;
|
||||
|
||||
let dongles = {}
|
||||
let dongles = {};
|
||||
|
||||
if (responseData.success === true) {
|
||||
if (responseData.success === true) {
|
||||
responseData.data.map((object) => dongles = {
|
||||
...dongles,
|
||||
[object.dongle_id]: {
|
||||
...object,
|
||||
online: false,
|
||||
// Show when last connected to api instead Athena by default
|
||||
last_seen: object.last_ping,
|
||||
},
|
||||
});
|
||||
|
||||
responseData.data.map((object) => {
|
||||
return dongles;
|
||||
}
|
||||
|
||||
return dongles = {
|
||||
...dongles,
|
||||
[object.dongle_id]: {
|
||||
...object,
|
||||
online: false,
|
||||
// Show when last connected to api instead Athena by default
|
||||
last_seen: object.last_ping,
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
return dongles;
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,24 +1,20 @@
|
|||
|
||||
|
||||
|
||||
export function formatDate(timestampMs) {
|
||||
return new Date(timestampMs).toISOString().replace(/T/, ' ').replace(/\..+/, '');
|
||||
}
|
||||
|
||||
|
||||
export function formatDuration(durationSeconds) {
|
||||
durationSeconds = Math.round(durationSeconds);
|
||||
const secs = durationSeconds % 60;
|
||||
let mins = Math.floor(durationSeconds / 60);
|
||||
let hours = Math.floor(mins / 60);
|
||||
mins = mins % 60;
|
||||
mins %= 60;
|
||||
const days = Math.floor(hours / 24);
|
||||
hours = hours % 24;
|
||||
hours %= 24;
|
||||
|
||||
let response = '';
|
||||
if (days > 0) response += days + 'd ';
|
||||
if (hours > 0 || days > 0) response += hours + 'h ';
|
||||
if (hours > 0 || days > 0 || mins > 0) response += mins + 'm ';
|
||||
response += secs + 's';
|
||||
if (days > 0) response += `${days}d `;
|
||||
if (hours > 0 || days > 0) response += `${hours}h `;
|
||||
if (hours > 0 || days > 0 || mins > 0) response += `${mins}m `;
|
||||
response += `${secs}s`;
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ ReactDOM.render(
|
|||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
document.getElementById('root'),
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
const reportWebVitals = onPerfEntry => {
|
||||
const reportWebVitals = (onPerfEntry) => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
import('web-vitals').then(({
|
||||
getCLS, getFID, getFCP, getLCP, getTTFB,
|
||||
}) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
|
|
21
src/yeet.js
21
src/yeet.js
|
@ -1,4 +1,4 @@
|
|||
import React, {useState, useContext} from 'react';
|
||||
import React, { useState, useContext } from 'react';
|
||||
import Avatar from '@mui/material/Avatar';
|
||||
import LoadingButton from '@mui/lab/LoadingButton';
|
||||
import CssBaseline from '@mui/material/CssBaseline';
|
||||
|
@ -14,20 +14,21 @@ import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
|
|||
import Typography from '@mui/material/Typography';
|
||||
import Container from '@mui/material/Container';
|
||||
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
||||
import { UserContext } from "./context/users"
|
||||
const theme = createTheme();
|
||||
import { UserContext } from './context/users';
|
||||
|
||||
const theme = createTheme();
|
||||
|
||||
export default function SignIn() {
|
||||
const [ state, dispatch ] = useContext(UserContext)
|
||||
|
||||
const [state, dispatch] = useContext(UserContext);
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
{console.log("testing", state)}
|
||||
<p> {JSON.stringify(state)}</p>
|
||||
|
||||
{console.log('testing', state)}
|
||||
<p>
|
||||
{' '}
|
||||
{JSON.stringify(state)}
|
||||
</p>
|
||||
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue