add eslint airbnb rules

main
Cameron Clough 2022-01-09 16:52:29 +00:00
parent 0956687fbb
commit d70e46583a
No known key found for this signature in database
GPG Key ID: BFB3B74B026ED43F
28 changed files with 897 additions and 894 deletions

View File

@ -1,9 +1,39 @@
{ {
"env": {
"browser": true,
"es6": true
},
"extends": [ "extends": [
"react-app", "react-app",
"react-app/jest" "react-app/jest",
"airbnb",
"airbnb/hooks"
], ],
"rules": { "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
}]
} }
} }

288
package-lock.json generated
View File

@ -1,11 +1,11 @@
{ {
"name": "app", "name": "retropilot-client",
"version": "0.1.0", "version": "0.1.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "app", "name": "retropilot-client",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@emotion/react": "^11.7.1", "@emotion/react": "^11.7.1",
@ -30,6 +30,9 @@
"react-scripts": "4.0.3", "react-scripts": "4.0.3",
"styled-components": "^5.3.3", "styled-components": "^5.3.3",
"web-vitals": "^1.1.2" "web-vitals": "^1.1.2"
},
"devDependencies": {
"eslint-config-airbnb": "^19.0.4"
} }
}, },
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
@ -5256,9 +5259,9 @@
"integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==" "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA=="
}, },
"node_modules/axe-core": { "node_modules/axe-core": {
"version": "4.3.3", "version": "4.3.5",
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.3.tgz", "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz",
"integrity": "sha512-/lqqLAmuIPi79WYfRpy2i8z+x+vxU3zX2uAm0gs1q52qTuKwolOj1P8XbufpXcsydrpKx2yGn2wzAnxCMV86QA==", "integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA==",
"engines": { "engines": {
"node": ">=4" "node": ">=4"
} }
@ -8374,6 +8377,55 @@
"url": "https://opencollective.com/eslint" "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": { "node_modules/eslint-config-react-app": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-6.0.0.tgz", "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": { "node_modules/eslint-module-utils": {
"version": "2.7.1", "version": "2.7.2",
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.2.tgz",
"integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==", "integrity": "sha512-zquepFnWCY2ISMFwD/DqzaM++H+7PDzOpUvotJWm/y1BAFt5R4oeULgdrTejKqLkz7MA/tgstsUMNYc7wNdTrg==",
"dependencies": { "dependencies": {
"debug": "^3.2.7", "debug": "^3.2.7",
"find-up": "^2.1.0", "find-up": "^2.1.0"
"pkg-dir": "^2.0.0"
}, },
"engines": { "engines": {
"node": ">=4" "node": ">=4"
@ -8517,17 +8568,6 @@
"node": ">=4" "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": { "node_modules/eslint-plugin-flowtype": {
"version": "5.10.0", "version": "5.10.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.10.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.10.0.tgz",
@ -8544,23 +8584,23 @@
} }
}, },
"node_modules/eslint-plugin-import": { "node_modules/eslint-plugin-import": {
"version": "2.25.2", "version": "2.25.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.2.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz",
"integrity": "sha512-qCwQr9TYfoBHOFcVGKY9C9unq05uOxxdklmBXLVvcwo68y5Hta6/GzCZEMx2zQiu0woKNEER0LE7ZgaOfBU14g==", "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==",
"dependencies": { "dependencies": {
"array-includes": "^3.1.4", "array-includes": "^3.1.4",
"array.prototype.flat": "^1.2.5", "array.prototype.flat": "^1.2.5",
"debug": "^2.6.9", "debug": "^2.6.9",
"doctrine": "^2.1.0", "doctrine": "^2.1.0",
"eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-node": "^0.3.6",
"eslint-module-utils": "^2.7.0", "eslint-module-utils": "^2.7.2",
"has": "^1.0.3", "has": "^1.0.3",
"is-core-module": "^2.7.0", "is-core-module": "^2.8.0",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
"minimatch": "^3.0.4", "minimatch": "^3.0.4",
"object.values": "^1.1.5", "object.values": "^1.1.5",
"resolve": "^1.20.0", "resolve": "^1.20.0",
"tsconfig-paths": "^3.11.0" "tsconfig-paths": "^3.12.0"
}, },
"engines": { "engines": {
"node": ">=4" "node": ">=4"
@ -8626,27 +8666,28 @@
} }
}, },
"node_modules/eslint-plugin-jsx-a11y": { "node_modules/eslint-plugin-jsx-a11y": {
"version": "6.4.1", "version": "6.5.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz",
"integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==", "integrity": "sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.11.2", "@babel/runtime": "^7.16.3",
"aria-query": "^4.2.2", "aria-query": "^4.2.2",
"array-includes": "^3.1.1", "array-includes": "^3.1.4",
"ast-types-flow": "^0.0.7", "ast-types-flow": "^0.0.7",
"axe-core": "^4.0.2", "axe-core": "^4.3.5",
"axobject-query": "^2.2.0", "axobject-query": "^2.2.0",
"damerau-levenshtein": "^1.0.6", "damerau-levenshtein": "^1.0.7",
"emoji-regex": "^9.0.0", "emoji-regex": "^9.2.2",
"has": "^1.0.3", "has": "^1.0.3",
"jsx-ast-utils": "^3.1.0", "jsx-ast-utils": "^3.2.1",
"language-tags": "^1.0.5" "language-tags": "^1.0.5",
"minimatch": "^3.0.4"
}, },
"engines": { "engines": {
"node": ">=4.0" "node": ">=4.0"
}, },
"peerDependencies": { "peerDependencies": {
"eslint": "^3 || ^4 || ^5 || ^6 || ^7" "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
} }
}, },
"node_modules/eslint-plugin-jsx-a11y/node_modules/emoji-regex": { "node_modules/eslint-plugin-jsx-a11y/node_modules/emoji-regex": {
@ -8655,41 +8696,41 @@
"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
}, },
"node_modules/eslint-plugin-react": { "node_modules/eslint-plugin-react": {
"version": "7.26.1", "version": "7.28.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.26.1.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz",
"integrity": "sha512-Lug0+NOFXeOE+ORZ5pbsh6mSKjBKXDXItUD2sQoT+5Yl0eoT82DqnXeTMfUare4QVCn9QwXbfzO/dBLjLXwVjQ==", "integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==",
"dependencies": { "dependencies": {
"array-includes": "^3.1.3", "array-includes": "^3.1.4",
"array.prototype.flatmap": "^1.2.4", "array.prototype.flatmap": "^1.2.5",
"doctrine": "^2.1.0", "doctrine": "^2.1.0",
"estraverse": "^5.2.0", "estraverse": "^5.3.0",
"jsx-ast-utils": "^2.4.1 || ^3.0.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0",
"minimatch": "^3.0.4", "minimatch": "^3.0.4",
"object.entries": "^1.1.4", "object.entries": "^1.1.5",
"object.fromentries": "^2.0.4", "object.fromentries": "^2.0.5",
"object.hasown": "^1.0.0", "object.hasown": "^1.1.0",
"object.values": "^1.1.4", "object.values": "^1.1.5",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"resolve": "^2.0.0-next.3", "resolve": "^2.0.0-next.3",
"semver": "^6.3.0", "semver": "^6.3.0",
"string.prototype.matchall": "^4.0.5" "string.prototype.matchall": "^4.0.6"
}, },
"engines": { "engines": {
"node": ">=4" "node": ">=4"
}, },
"peerDependencies": { "peerDependencies": {
"eslint": "^3 || ^4 || ^5 || ^6 || ^7" "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
} }
}, },
"node_modules/eslint-plugin-react-hooks": { "node_modules/eslint-plugin-react-hooks": {
"version": "4.2.0", "version": "4.3.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz",
"integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==", "integrity": "sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==",
"engines": { "engines": {
"node": ">=10" "node": ">=10"
}, },
"peerDependencies": { "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": { "node_modules/eslint-plugin-react/node_modules/doctrine": {
@ -8704,9 +8745,9 @@
} }
}, },
"node_modules/eslint-plugin-react/node_modules/estraverse": { "node_modules/eslint-plugin-react/node_modules/estraverse": {
"version": "5.2.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
"integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
"engines": { "engines": {
"node": ">=4.0" "node": ">=4.0"
} }
@ -19939,9 +19980,9 @@
} }
}, },
"node_modules/tsconfig-paths": { "node_modules/tsconfig-paths": {
"version": "3.11.0", "version": "3.12.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz",
"integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==",
"dependencies": { "dependencies": {
"@types/json5": "^0.0.29", "@types/json5": "^0.0.29",
"json5": "^1.0.1", "json5": "^1.0.1",
@ -25990,9 +26031,9 @@
} }
}, },
"axe-core": { "axe-core": {
"version": "4.3.3", "version": "4.3.5",
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.3.tgz", "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz",
"integrity": "sha512-/lqqLAmuIPi79WYfRpy2i8z+x+vxU3zX2uAm0gs1q52qTuKwolOj1P8XbufpXcsydrpKx2yGn2wzAnxCMV86QA==" "integrity": "sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA=="
}, },
"axios": { "axios": {
"version": "0.24.0", "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": { "eslint-config-react-app": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-6.0.0.tgz", "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-6.0.0.tgz",
@ -28672,13 +28744,12 @@
} }
}, },
"eslint-module-utils": { "eslint-module-utils": {
"version": "2.7.1", "version": "2.7.2",
"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.2.tgz",
"integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==", "integrity": "sha512-zquepFnWCY2ISMFwD/DqzaM++H+7PDzOpUvotJWm/y1BAFt5R4oeULgdrTejKqLkz7MA/tgstsUMNYc7wNdTrg==",
"requires": { "requires": {
"debug": "^3.2.7", "debug": "^3.2.7",
"find-up": "^2.1.0", "find-up": "^2.1.0"
"pkg-dir": "^2.0.0"
}, },
"dependencies": { "dependencies": {
"debug": { "debug": {
@ -28731,14 +28802,6 @@
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" "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": { "eslint-plugin-import": {
"version": "2.25.2", "version": "2.25.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.2.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz",
"integrity": "sha512-qCwQr9TYfoBHOFcVGKY9C9unq05uOxxdklmBXLVvcwo68y5Hta6/GzCZEMx2zQiu0woKNEER0LE7ZgaOfBU14g==", "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==",
"requires": { "requires": {
"array-includes": "^3.1.4", "array-includes": "^3.1.4",
"array.prototype.flat": "^1.2.5", "array.prototype.flat": "^1.2.5",
"debug": "^2.6.9", "debug": "^2.6.9",
"doctrine": "^2.1.0", "doctrine": "^2.1.0",
"eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-node": "^0.3.6",
"eslint-module-utils": "^2.7.0", "eslint-module-utils": "^2.7.2",
"has": "^1.0.3", "has": "^1.0.3",
"is-core-module": "^2.7.0", "is-core-module": "^2.8.0",
"is-glob": "^4.0.3", "is-glob": "^4.0.3",
"minimatch": "^3.0.4", "minimatch": "^3.0.4",
"object.values": "^1.1.5", "object.values": "^1.1.5",
"resolve": "^1.20.0", "resolve": "^1.20.0",
"tsconfig-paths": "^3.11.0" "tsconfig-paths": "^3.12.0"
}, },
"dependencies": { "dependencies": {
"debug": { "debug": {
@ -28812,21 +28875,22 @@
} }
}, },
"eslint-plugin-jsx-a11y": { "eslint-plugin-jsx-a11y": {
"version": "6.4.1", "version": "6.5.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz",
"integrity": "sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg==", "integrity": "sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g==",
"requires": { "requires": {
"@babel/runtime": "^7.11.2", "@babel/runtime": "^7.16.3",
"aria-query": "^4.2.2", "aria-query": "^4.2.2",
"array-includes": "^3.1.1", "array-includes": "^3.1.4",
"ast-types-flow": "^0.0.7", "ast-types-flow": "^0.0.7",
"axe-core": "^4.0.2", "axe-core": "^4.3.5",
"axobject-query": "^2.2.0", "axobject-query": "^2.2.0",
"damerau-levenshtein": "^1.0.6", "damerau-levenshtein": "^1.0.7",
"emoji-regex": "^9.0.0", "emoji-regex": "^9.2.2",
"has": "^1.0.3", "has": "^1.0.3",
"jsx-ast-utils": "^3.1.0", "jsx-ast-utils": "^3.2.1",
"language-tags": "^1.0.5" "language-tags": "^1.0.5",
"minimatch": "^3.0.4"
}, },
"dependencies": { "dependencies": {
"emoji-regex": { "emoji-regex": {
@ -28837,24 +28901,24 @@
} }
}, },
"eslint-plugin-react": { "eslint-plugin-react": {
"version": "7.26.1", "version": "7.28.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.26.1.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz",
"integrity": "sha512-Lug0+NOFXeOE+ORZ5pbsh6mSKjBKXDXItUD2sQoT+5Yl0eoT82DqnXeTMfUare4QVCn9QwXbfzO/dBLjLXwVjQ==", "integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==",
"requires": { "requires": {
"array-includes": "^3.1.3", "array-includes": "^3.1.4",
"array.prototype.flatmap": "^1.2.4", "array.prototype.flatmap": "^1.2.5",
"doctrine": "^2.1.0", "doctrine": "^2.1.0",
"estraverse": "^5.2.0", "estraverse": "^5.3.0",
"jsx-ast-utils": "^2.4.1 || ^3.0.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0",
"minimatch": "^3.0.4", "minimatch": "^3.0.4",
"object.entries": "^1.1.4", "object.entries": "^1.1.5",
"object.fromentries": "^2.0.4", "object.fromentries": "^2.0.5",
"object.hasown": "^1.0.0", "object.hasown": "^1.1.0",
"object.values": "^1.1.4", "object.values": "^1.1.5",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"resolve": "^2.0.0-next.3", "resolve": "^2.0.0-next.3",
"semver": "^6.3.0", "semver": "^6.3.0",
"string.prototype.matchall": "^4.0.5" "string.prototype.matchall": "^4.0.6"
}, },
"dependencies": { "dependencies": {
"doctrine": { "doctrine": {
@ -28866,9 +28930,9 @@
} }
}, },
"estraverse": { "estraverse": {
"version": "5.2.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
"integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="
}, },
"resolve": { "resolve": {
"version": "2.0.0-next.3", "version": "2.0.0-next.3",
@ -28887,9 +28951,9 @@
} }
}, },
"eslint-plugin-react-hooks": { "eslint-plugin-react-hooks": {
"version": "4.2.0", "version": "4.3.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz",
"integrity": "sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ==", "integrity": "sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==",
"requires": {} "requires": {}
}, },
"eslint-plugin-testing-library": { "eslint-plugin-testing-library": {
@ -37426,9 +37490,9 @@
"integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==" "integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw=="
}, },
"tsconfig-paths": { "tsconfig-paths": {
"version": "3.11.0", "version": "3.12.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz",
"integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==",
"requires": { "requires": {
"@types/json5": "^0.0.29", "@types/json5": "^0.0.29",
"json5": "^1.0.1", "json5": "^1.0.1",

View File

@ -6,7 +6,9 @@
"start": "react-scripts start", "start": "react-scripts start",
"build": "react-scripts build", "build": "react-scripts build",
"test": "react-scripts test", "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": { "dependencies": {
"@emotion/react": "^11.7.1", "@emotion/react": "^11.7.1",
@ -32,6 +34,9 @@
"styled-components": "^5.3.3", "styled-components": "^5.3.3",
"web-vitals": "^1.1.2" "web-vitals": "^1.1.2"
}, },
"devDependencies": {
"eslint-config-airbnb": "^19.0.4"
},
"browserslist": { "browserslist": {
"production": [ "production": [
">0.2%", ">0.2%",

View File

@ -1,38 +1,25 @@
import CssBaseline from '@mui/material/CssBaseline'; import CssBaseline from '@mui/material/CssBaseline';
import { createTheme, ThemeProvider } from '@mui/material/styles'; import { createTheme, ThemeProvider } from '@mui/material/styles';
import React, { useState } from 'react'; import React, { useState } from 'react';
import Login from "./components/views/login"; import Login from './components/views/login';
import UserAdmin from "./components/views/useradmin"; import UserAdmin from './components/views/useradmin';
import GlobalSnack from './components/widgets/globalSnack'; import GlobalSnack from './components/widgets/globalSnack';
import DeviceStore from "./context/devices"; import DeviceStore from './context/devices';
import ToastStore from "./context/toast"; import ToastStore from './context/toast';
import { UserProvider } from "./context/users"; import { UserProvider } from './context/users';
import * as authenticationController from "./controllers/authentication"; import * as authenticationController from './controllers/authentication';
// Connection opened // Connection opened
function App() { function App() {
const [session, setSession] = useState(false);
const [session, setSession] = useState(false)
authenticationController.getSession().then((res) => { authenticationController.getSession().then((res) => {
setSession(res.data.authenticated) setSession(res.data.authenticated);
});
})
const theme = React.useMemo( const theme = React.useMemo(
() => () => createTheme({
createTheme({
palette: { palette: {
mode: window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light', mode: window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light',
}, },

View File

@ -2,5 +2,5 @@ import { render, screen } from '@testing-library/react';
import App from './App'; import App from './App';
test('renders learn react link', () => { test('renders learn react link', () => {
render(<p></p>); render(<p />);
}); });

View File

@ -6,123 +6,119 @@ import DrivesTable from './tabPane';
function DeviceLastSeenMap() { function DeviceLastSeenMap() {
return ( return (
<div style={{ height: "500px", width: 'calc(100%)' }}> <div style={{ height: '500px', width: 'calc(100%)' }}>
<GoogleMapReact <GoogleMapReact
height="100px" height="100px"
bootstrapURLKeys={{ key: process.env.REACT_APP_GMAPS_API_KEY }} bootstrapURLKeys={{ key: process.env.REACT_APP_GMAPS_API_KEY }}
defaultCenter={{ defaultCenter={{
lat: 51.501134, lat: 51.501134,
lng: -0.142318 lng: -0.142318,
}} }}
defaultZoom={17} defaultZoom={17}
options={{ options={{
styles: [ styles: [
{ elementType: "geometry", stylers: [{ color: "#242f3e" }] }, { elementType: 'geometry', stylers: [{ color: '#242f3e' }] },
{ elementType: "labels.text.stroke", stylers: [{ color: "#242f3e" }] }, { elementType: 'labels.text.stroke', stylers: [{ color: '#242f3e' }] },
{ elementType: "labels.text.fill", stylers: [{ color: "#746855" }] }, { elementType: 'labels.text.fill', stylers: [{ color: '#746855' }] },
{ {
featureType: "administrative.locality", featureType: 'administrative.locality',
elementType: "labels.text.fill", elementType: 'labels.text.fill',
stylers: [{ color: "#d59563" }], stylers: [{ color: '#d59563' }],
}, },
{ {
featureType: "poi", featureType: 'poi',
elementType: "labels.text.fill", elementType: 'labels.text.fill',
stylers: [{ color: "#d59563" }], stylers: [{ color: '#d59563' }],
}, },
{ {
featureType: "poi.park", featureType: 'poi.park',
elementType: "geometry", elementType: 'geometry',
stylers: [{ color: "#263c3f" }], stylers: [{ color: '#263c3f' }],
}, },
{ {
featureType: "poi.park", featureType: 'poi.park',
elementType: "labels.text.fill", elementType: 'labels.text.fill',
stylers: [{ color: "#6b9a76" }], stylers: [{ color: '#6b9a76' }],
}, },
{ {
featureType: "road", featureType: 'road',
elementType: "geometry", elementType: 'geometry',
stylers: [{ color: "#38414e" }], stylers: [{ color: '#38414e' }],
}, },
{ {
featureType: "road", featureType: 'road',
elementType: "geometry.stroke", elementType: 'geometry.stroke',
stylers: [{ color: "#212a37" }], stylers: [{ color: '#212a37' }],
}, },
{ {
featureType: "road", featureType: 'road',
elementType: "labels.text.fill", elementType: 'labels.text.fill',
stylers: [{ color: "#9ca5b3" }], stylers: [{ color: '#9ca5b3' }],
}, },
{ {
featureType: "road.highway", featureType: 'road.highway',
elementType: "geometry", elementType: 'geometry',
stylers: [{ color: "#746855" }], stylers: [{ color: '#746855' }],
}, },
{ {
featureType: "road.highway", featureType: 'road.highway',
elementType: "geometry.stroke", elementType: 'geometry.stroke',
stylers: [{ color: "#1f2835" }], stylers: [{ color: '#1f2835' }],
}, },
{ {
featureType: "road.highway", featureType: 'road.highway',
elementType: "labels.text.fill", elementType: 'labels.text.fill',
stylers: [{ color: "#f3d19c" }], stylers: [{ color: '#f3d19c' }],
}, },
{ {
featureType: "transit", featureType: 'transit',
elementType: "geometry", elementType: 'geometry',
stylers: [{ color: "#2f3948" }], stylers: [{ color: '#2f3948' }],
}, },
{ {
featureType: "transit.station", featureType: 'transit.station',
elementType: "labels.text.fill", elementType: 'labels.text.fill',
stylers: [{ color: "#d59563" }], stylers: [{ color: '#d59563' }],
}, },
{ {
featureType: "water", featureType: 'water',
elementType: "geometry", elementType: 'geometry',
stylers: [{ color: "#17263c" }], stylers: [{ color: '#17263c' }],
}, },
{ {
featureType: "water", featureType: 'water',
elementType: "labels.text.fill", elementType: 'labels.text.fill',
stylers: [{ color: "#515c6d" }], stylers: [{ color: '#515c6d' }],
}, },
{ {
featureType: "water", featureType: 'water',
elementType: "labels.text.stroke", elementType: 'labels.text.stroke',
stylers: [{ color: "#17263c" }], stylers: [{ color: '#17263c' }],
}, },
], ],
}} }}
/> />
</div> </div>
) );
} }
export default function SignIn(props) { export default function SignIn(props) {
return ( return (
<div style={{ <div style={{
height: "100%", height: '100%',
width: "100%", width: '100%',
}}> }}
>
<Scrollbars autoHeightMin="100%" autoHeightMax="100%"> <Scrollbars autoHeightMin="100%" autoHeightMax="100%">
<Grid container style={{padding: 30}}> <Grid container style={{ padding: 30 }}>
<Grid item xs={12}> <Grid item xs={12}>
<DeviceLastSeenMap /> <DeviceLastSeenMap />
</Grid> </Grid>
<Grid item xs={12}> <Grid item xs={12}>
<DrivesTable dongleId={props.device.dongle_id}/> <DrivesTable dongleId={props.device.dongle_id} />
</Grid> </Grid>
</Grid> </Grid>
@ -131,5 +127,3 @@ export default function SignIn(props) {
); );
} }

View File

@ -5,35 +5,26 @@ import Grid from '@mui/material/Grid';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
const stylezz = { const stylezz = {
margin: '0px 2px 0px 0px', margin: '0px 2px 0px 0px',
} };
function timeSince(date) { function timeSince(date) {
const seconds = Math.floor((new Date() - date) / 1000);
var seconds = Math.floor((new Date() - date) / 1000);
if (seconds / 86400 > 1) { if (seconds / 86400 > 1) {
return Math.floor(seconds / 86400) + `d`; return `${Math.floor(seconds / 86400)}d`;
} else if (seconds / 3600 > 1) { } if (seconds / 3600 > 1) {
return Math.floor(seconds / 3600) + `h`; return `${Math.floor(seconds / 3600)}h`;
} else if (seconds / 60 > 1) { } if (seconds / 60 > 1) {
return Math.floor(seconds / 60) + `m`; return `${Math.floor(seconds / 60)}m`;
} else {
return "just now";
} }
return 'just now';
} }
export default function SignIn(props) { export default function SignIn(props) {
const [state, setState] = React.useState({ count: 0, last_seen: 0 }); const [state, setState] = React.useState({ count: 0, last_seen: 0 });
const device = props.device; const { device } = props;
// Reloads component to update X time ago // Reloads component to update X time ago
// TODO prevent X time ago from being refreshed when the device has been // TODO prevent X time ago from being refreshed when the device has been
@ -41,21 +32,18 @@ export default function SignIn(props) {
useEffect(() => { useEffect(() => {
setInterval(() => { setInterval(() => {
setState({ ...state, count: state.count + 1 }) setState({ ...state, count: state.count + 1 });
}, 60 * 1000) }, 60 * 1000);
}); });
const deviceLastSeen = timeSince(new Date(device.last_seen)); const deviceLastSeen = timeSince(new Date(device.last_seen));
return ( return (
<div> <div>
<ButtonBase style={{ padding: '10px' }}> <ButtonBase style={{ padding: '10px' }}>
<Grid container spacing={2}> <Grid container spacing={2}>
<Grid item xs={4}> <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>
<Grid item xs={8} style={{ textAlign: 'left' }}> <Grid item xs={8} style={{ textAlign: 'left' }}>
{/* <TextField {/* <TextField
@ -77,16 +65,17 @@ export default function SignIn(props) {
}} }}
fullWidth fullWidth
/> */}
/>*/} <Typography variant="body2" align="left" gutterBottom>
<Typography variant="body2" align={"left"} gutterBottom>Dongle: {device.dongle_id}</Typography> Dongle:
{device.dongle_id}
</Typography>
<div> <div>
{device.online ? {device.online
<Chip style={{ background: '#004d40', ...stylezz }} label="Online" size="small" variant="outlined" /> : ? <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: '#b71c1c', ...stylezz }} label={`Offline ${deviceLastSeen}`} size="small" variant="outlined" />}
}
<Chip style={{ background: '#004d40', ...stylezz }} label="Active" size="small" variant="outlined" /> <Chip style={{ background: '#004d40', ...stylezz }} label="Active" size="small" variant="outlined" />
</div> </div>
@ -98,5 +87,3 @@ export default function SignIn(props) {
); );
} }

View File

@ -13,39 +13,36 @@ import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow'; import TableRow from '@mui/material/TableRow';
import Tooltip from '@mui/material/Tooltip'; import Tooltip from '@mui/material/Tooltip';
import React, { useContext, useEffect } from 'react'; import React, { useContext, useEffect } from 'react';
import { context as DeviceContext } from "./../../../context/devices"; import { context as DeviceContext } from '../../../context/devices';
import { context as SnackbarContext } from "./../../../context/toast"; import { context as SnackbarContext } from '../../../context/toast';
import * as deviceController from "./../../../controllers/devices"; import * as deviceController from '../../../controllers/devices';
import * as helpers from "./../../../controllers/helpers" import * as helpers from '../../../controllers/helpers';
function loading() { function loading() {
return ( return (
<TableRow> <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> </TableRow>
) );
} }
export default function EnhancedTable(props) { export default function EnhancedTable(props) {
const [state, dispatch] = useContext(DeviceContext) const [state, dispatch] = useContext(DeviceContext);
const [, notifDispatch] = useContext(SnackbarContext) const [, notifDispatch] = useContext(SnackbarContext);
useEffect(() => { useEffect(() => {
deviceController.getBootlogs(props.dongleId).then((res) => { deviceController.getBootlogs(props.dongleId).then((res) => {
setTimeout(() => { setTimeout(() => {
dispatch({ type: "update_dongle_bootlogs", dongle_id: props.dongleId, bootlogs: res.data }) dispatch({ type: 'update_dongle_bootlogs', dongle_id: props.dongleId, bootlogs: res.data });
}, 1) }, 1);
}).catch(() => { }).catch(() => {
notifDispatch({type: "NEW_TOAST", msg: 'Failed to load bootlogs'}) notifDispatch({ type: 'NEW_TOAST', msg: 'Failed to load bootlogs' });
}) });
}, [dispatch, notifDispatch, props.dongleId]);
}, [dispatch, notifDispatch, props.dongleId])
return ( return (
<Box sx={{ width: '100%' }}> <Box sx={{ width: '100%' }}>
@ -54,51 +51,48 @@ export default function EnhancedTable(props) {
<Table <Table
sx={{ minWidth: 750 }} sx={{ minWidth: 750 }}
aria-labelledby="tableTitle" aria-labelledby="tableTitle"
size={'small'} size="small"
> >
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell >Date</TableCell> <TableCell>Date</TableCell>
<TableCell >File</TableCell> <TableCell>File</TableCell>
<TableCell >File size</TableCell> <TableCell>File size</TableCell>
<TableCell >Actions</TableCell> <TableCell>Actions</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{/* if you don't need to support IE11, you can replace the `stableSort` call with: {/* if you don't need to support IE11, you can replace the `stableSort` call with:
rows.slice().sort(getComparator(order, orderBy)) */} rows.slice().sort(getComparator(order, orderBy)) */}
{state.dongles[props.dongleId].boot ? state.dongles[props.dongleId].boot.map((row) => { {state.dongles[props.dongleId].boot ? state.dongles[props.dongleId].boot.map((row) => (
return (
<TableRow hover> <TableRow hover>
<TableCell >{helpers.formatDate(row.date)}</TableCell> <TableCell>{helpers.formatDate(row.date)}</TableCell>
<TableCell >{row.name}</TableCell> <TableCell>{row.name}</TableCell>
<TableCell >{Math.round(row.size / 1024) + ' MiB'}</TableCell> <TableCell>{`${Math.round(row.size / 1024)} MiB`}</TableCell>
<TableCell> <TableCell>
<Tooltip title="Open in new window"> <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"/> <OpenInNewIcon fontSize="inherit" />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Tooltip title="Preserve"> <Tooltip title="Preserve">
<IconButton size="small"> <IconButton size="small">
<FavoriteBorderIcon fontSize="inherit"/> <FavoriteBorderIcon fontSize="inherit" />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Tooltip title="Delete"> <Tooltip title="Delete">
<IconButton size="small"> <IconButton size="small">
<DeleteIcon fontSize="inherit"/> <DeleteIcon fontSize="inherit" />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
</TableCell> </TableCell>
</TableRow> </TableRow>
) )) : [1, 1, 1, 1, 1].map(loading) }
}) : [1, 1, 1, 1, 1].map(loading) }
</TableBody> </TableBody>
</Table> </Table>
</TableContainer> </TableContainer>
@ -106,4 +100,3 @@ export default function EnhancedTable(props) {
</Box> </Box>
); );
} }

View File

@ -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 DeleteIcon from '@mui/icons-material/Delete';
import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder'; import FavoriteBorderIcon from '@mui/icons-material/FavoriteBorder';
@ -15,13 +15,9 @@ import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow'; import TableRow from '@mui/material/TableRow';
import Tooltip from '@mui/material/Tooltip'; import Tooltip from '@mui/material/Tooltip';
import React, { useContext, useEffect } from 'react'; import React, { useContext, useEffect } from 'react';
import { context as DeviceContext } from "./../../../context/devices"; import { context as DeviceContext } from '../../../context/devices';
import * as deviceController from "./../../../controllers/devices"; import * as deviceController from '../../../controllers/devices';
import * as helpers from "./../../../controllers/helpers" import * as helpers from '../../../controllers/helpers';
function buildContent(row) { function buildContent(row) {
return ( return (
@ -29,15 +25,13 @@ function buildContent(row) {
hover hover
> >
<TableCell>{helpers.formatDate(row.date)}</TableCell>
<TableCell >{helpers.formatDate(row.date)}</TableCell> <TableCell>{row.name}</TableCell>
<TableCell >{row.name}</TableCell> <TableCell>{`${Math.round(row.size / 1024)} MiB`}</TableCell>
<TableCell >{Math.round(row.size / 1024) + ' MiB'}</TableCell>
<TableCell> <TableCell>
<Tooltip title="Open in new window"> <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" /> <OpenInNewIcon fontSize="inherit" />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
@ -56,31 +50,31 @@ function buildContent(row) {
</TableCell> </TableCell>
</TableRow> </TableRow>
) );
} }
function loading() { function loading() {
return ( return (
<TableRow> <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> </TableRow>
) );
} }
export default function EnhancedTable(props) { export default function EnhancedTable(props) {
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
const [state, dispatch] = useContext(DeviceContext) const [state, dispatch] = useContext(DeviceContext);
useEffect(() => { useEffect(() => {
deviceController.getCrashlogs(props.dongleId).then((res) => { 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]); }, [dispatch, props.dongleId]);
console.log("drives", state.dongles[props.dongleId]) console.log('drives', state.dongles[props.dongleId]);
console.log("drives", typeof state.dongles[props.dongleId]) console.log('drives', typeof state.dongles[props.dongleId]);
return ( return (
<Box sx={{ width: '100%' }}> <Box sx={{ width: '100%' }}>
@ -89,23 +83,21 @@ export default function EnhancedTable(props) {
<Table <Table
sx={{ minWidth: 750 }} sx={{ minWidth: 750 }}
aria-labelledby="tableTitle" aria-labelledby="tableTitle"
size={'small'} size="small"
> >
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell >Date</TableCell> <TableCell>Date</TableCell>
<TableCell >File</TableCell> <TableCell>File</TableCell>
<TableCell >File size</TableCell> <TableCell>File size</TableCell>
<TableCell >Actions</TableCell> <TableCell>Actions</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{state.dongles[props.dongleId].crash ? {state.dongles[props.dongleId].crash
state.dongles[props.dongleId].crash.length > 0 ? state.dongles[props.dongleId].crash.map(buildContent) : <p> No drives </p> ? 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)}
[1, 1, 1, 1, 1].map(loading)
}
</TableBody> </TableBody>
</Table> </Table>
@ -115,4 +107,3 @@ export default function EnhancedTable(props) {
</Box> </Box>
); );
} }

View File

@ -1,47 +1,37 @@
import ContentCopyIcon from '@mui/icons-material/ContentCopy'; import ContentCopyIcon from '@mui/icons-material/ContentCopy';
import Grid from '@mui/material/Grid'; import Grid from '@mui/material/Grid';
import IconButton from '@mui/material/IconButton'; 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 Tooltip from '@mui/material/Tooltip';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { context as DeviceContext } from "./../../../context/devices"; import { context as DeviceContext } from '../../../context/devices';
import { context as SnackbarContext } from "./../../../context/toast"; import { context as SnackbarContext } from '../../../context/toast';
import * as helpers from "./../../../controllers/helpers" import * as helpers from '../../../controllers/helpers';
export default function SignIn(props) { export default function SignIn(props) {
const [state] = useContext(DeviceContext);
const [state] = useContext(DeviceContext) const [, notifDispatch] = useContext(SnackbarContext);
const [, notifDispatch] = useContext(SnackbarContext)
function pubKeyClipboard(newClip) { function pubKeyClipboard(newClip) {
navigator.clipboard.writeText(newClip).then(function () { navigator.clipboard.writeText(newClip).then(() => {
notifDispatch({ notifDispatch({
type: "NEW_TOAST", type: 'NEW_TOAST',
open: true, open: true,
msg: "Successfully copied to clipboard!" msg: 'Successfully copied to clipboard!',
}) });
}, function () { }, () => {
notifDispatch({ notifDispatch({
type: "NEW_TOAST", type: 'NEW_TOAST',
open: true, 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]; const dongle = state.dongles[props.dongleId];
if (!dongle) { if (!dongle) {
return ( return (
<Grid container> <Grid container>
@ -53,7 +43,7 @@ export default function SignIn(props) {
</Grid> </Grid>
) );
} }
return ( return (
@ -63,29 +53,47 @@ export default function SignIn(props) {
<Grid container> <Grid container>
<Grid item xs={3}> <Grid item xs={3}>
<b>Nickname:</b>
<b>Nickname:</b> {dongle.nick_name ? dongle.nick_name : `My ${dongle.device_type}`}<br></br> {' '}
<b>Type:</b> {dongle.device_type}<br></br> {dongle.nick_name ? dongle.nick_name : `My ${dongle.device_type}`}
<b>Serial:</b> {dongle.serial}<br></br> <br />
<b>IMEI:</b> {dongle.imei}<br></br> <b>Type:</b>
<b>Registered:</b> {helpers.formatDate(dongle.created)}<br></br> {' '}
<b>Last Ping:</b> {helpers.formatDate(dongle.last_ping)}<br></br> {dongle.device_type}
<b>Public Key:</b> -----BEGIN PUBLIC KEY----- <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"> <Tooltip title="Copy public key">
<IconButton onClick={() => pubKeyClipboard(dongle.public_key)}> <IconButton onClick={() => pubKeyClipboard(dongle.public_key)}>
<ContentCopyIcon /> <ContentCopyIcon />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<br></br> <br />
<b>Quota Storage: </b>
<b>Quota Storage: </b>{dongle.storage_used} MB / 200000 MB {dongle.storage_used}
{' '}
MB / 200000 MB
</Grid> </Grid>
</Grid> </Grid>
</div> </div>
); );
} }

View File

@ -13,26 +13,26 @@ import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow'; import TableRow from '@mui/material/TableRow';
import Tooltip from '@mui/material/Tooltip'; import Tooltip from '@mui/material/Tooltip';
import React, { useContext, useEffect, useState } from 'react'; import React, { useContext, useEffect, useState } from 'react';
import { context as DeviceContext } from "./../../../context/devices"; import { context as DeviceContext } from '../../../context/devices';
import { context as SnackbarContext } from "./../../../context/toast"; import { context as SnackbarContext } from '../../../context/toast';
import * as deviceController from "./../../../controllers/devices"; import * as deviceController from '../../../controllers/devices';
import * as helpers from "./../../../controllers/helpers" import * as helpers from '../../../controllers/helpers';
import ViewDrive from "./view_drive" import ViewDrive from './view_drive';
export default function EnhancedTable(props) { export default function EnhancedTable(props) {
const [deviceState, dispatch] = useContext(DeviceContext) const [deviceState, dispatch] = useContext(DeviceContext);
const [, notifDispatch] = useContext(SnackbarContext) const [, notifDispatch] = useContext(SnackbarContext);
const [state, setState] = useState({selectedSegment: null}) const [state, setState] = useState({ selectedSegment: null });
useEffect(() => { useEffect(() => {
deviceController.getDrives(props.dongleId).then((res) => { deviceController.getDrives(props.dongleId).then((res) => {
setTimeout(() => { setTimeout(() => {
dispatch({ type: "update_dongle_drive", dongle_id: props.dongleId, drives: res.data }) dispatch({ type: 'update_dongle_drive', dongle_id: props.dongleId, drives: res.data });
}, 1) }, 1);
}).catch(() => { }).catch(() => {
notifDispatch({type: "NEW_TOAST", msg: 'Failed to load drives'}) notifDispatch({ type: 'NEW_TOAST', msg: 'Failed to load drives' });
}) });
}, [dispatch, notifDispatch, props.dongleId]) }, [dispatch, notifDispatch, props.dongleId]);
return ( return (
<Box sx={{ width: '100%' }}> <Box sx={{ width: '100%' }}>
@ -41,7 +41,7 @@ export default function EnhancedTable(props) {
<Table <Table
sx={{ minWidth: 750 }} sx={{ minWidth: 750 }}
aria-labelledby="tableTitle" aria-labelledby="tableTitle"
size={'small'} size="small"
> >
<TableHead> <TableHead>
<TableRow> <TableRow>
@ -65,25 +65,27 @@ export default function EnhancedTable(props) {
let metadata; let metadata;
try { try {
metadata = JSON.parse(row.metadata) metadata = JSON.parse(row.metadata);
} catch (err) { metadata = {} } } catch (err) { metadata = {}; }
return ( return (
<TableRow <TableRow
hover 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 <TableCell
scope="row" scope="row"
>{row.identifier}</TableCell> >
{row.identifier}
</TableCell>
<TableCell >{metadata.hasOwnProperty('CarParams1') ? metadata.CarParams['CarName'] : "Glorious Skoda"}</TableCell> <TableCell>{metadata.hasOwnProperty('CarParams1') ? metadata.CarParams.CarName : 'Glorious Skoda'}</TableCell>
<TableCell >{metadata.hasOwnProperty('InitData1') ? metadata.InitData['Version'] : "Lemon boy"}</TableCell> <TableCell>{metadata.hasOwnProperty('InitData1') ? metadata.InitData.Version : 'Lemon boy'}</TableCell>
<TableCell >{Math.round(row.filesize / 1024) + ' MiB'}</TableCell> <TableCell>{`${Math.round(row.filesize / 1024)} MiB`}</TableCell>
<TableCell >{helpers.formatDuration(row.duration)}</TableCell> <TableCell>{helpers.formatDuration(row.duration)}</TableCell>
<TableCell >{Math.round(row.distance_meters / 1000)}</TableCell> <TableCell>{Math.round(row.distance_meters / 1000)}</TableCell>
<TableCell >{row.upload_complete.toString()}</TableCell> <TableCell>{row.upload_complete.toString()}</TableCell>
<TableCell >{row.is_processed.toString()}</TableCell> <TableCell>{row.is_processed.toString()}</TableCell>
<TableCell >{helpers.formatDate(row.drive_date)}</TableCell> <TableCell>{helpers.formatDate(row.drive_date)}</TableCell>
<TableCell> <TableCell>
<Tooltip title="Open in new window"> <Tooltip title="Open in new window">
@ -106,13 +108,11 @@ export default function EnhancedTable(props) {
</TableCell> </TableCell>
</TableRow> </TableRow>
) );
})
}) : : [1, 1, 1, 1, 1].map((v) => (
<TableRow>
[1, 1, 1, 1, 1].map((v) => (
<TableRow
>
<TableCell padding="checkbox"> <TableCell padding="checkbox">
<Skeleton animation="wave" /> <Skeleton animation="wave" />
</TableCell> </TableCell>
@ -122,19 +122,16 @@ export default function EnhancedTable(props) {
<Skeleton animation="wave" /> <Skeleton animation="wave" />
</TableCell> </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> </TableRow>
)) ))}
}
</TableBody> </TableBody>
</Table> </Table>
@ -145,4 +142,3 @@ export default function EnhancedTable(props) {
</Box> </Box>
); );
} }

View File

@ -2,17 +2,16 @@ import Box from '@mui/material/Box';
import Tab from '@mui/material/Tab'; import Tab from '@mui/material/Tab';
import Tabs from '@mui/material/Tabs'; import Tabs from '@mui/material/Tabs';
import React from 'react'; import React from 'react';
import BootLogsTable from "./boot"; import BootLogsTable from './boot';
import Console from './console'; import Console from './console';
import CrashLogsTable from "./crash"; import CrashLogsTable from './crash';
import DeviceInfo from './device'; import DeviceInfo from './device';
import DrivesLogTable from "./drives"; import DrivesLogTable from './drives';
function TabPanel(props) { function TabPanel(props) {
const { children, value, index, ...other } = props; const {
children, value, index, ...other
} = props;
return ( return (
<div <div
@ -31,10 +30,7 @@ function TabPanel(props) {
); );
} }
export default function SignIn(props) { export default function SignIn(props) {
const [value, setValue] = React.useState(0); const [value, setValue] = React.useState(0);
const handleChange = (event, newValue) => { const handleChange = (event, newValue) => {
@ -45,8 +41,13 @@ export default function SignIn(props) {
<div className="wrapper"> <div className="wrapper">
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}> <Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<Tabs value={value} onChange={handleChange} aria-label="basic tabs example" variant="scrollable" <Tabs
scrollButtons="auto"> value={value}
onChange={handleChange}
aria-label="basic tabs example"
variant="scrollable"
scrollButtons="auto"
>
<Tab label="Device" /> <Tab label="Device" />
<Tab label="Drives" /> <Tab label="Drives" />
<Tab label="Crashes" /> <Tab label="Crashes" />
@ -72,10 +73,7 @@ export default function SignIn(props) {
{ {
} }
</div> </div>
); );
} }

View File

@ -10,168 +10,169 @@ import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow'; import TableRow from '@mui/material/TableRow';
import Tooltip from '@mui/material/Tooltip'; import Tooltip from '@mui/material/Tooltip';
import React, { useContext, useState } from 'react'; import React, { useContext, useState } from 'react';
import { context as DeviceContext } from "./../../../context/devices"; import Typography from '@mui/material/Typography';
import * as deviceController from "./../../../controllers/devices"; import { context as DeviceContext } from '../../../context/devices';
import Typography from "@mui/material/Typography" import * as deviceController from '../../../controllers/devices';
export default function EnhancedTable(props) { 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) { if (state.drive === null) {
setState({ ...state, drive: props.drive }) setState({ ...state, drive: props.drive });
} }
if (props.drive !== state.drive) { if (props.drive !== state.drive) {
setState({ ...state, loading: true, firstReqSent: false, segment: null, drive: props.drive }) setState({
...state, loading: true, firstReqSent: false, segment: null, drive: props.drive,
});
} }
const dongle_id = props.dongleId; const dongle_id = props.dongleId;
const drive_id = props.drive; const drive_id = props.drive;
const dongle = deviceState.dongles[dongle_id]; const dongle = deviceState.dongles[dongle_id];
console.log("view drive", dongle) console.log('view drive', dongle);
console.log("drives", dongle.drives) console.log('drives', dongle.drives);
if (!dongle || !dongle.drives) return (<p>loading</p>) if (!dongle || !dongle.drives) return (<p>loading</p>);
if (state.segment === null) { if (state.segment === null) {
// TODO Make this not run multiple times // TODO Make this not run multiple times
deviceController.getDriveSegments(dongle_id, dongle.drives[drive_id].identifier).then((res) => { deviceController.getDriveSegments(dongle_id, dongle.drives[drive_id].identifier).then((res) => {
console.log("my res", res.data) console.log('my res', res.data);
if (res.data === null) { if (res.data === null) {
setState({ ...state, loading: false, firstReqSent: true, segment: [] }) setState({
...state, loading: false, firstReqSent: true, segment: [],
});
} else { } else {
setState({ ...state, loading: false, firstReqSent: true, segment: res.data }) setState({
...state, loading: false, firstReqSent: true, segment: res.data,
});
} }
});
})
} }
// test // test
const drive = dongle.drives[drive_id]; const drive = dongle.drives[drive_id];
let vehicle = '';
let version = '';
let gitRemote = '';
let gitBranch = '';
let vehicle = ""; let gitCommit = '';
let version = "";
let gitRemote = "";
let gitBranch = "";
let gitCommit = "";
let metadata = {}; let metadata = {};
try { try {
metadata = JSON.parse(drive.metadata); metadata = JSON.parse(drive.metadata);
if (metadata['InitData']) { if (metadata.InitData) {
version = metadata['InitData']['Version'] || "Unknown"; version = metadata.InitData.Version || 'Unknown';
gitRemote = metadata['InitData']['GitRemote'] || "Unknown"; gitRemote = metadata.InitData.GitRemote || 'Unknown';
gitBranch = metadata['InitData']['GitBranch'] || "Unknown"; gitBranch = metadata.InitData.GitBranch || 'Unknown';
gitCommit = metadata['InitData']['GitCommit'] || "Unknown"; gitCommit = metadata.InitData.GitCommit || 'Unknown';
} }
if (metadata.CarParams) {
if (metadata['CarParams']) { if (metadata.CarParams.CarName !== undefined) vehicle += `${metadata.CarParams.CarName.toUpperCase()} `;
if (metadata['CarParams']['CarName'] !== undefined) vehicle += (metadata['CarParams']['CarName'].toUpperCase()) + " "; if (metadata.CarParams.CarFingerprint !== undefined) vehicle += (metadata.CarParams.CarFingerprint.toUpperCase());
if (metadata['CarParams']['CarFingerprint'] !== undefined) vehicle += (metadata['CarParams']['CarFingerprint'].toUpperCase())
} }
} catch (exception) { console.log(exception) } } catch (exception) { console.log(exception); }
//const directoryTree = dirTree(config.storagePath + device.dongle_id + "/" + dongleIdHash + "/" + driveIdentifierHash + "/" + drive.identifier); // const directoryTree = dirTree(config.storagePath + device.dongle_id + "/" + dongleIdHash + "/" + driveIdentifierHash + "/" + drive.identifier);
const directoryTree = state.segment; const directoryTree = state.segment;
const driveUrl = "driveurl" const driveUrl = 'driveurl';
var directorySegments = {}; const directorySegments = {};
if (directoryTree) { if (directoryTree) {
for (var i in directoryTree.children) { for (const i in directoryTree.children) {
// skip any non-directory entries (for example m3u8 file in the drive directory) // skip any non-directory entries (for example m3u8 file in the drive directory)
if (directoryTree.children[i].type !== 'directory') continue; if (directoryTree.children[i].type !== 'directory') continue;
var segment = directoryTree.children[i].name; const segment = directoryTree.children[i].name;
let logSegment = {} const logSegment = {};
for (var c in directoryTree.children[i].children) { for (const c in directoryTree.children[i].children) {
logSegment[directoryTree.children[i].children[c].name] = { logSegment[directoryTree.children[i].children[c].name] = {
url: `${driveUrl}/${segment}/${directoryTree.children[i].children[c].name}`, url: `${driveUrl}/${segment}/${directoryTree.children[i].children[c].name}`,
name: directoryTree.children[i].children[c].name, name: directoryTree.children[i].children[c].name,
fileSize: directoryTree.children[i].children[c].size fileSize: directoryTree.children[i].children[c].size,
} };
} }
directorySegments[segment] = logSegment; directorySegments[segment] = logSegment;
} }
console.log("output is", directorySegments) console.log('output is', directorySegments);
} }
return ( return (
<Box sx={{ width: '100%' }}> <Box sx={{ width: '100%' }}>
<Paper sx={{ width: '100%', mb: 2, padding: '20px' }}> <Paper sx={{ width: '100%', mb: 2, padding: '20px' }}>
<Typography variant="body1"><b>Vehicle:</b> {vehicle}</Typography> <Typography variant="body1">
<Typography variant="body1"><b>Version:</b> {version}</Typography> <b>Vehicle:</b>
<Typography variant="body1"><b>gitRemote:</b> {gitRemote}</Typography> {' '}
<Typography variant="body1"><b>gitBranch:</b> {gitBranch}</Typography> {vehicle}
<Typography variant="body1"><b>gitCommit:</b> {gitCommit}</Typography> </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> <Typography variant="body2"><b>Fingerprint: </b></Typography>
<TableContainer> <TableContainer>
<Table <Table
sx={{ minWidth: 750 }} sx={{ minWidth: 750 }}
aria-labelledby="tableTitle" aria-labelledby="tableTitle"
size={'small'} size="small"
> >
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell >Segment ID</TableCell> <TableCell>Segment ID</TableCell>
<TableCell >File</TableCell> <TableCell>File</TableCell>
<TableCell >File size</TableCell> <TableCell>File size</TableCell>
<TableCell >Actions</TableCell> <TableCell>Actions</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
{ {
directorySegments ? Object.keys(directorySegments).map((key, index) => { directorySegments ? Object.keys(directorySegments).map((key, index) => Object.keys(directorySegments[key]).map((key1, index1) => (
return Object.keys(directorySegments[key]).map((key1, index1) => (
<TableRow hover> <TableRow hover>
<TableCell >{key}</TableCell> <TableCell>{key}</TableCell>
<TableCell >{directorySegments[key][key1].name}</TableCell> <TableCell>{directorySegments[key][key1].name}</TableCell>
<TableCell>{Math.round(directorySegments[key][key1].fileSize / 1024) + ' MiB'}</TableCell> <TableCell>{`${Math.round(directorySegments[key][key1].fileSize / 1024)} MiB`}</TableCell>
<TableCell> <TableCell>
<Tooltip title="Open in new window"> <Tooltip title="Open in new window">
<IconButton size="small" onClick={() => window.open(directorySegments[key][key1].url, "_blank")}> <IconButton size="small" onClick={() => window.open(directorySegments[key][key1].url, '_blank')}>
<OpenInNewIcon fontSize="inherit" /> <OpenInNewIcon fontSize="inherit" />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
</TableCell> </TableCell>
</TableRow> </TableRow>
)) ))) : null
}) : null
} }
</TableBody> </TableBody>
@ -179,7 +180,7 @@ export default function EnhancedTable(props) {
</TableContainer> </TableContainer>
</Paper> </Paper>
</Box > </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"'; cabanaUrl = config.cabanaUrl + '?retropilotIdentifier=' + device.dongle_id + '|' + dongleIdHash + '|' + drive.identifier + '|' + driveIdentifierHash + '&retropilotHost=' + encodeURIComponent(config.baseUrl) + '&demo=1"';
} }
var response = `<html style="font-family: monospace"> var response = `<html style="font-family: monospace">
<head> <head>
<link href="https://vjs.zencdn.net/7.11.4/video-js.css" rel="stylesheet" /> <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> <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 = {}; var directorySegments = {};
for (var i in directoryTree.children) { for (var i in directoryTree.children) {
// skip any non-directory entries (for example m3u8 file in the drive directory) // 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 segment = directoryTree.children[i].name;
var qcamera = '--'; var qcamera = '--';
var fcamera = '--'; var fcamera = '--';
var dcamera = '--'; var dcamera = '--';

View File

@ -1,16 +1,16 @@
import { createTheme, ThemeProvider } from '@mui/material/styles'; import { createTheme, ThemeProvider } from '@mui/material/styles';
import React, { useContext, useState } from 'react'; import React, { useContext, useState } from 'react';
import { Link } from "react-router-dom"; import { Link } from 'react-router-dom';
import { UserContext } from "./../../context/users"; import { UserContext } from '../../context/users';
const theme = createTheme(); const theme = createTheme();
export default function SignIn() { export default function SignIn() {
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false);
const [ state, dispatch ] = useContext(UserContext) const [state, dispatch] = useContext(UserContext);
console.log("component", state) console.log('component', state);
const handleSubmit = (event) => { const handleSubmit = (event) => {
dispatch({ type: "toggle_button" }) dispatch({ type: 'toggle_button' });
event.preventDefault(); event.preventDefault();
const data = new FormData(event.currentTarget); const data = new FormData(event.currentTarget);
@ -20,19 +20,15 @@ export default function SignIn() {
password: data.get('password'), password: data.get('password'),
}); });
setLoading(true) setLoading(true);
}; };
return ( return (
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<p>hello</p> <p>hello</p>
<Link to="/login" variant="body2"> <Link to="/login" variant="body2">
{"login?"} login?
</Link> </Link>
</ThemeProvider> </ThemeProvider>
); );
} }

View File

@ -7,14 +7,14 @@ import Paper from '@mui/material/Paper';
import TextField from '@mui/material/TextField'; import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import React, { useContext, useState } from 'react'; import React, { useContext, useState } from 'react';
import { UserContext } from "./../../context/users"; import { UserContext } from '../../context/users';
export default function SignIn() { export default function SignIn() {
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false);
const [state, dispatch] = useContext(UserContext) const [state, dispatch] = useContext(UserContext);
console.log("component", state) console.log('component', state);
const handleSubmit = (event) => { const handleSubmit = (event) => {
dispatch({ type: "toggle_button" }) dispatch({ type: 'toggle_button' });
event.preventDefault(); event.preventDefault();
const data = new FormData(event.currentTarget); const data = new FormData(event.currentTarget);
@ -24,7 +24,7 @@ export default function SignIn() {
password: data.get('password'), password: data.get('password'),
}); });
setLoading(true) setLoading(true);
}; };
return ( return (
@ -41,13 +41,10 @@ export default function SignIn() {
alignItems: 'center', alignItems: 'center',
}} }}
style={{ style={{
padding: '15px' padding: '15px',
}} }}
> >
<Typography component="h1" variant="h5" align="left"> <Typography component="h1" variant="h5" align="left">
Sign in Sign in
</Typography> </Typography>
@ -85,20 +82,15 @@ export default function SignIn() {
</LoadingButton> </LoadingButton>
<Link href="#" variant="body2"> <Link href="#" variant="body2">
{"New Here or Forgotten password?"} New Here or Forgotten password?
</Link> </Link>
</Box> </Box>
</Paper> </Paper>
</Grid> </Grid>
</Grid> </Grid>
</Container> </Container>
); );
} }

View File

@ -2,52 +2,41 @@ import Grid from '@mui/material/Grid';
import Paper from '@mui/material/Paper'; import Paper from '@mui/material/Paper';
import { Scrollbars } from 'rc-scrollbars'; import { Scrollbars } from 'rc-scrollbars';
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { context as DeviceContext } from "./../../context/devices"; import { context as DeviceContext } from '../../context/devices';
import DeviceData from './../device/deviceData'; import DeviceData from '../device/deviceData';
import DeviceOverview from "./../device/overview"; import DeviceOverview from '../device/overview';
export default function SignIn() { export default function SignIn() {
const [deviceState] = useContext(DeviceContext); const [deviceState] = useContext(DeviceContext);
return ( return (
<div className="wrapper"> <div className="wrapper">
<Grid container spacing={0} style={{ height: '100%', justify: 'space-around', minHeight: "100%", maxHeight: "100%" }} > <Grid
<Grid item xs={12} md={4} lg={3} sm={6} xl={2} style={{ minHeight: "100%", maxHeight: "100%" }}> container
<Paper style={{ minHeight: "100%", maxHeight: "100%", margin: "0" }}> spacing={0}
<Scrollbars autoHeight={true} autoHeightMin="calc(100vh - 14px)" autoHeightMax="calc(100% - 14px)"> 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' }}> <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> </div>
</Scrollbars> </Scrollbars>
</Paper> </Paper>
</Grid> </Grid>
<Grid item xs={12} md={8} lg={9} sm={6} xl={10}> <Grid item xs={12} md={8} lg={9} sm={6} xl={10}>
{deviceState.dongles['53331425'] ? <DeviceData device={deviceState.dongles['53331425']} /> : <p>no</p>} {deviceState.dongles['53331425'] ? <DeviceData device={deviceState.dongles['53331425']} /> : <p>no</p>}
</Grid> </Grid>
</Grid> </Grid>
</div> </div>
); );
} }

View File

@ -1,19 +1,12 @@
import Snackbar from '@mui/material/Snackbar'; import Snackbar from '@mui/material/Snackbar';
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { context as DeviceContext } from "./../../context/toast"; import { context as DeviceContext } from '../../context/toast';
export default function Toast(props) { export default function Toast(props) {
const [state, dispatch] = useContext(DeviceContext) const [state, dispatch] = useContext(DeviceContext);
const handleClose = () => { const handleClose = () => {
dispatch({ type: 'CLOSE_TOAST' }) dispatch({ type: 'CLOSE_TOAST' });
}; };
return ( return (

View File

@ -1,12 +1,11 @@
import React, { createContext, useEffect, useReducer } from "react"; import React, { createContext, useEffect, useReducer } from 'react';
import * as deviceController from "./../../controllers/devices"; import * as deviceController from '../../controllers/devices';
function process(state, action) { function process(state, action) {
if (action.type !== "ADD_DATA") { return state } if (action.type !== 'ADD_DATA') { return state; }
switch (action.data.command) { switch (action.data.command) {
case 'dongle_status':
case "dongle_status":
return { return {
...state, ...state,
dongles: { dongles: {
@ -15,102 +14,98 @@ function process(state, action) {
...state.dongles[action.data.data.dongle_id], ...state.dongles[action.data.data.dongle_id],
online: action.data.data.online, online: action.data.data.online,
last_seen: action.data.data.time, last_seen: action.data.data.time,
dongle_id: action.data.data.dongle_id dongle_id: action.data.data.dongle_id,
} },
} },
} };
default: default:
return state; return state;
} }
} }
export const Reducer = (state, action) => { export const Reducer = (state, action) => {
console.log("input", state, action) console.log('input', state, action);
switch (action.type) { switch (action.type) {
case 'ADD_DATA': case 'ADD_DATA':
return process(state, action); return process(state, action);
case "fetch_all_dongles": case 'fetch_all_dongles':
console.log("fetch", action) console.log('fetch', action);
return { return {
...state, ...state,
dongles: action.data dongles: action.data,
} };
case "update_dongle_drive": case 'update_dongle_drive':
return { return {
...state, ...state,
dongles: { dongles: {
...state.dongles, ...state.dongles,
[action.dongle_id]: { [action.dongle_id]: {
...state.dongles[action.dongle_id], ...state.dongles[action.dongle_id],
drives: action.drives drives: action.drives,
} },
} },
} };
case "update_dongle_bootlogs": case 'update_dongle_bootlogs':
return { return {
...state, ...state,
dongles: { dongles: {
...state.dongles, ...state.dongles,
[action.dongle_id]: { [action.dongle_id]: {
...state.dongles[action.dongle_id], ...state.dongles[action.dongle_id],
boot: action.bootlogs boot: action.bootlogs,
} },
} },
} };
case "update_dongle_crashlogs": case 'update_dongle_crashlogs':
return { return {
...state, ...state,
dongles: { dongles: {
...state.dongles, ...state.dongles,
[action.dongle_id]: { [action.dongle_id]: {
...state.dongles[action.dongle_id], ...state.dongles[action.dongle_id],
crash: action.crashlogs crash: action.crashlogs,
} },
} },
} };
case "user_authentication": case 'user_authentication':
return { return {
...state, ...state,
user: action.user user: action.user,
} };
default: default:
return state; return state;
} }
}; };
const initialState = { const initialState = {
dongles: {} dongles: {},
}; };
const Store = ({ children }) => { function Store({ children }) {
console.log("STORE HAS BEEN RERENDERED") console.log('STORE HAS BEEN RERENDERED');
const [state, dispatch] = useReducer(Reducer, initialState); const [state, dispatch] = useReducer(Reducer, initialState);
useEffect(() => { useEffect(() => {
const ws = new WebSocket('ws://localhost:81'); const ws = new WebSocket('ws://localhost:81');
ws.onmessage = ({ data }) => { ws.onmessage = ({ data }) => {
data = JSON.parse(data) data = JSON.parse(data);
console.log("Message") console.log('Message');
if (data.id) { if (data.id) {
dispatch({ type: "ADD_DATA", id: data.id, data: data }) dispatch({ type: 'ADD_DATA', id: data.id, data });
} }
}; };
deviceController.getAllDevices().then((devices) => { deviceController.getAllDevices().then((devices) => {
console.log("store", devices) console.log('store', devices);
dispatch({ type: "fetch_all_dongles", data: devices }) dispatch({ type: 'fetch_all_dongles', data: devices });
}) });
return () => { return () => {
try { try {
@ -119,13 +114,12 @@ const Store = ({ children }) => {
}; };
}, []); }, []);
return ( return (
<context.Provider value={[state, dispatch]}> <context.Provider value={[state, dispatch]}>
{children} {children}
</context.Provider> </context.Provider>
) );
}; }
export const context = createContext(initialState); export const context = createContext(initialState);
export default Store; export default Store;

View File

@ -1,20 +1,19 @@
import React, {createContext, useReducer} from "react"; import React, { createContext, useReducer } from 'react';
import Reducer from './reducer' import Reducer from './reducer';
const initialState = { const initialState = {
open: false, open: false,
message: null message: null,
}; };
const Store = ({children}) => { function Store({ children }) {
const [state, dispatch] = useReducer(Reducer, initialState); const [state, dispatch] = useReducer(Reducer, initialState);
return ( return (
<context.Provider value={[state, dispatch]}> <context.Provider value={[state, dispatch]}>
{children} {children}
</context.Provider> </context.Provider>
) );
}; }
export const context = createContext(initialState); export const context = createContext(initialState);
export default Store; export default Store;

View File

@ -4,13 +4,13 @@ const Reducer = (state, action) => {
return { return {
...state, ...state,
open: action.open, open: action.open,
msg: action.message msg: action.message,
}; };
case 'CLOSE_TOAST': case 'CLOSE_TOAST':
return { return {
...state, ...state,
open: false open: false,
} };
default: default:
return state; return state;

View File

@ -1,17 +1,17 @@
import React from "react" import React from 'react';
import { reducer, initialState } from "./reducer" import { reducer, initialState } from './reducer';
export const UserContext = React.createContext({ export const UserContext = React.createContext({
state: initialState, state: initialState,
dispatch: () => null dispatch: () => null,
}) });
export const UserProvider = ({ children }) => { export function UserProvider({ children }) {
const [state, dispatch] = React.useReducer(reducer, initialState) const [state, dispatch] = React.useReducer(reducer, initialState);
return ( return (
<UserContext.Provider value={[ state, dispatch ]}> <UserContext.Provider value={[state, dispatch]}>
{ children } { children }
</UserContext.Provider> </UserContext.Provider>
) );
} }

View File

@ -1,16 +1,16 @@
export const reducer = (state, action) => { export const reducer = (state, action) => {
switch (action.type) { switch (action.type) {
case "sign_out": case 'sign_out':
return { return {
...state, ...state,
active: !state.active active: !state.active,
} };
default: default:
return state return state;
} }
} };
export const initialState = { export const initialState = {
signedIn: false, signedIn: false,
@ -19,4 +19,4 @@ export const initialState = {
username: null, username: null,
JWT: null, JWT: null,
}, },
} };

View File

@ -1,9 +1,6 @@
import axios from "axios"; import axios from 'axios';
export async function getSession() { export async function getSession() {
const req = await axios.get('http://localhost/retropilot/0/useradmin/session', { withCredentials: true });
const req = await axios.get(`http://localhost/retropilot/0/useradmin/session`, {withCredentials: true}); return req.data;
return req.data
} }

View File

@ -1,49 +1,43 @@
import axios from "axios"; import axios from 'axios';
export async function getDrives(dongleId) { export async function getDrives(dongleId) {
const req = await axios.get(`http://localhost/retropilot/0/device/${dongleId}/drives/false`, { withCredentials: true }); const req = await axios.get(`http://localhost/retropilot/0/device/${dongleId}/drives/false`, { withCredentials: true });
return req.data return req.data;
} }
export async function getBootlogs(dongleId) { export async function getBootlogs(dongleId) {
const req = await axios.get(`http://localhost/retropilot/0/device/${dongleId}/bootlogs`, { withCredentials: true }); const req = await axios.get(`http://localhost/retropilot/0/device/${dongleId}/bootlogs`, { withCredentials: true });
return req.data return req.data;
} }
export async function getCrashlogs(dongleId) { export async function getCrashlogs(dongleId) {
const req = await axios.get(`http://localhost/retropilot/0/device/${dongleId}/crashlogs`, { withCredentials: true }); const req = await axios.get(`http://localhost/retropilot/0/device/${dongleId}/crashlogs`, { withCredentials: true });
return req.data return req.data;
} }
export async function getDriveSegments(dongleId, drive_identifier) { export async function getDriveSegments(dongleId, drive_identifier) {
const req = await axios.get(`http://localhost/retropilot/0/device/${dongleId}/drives/${drive_identifier}/segment`, { withCredentials: true }); const req = await axios.get(`http://localhost/retropilot/0/device/${dongleId}/drives/${drive_identifier}/segment`, { withCredentials: true });
return req.data return req.data;
} }
export async function getAllDevices() { export async function getAllDevices() {
const req = await axios.get(`http://localhost/retropilot/0/devices`, { withCredentials: true }); const req = await axios.get('http://localhost/retropilot/0/devices', { withCredentials: true });
const responseData = req.data const responseData = req.data;
let dongles = {} let dongles = {};
if (responseData.success === true) { if (responseData.success === true) {
responseData.data.map((object) => dongles = {
responseData.data.map((object) => {
return dongles = {
...dongles, ...dongles,
[object.dongle_id]: { [object.dongle_id]: {
...object, ...object,
online: false, online: false,
// Show when last connected to api instead Athena by default // Show when last connected to api instead Athena by default
last_seen: object.last_ping, last_seen: object.last_ping,
} },
} });
})
return dongles; return dongles;
} }
return null; return null;

View File

@ -1,24 +1,20 @@
export function formatDate(timestampMs) { export function formatDate(timestampMs) {
return new Date(timestampMs).toISOString().replace(/T/, ' ').replace(/\..+/, ''); return new Date(timestampMs).toISOString().replace(/T/, ' ').replace(/\..+/, '');
} }
export function formatDuration(durationSeconds) { export function formatDuration(durationSeconds) {
durationSeconds = Math.round(durationSeconds); durationSeconds = Math.round(durationSeconds);
const secs = durationSeconds % 60; const secs = durationSeconds % 60;
let mins = Math.floor(durationSeconds / 60); let mins = Math.floor(durationSeconds / 60);
let hours = Math.floor(mins / 60); let hours = Math.floor(mins / 60);
mins = mins % 60; mins %= 60;
const days = Math.floor(hours / 24); const days = Math.floor(hours / 24);
hours = hours % 24; hours %= 24;
let response = ''; let response = '';
if (days > 0) response += days + 'd '; if (days > 0) response += `${days}d `;
if (hours > 0 || days > 0) response += hours + 'h '; if (hours > 0 || days > 0) response += `${hours}h `;
if (hours > 0 || days > 0 || mins > 0) response += mins + 'm '; if (hours > 0 || days > 0 || mins > 0) response += `${mins}m `;
response += secs + 's'; response += `${secs}s`;
return response; return response;
} }

View File

@ -8,7 +8,7 @@ ReactDOM.render(
<React.StrictMode> <React.StrictMode>
<App /> <App />
</React.StrictMode>, </React.StrictMode>,
document.getElementById('root') document.getElementById('root'),
); );
// If you want to start measuring performance in your app, pass a function // If you want to start measuring performance in your app, pass a function

View File

@ -1,6 +1,8 @@
const reportWebVitals = onPerfEntry => { const reportWebVitals = (onPerfEntry) => {
if (onPerfEntry && onPerfEntry instanceof Function) { 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); getCLS(onPerfEntry);
getFID(onPerfEntry); getFID(onPerfEntry);
getFCP(onPerfEntry); getFCP(onPerfEntry);

View File

@ -1,4 +1,4 @@
import React, {useState, useContext} from 'react'; import React, { useState, useContext } from 'react';
import Avatar from '@mui/material/Avatar'; import Avatar from '@mui/material/Avatar';
import LoadingButton from '@mui/lab/LoadingButton'; import LoadingButton from '@mui/lab/LoadingButton';
import CssBaseline from '@mui/material/CssBaseline'; import CssBaseline from '@mui/material/CssBaseline';
@ -14,20 +14,21 @@ import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
import Container from '@mui/material/Container'; import Container from '@mui/material/Container';
import { createTheme, ThemeProvider } from '@mui/material/styles'; import { createTheme, ThemeProvider } from '@mui/material/styles';
import { UserContext } from "./context/users" import { UserContext } from './context/users';
const theme = createTheme(); const theme = createTheme();
export default function SignIn() { export default function SignIn() {
const [ state, dispatch ] = useContext(UserContext) const [state, dispatch] = useContext(UserContext);
return ( return (
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
{console.log("testing", state)} {console.log('testing', state)}
<p> {JSON.stringify(state)}</p> <p>
{' '}
{JSON.stringify(state)}
</p>
</ThemeProvider> </ThemeProvider>
); );
} }