diff --git a/.env-op b/.env-op
new file mode 100644
index 0000000..2a180dc
--- /dev/null
+++ b/.env-op
@@ -0,0 +1,3 @@
+REACT_APP_AUTH0_DOMAIN="op://Kingsrook/Auth0 Developer Keys/domain"
+REACT_APP_AUTH0_CLIENT_ID="op://Kingsrook/Auth0 Developer Keys/clientId"
+MATERIAL_UI_LICENSE_KEY="op://Kingsrook/Material UI Licence/key"
diff --git a/.eslintrc.json b/.eslintrc.json
index 86d3b2b..1d1d0b2 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -56,12 +56,14 @@
"devDependencies": true
}
],
+ "import/order": "off",
"max-len": "off",
"no-console": "off",
"no-constant-condition": "off",
"no-shadow": "off",
"no-unused-vars": "off",
"no-plusplus": "off",
+ "no-underscore-dangle": "off",
"spaced-comment": "off",
"object-curly-spacing": [
"error",
diff --git a/package-lock.json b/package-lock.json
index 11ad173..7b5dae0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,6 +9,7 @@
"version": "1.0.0",
"dependencies": {
"@asseinfo/react-kanban": "2.2.0",
+ "@auth0/auth0-react": "1.10.2",
"@emotion/cache": "11.7.1",
"@emotion/react": "11.7.1",
"@emotion/styled": "11.6.0",
@@ -20,6 +21,7 @@
"@mui/icons-material": "5.4.1",
"@mui/material": "5.4.1",
"@mui/styled-engine": "5.4.1",
+ "@mui/x-data-grid": "5.13.0",
"@mui/x-data-grid-pro": "5.13.0",
"@mui/x-license-pro": "5.12.3",
"@react-jvectormap/core": "1.0.1",
@@ -39,6 +41,7 @@
"html-react-parser": "1.4.8",
"react": "17.0.2",
"react-chartjs-2": "3.0.4",
+ "react-cookie": "4.1.1",
"react-dom": "17.0.2",
"react-flatpickr": "3.10.7",
"react-github-btn": "1.2.1",
@@ -120,6 +123,32 @@
"react-dom": "^16.8.0 || ^17.0.0"
}
},
+ "node_modules/@auth0/auth0-react": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/@auth0/auth0-react/-/auth0-react-1.10.2.tgz",
+ "integrity": "sha512-s622ac/gLZ9pUX7d5dOhRggF4VI3MaLLCPVBFR5CKOGcPtPG80/4w2jMoBQtRRn6uKS6IVMWAUAFKWB7yATAoQ==",
+ "dependencies": {
+ "@auth0/auth0-spa-js": "^1.22.0"
+ },
+ "peerDependencies": {
+ "react": "^16.11.0 || ^17 || ^18",
+ "react-dom": "^16.11.0 || ^17 || ^18"
+ }
+ },
+ "node_modules/@auth0/auth0-spa-js": {
+ "version": "1.22.1",
+ "resolved": "https://registry.npmjs.org/@auth0/auth0-spa-js/-/auth0-spa-js-1.22.1.tgz",
+ "integrity": "sha512-l0FCmiN3XubpgCtB3U0ds4h+5WQNTnIF4eLT/fudHEtcyrT65QF/03LybGVdLyuvqdIF/D6OQsfjwYw0Ms605Q==",
+ "dependencies": {
+ "abortcontroller-polyfill": "^1.7.3",
+ "browser-tabs-lock": "^1.2.15",
+ "core-js": "^3.22.6",
+ "es-cookie": "^1.3.2",
+ "fast-text-encoding": "^1.0.3",
+ "promise-polyfill": "^8.2.3",
+ "unfetch": "^4.2.0"
+ }
+ },
"node_modules/@babel/code-frame": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
@@ -4131,6 +4160,11 @@
"@types/node": "*"
}
},
+ "node_modules/@types/cookie": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz",
+ "integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow=="
+ },
"node_modules/@types/dropzone": {
"version": "5.7.4",
"resolved": "https://registry.npmjs.org/@types/dropzone/-/dropzone-5.7.4.tgz",
@@ -4912,6 +4946,11 @@
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA=="
},
+ "node_modules/abortcontroller-polyfill": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.3.tgz",
+ "integrity": "sha512-zetDJxd89y3X99Kvo4qFx8GKlt6GsvN3UcRZHwU6iFA/0KiOmhkTVhe8oRoTBiTVPZu09x3vCra47+w8Yz1+2Q=="
+ },
"node_modules/accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@@ -5782,6 +5821,15 @@
"resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz",
"integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow=="
},
+ "node_modules/browser-tabs-lock": {
+ "version": "1.2.15",
+ "resolved": "https://registry.npmjs.org/browser-tabs-lock/-/browser-tabs-lock-1.2.15.tgz",
+ "integrity": "sha512-J8K9vdivK0Di+b8SBdE7EZxDr88TnATing7XoLw6+nFkXMQ6sVBh92K3NQvZlZU91AIkFRi0w3sztk5Z+vsswA==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "lodash": ">=4.17.21"
+ }
+ },
"node_modules/browserslist": {
"version": "4.21.1",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.1.tgz",
@@ -7399,6 +7447,11 @@
"resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz",
"integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA=="
},
+ "node_modules/es-cookie": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/es-cookie/-/es-cookie-1.3.2.tgz",
+ "integrity": "sha512-UTlYYhXGLOy05P/vKVT2Ui7WtC7NiRzGtJyAKKn32g5Gvcjn7KAClLPWlipCtxIus934dFg9o9jXiBL0nP+t9Q=="
+ },
"node_modules/es-module-lexer": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz",
@@ -8475,6 +8528,11 @@
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
},
+ "node_modules/fast-text-encoding": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.4.tgz",
+ "integrity": "sha512-x6lDDm/tBAzX9kmsPcZsNbvDs3Zey3+scsxaZElS8xWLgUMAg/oFLeewfUz0mu1CblHhhsu15jGkraldkFh8KQ=="
+ },
"node_modules/fastq": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
@@ -13638,6 +13696,11 @@
"asap": "~2.0.6"
}
},
+ "node_modules/promise-polyfill": {
+ "version": "8.2.3",
+ "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.3.tgz",
+ "integrity": "sha512-Og0+jCRQetV84U8wVjMNccfGCnMQ9mGs9Hv78QFe+pSDD3gWTpz0y+1QCuxy5d/vBFuZ3iwP2eycAkvqIMPmWg=="
+ },
"node_modules/prompts": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
@@ -13902,6 +13965,19 @@
"react": "^16.8.0 || ^17.0.0"
}
},
+ "node_modules/react-cookie": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/react-cookie/-/react-cookie-4.1.1.tgz",
+ "integrity": "sha512-ffn7Y7G4bXiFbnE+dKhHhbP+b8I34mH9jqnm8Llhj89zF4nPxPutxHT1suUqMeCEhLDBI7InYwf1tpaSoK5w8A==",
+ "dependencies": {
+ "@types/hoist-non-react-statics": "^3.0.1",
+ "hoist-non-react-statics": "^3.0.0",
+ "universal-cookie": "^4.0.0"
+ },
+ "peerDependencies": {
+ "react": ">= 16.3.0"
+ }
+ },
"node_modules/react-dev-utils": {
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
@@ -16105,6 +16181,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/unfetch": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz",
+ "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA=="
+ },
"node_modules/unicode-canonical-property-names-ecmascript": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
@@ -16152,6 +16233,23 @@
"node": ">=8"
}
},
+ "node_modules/universal-cookie": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.4.tgz",
+ "integrity": "sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw==",
+ "dependencies": {
+ "@types/cookie": "^0.3.3",
+ "cookie": "^0.4.0"
+ }
+ },
+ "node_modules/universal-cookie/node_modules/cookie": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
+ "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
"node_modules/universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
@@ -17196,6 +17294,28 @@
"react-beautiful-dnd": "^13.0.0"
}
},
+ "@auth0/auth0-react": {
+ "version": "1.10.2",
+ "resolved": "https://registry.npmjs.org/@auth0/auth0-react/-/auth0-react-1.10.2.tgz",
+ "integrity": "sha512-s622ac/gLZ9pUX7d5dOhRggF4VI3MaLLCPVBFR5CKOGcPtPG80/4w2jMoBQtRRn6uKS6IVMWAUAFKWB7yATAoQ==",
+ "requires": {
+ "@auth0/auth0-spa-js": "^1.22.0"
+ }
+ },
+ "@auth0/auth0-spa-js": {
+ "version": "1.22.1",
+ "resolved": "https://registry.npmjs.org/@auth0/auth0-spa-js/-/auth0-spa-js-1.22.1.tgz",
+ "integrity": "sha512-l0FCmiN3XubpgCtB3U0ds4h+5WQNTnIF4eLT/fudHEtcyrT65QF/03LybGVdLyuvqdIF/D6OQsfjwYw0Ms605Q==",
+ "requires": {
+ "abortcontroller-polyfill": "^1.7.3",
+ "browser-tabs-lock": "^1.2.15",
+ "core-js": "^3.22.6",
+ "es-cookie": "^1.3.2",
+ "fast-text-encoding": "^1.0.3",
+ "promise-polyfill": "^8.2.3",
+ "unfetch": "^4.2.0"
+ }
+ },
"@babel/code-frame": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
@@ -19879,6 +19999,11 @@
"@types/node": "*"
}
},
+ "@types/cookie": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.3.3.tgz",
+ "integrity": "sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow=="
+ },
"@types/dropzone": {
"version": "5.7.4",
"resolved": "https://registry.npmjs.org/@types/dropzone/-/dropzone-5.7.4.tgz",
@@ -20520,6 +20645,11 @@
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA=="
},
+ "abortcontroller-polyfill": {
+ "version": "1.7.3",
+ "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.3.tgz",
+ "integrity": "sha512-zetDJxd89y3X99Kvo4qFx8GKlt6GsvN3UcRZHwU6iFA/0KiOmhkTVhe8oRoTBiTVPZu09x3vCra47+w8Yz1+2Q=="
+ },
"accepts": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@@ -21173,6 +21303,14 @@
"resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz",
"integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow=="
},
+ "browser-tabs-lock": {
+ "version": "1.2.15",
+ "resolved": "https://registry.npmjs.org/browser-tabs-lock/-/browser-tabs-lock-1.2.15.tgz",
+ "integrity": "sha512-J8K9vdivK0Di+b8SBdE7EZxDr88TnATing7XoLw6+nFkXMQ6sVBh92K3NQvZlZU91AIkFRi0w3sztk5Z+vsswA==",
+ "requires": {
+ "lodash": ">=4.17.21"
+ }
+ },
"browserslist": {
"version": "4.21.1",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.1.tgz",
@@ -22352,6 +22490,11 @@
"resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz",
"integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA=="
},
+ "es-cookie": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/es-cookie/-/es-cookie-1.3.2.tgz",
+ "integrity": "sha512-UTlYYhXGLOy05P/vKVT2Ui7WtC7NiRzGtJyAKKn32g5Gvcjn7KAClLPWlipCtxIus934dFg9o9jXiBL0nP+t9Q=="
+ },
"es-module-lexer": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz",
@@ -23127,6 +23270,11 @@
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
},
+ "fast-text-encoding": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.4.tgz",
+ "integrity": "sha512-x6lDDm/tBAzX9kmsPcZsNbvDs3Zey3+scsxaZElS8xWLgUMAg/oFLeewfUz0mu1CblHhhsu15jGkraldkFh8KQ=="
+ },
"fastq": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
@@ -26691,6 +26839,11 @@
"asap": "~2.0.6"
}
},
+ "promise-polyfill": {
+ "version": "8.2.3",
+ "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.3.tgz",
+ "integrity": "sha512-Og0+jCRQetV84U8wVjMNccfGCnMQ9mGs9Hv78QFe+pSDD3gWTpz0y+1QCuxy5d/vBFuZ3iwP2eycAkvqIMPmWg=="
+ },
"prompts": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
@@ -26890,6 +27043,16 @@
"lodash": "^4.17.19"
}
},
+ "react-cookie": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/react-cookie/-/react-cookie-4.1.1.tgz",
+ "integrity": "sha512-ffn7Y7G4bXiFbnE+dKhHhbP+b8I34mH9jqnm8Llhj89zF4nPxPutxHT1suUqMeCEhLDBI7InYwf1tpaSoK5w8A==",
+ "requires": {
+ "@types/hoist-non-react-statics": "^3.0.1",
+ "hoist-non-react-statics": "^3.0.0",
+ "universal-cookie": "^4.0.0"
+ }
+ },
"react-dev-utils": {
"version": "12.0.1",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz",
@@ -28541,6 +28704,11 @@
"which-boxed-primitive": "^1.0.2"
}
},
+ "unfetch": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz",
+ "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA=="
+ },
"unicode-canonical-property-names-ecmascript": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
@@ -28573,6 +28741,22 @@
"crypto-random-string": "^2.0.0"
}
},
+ "universal-cookie": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/universal-cookie/-/universal-cookie-4.0.4.tgz",
+ "integrity": "sha512-lbRVHoOMtItjWbM7TwDLdl8wug7izB0tq3/YVKhT/ahB4VDvWMyvnADfnJI8y6fSvsjh51Ix7lTGC6Tn4rMPhw==",
+ "requires": {
+ "@types/cookie": "^0.3.3",
+ "cookie": "^0.4.0"
+ },
+ "dependencies": {
+ "cookie": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
+ "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA=="
+ }
+ }
+ },
"universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
diff --git a/package.json b/package.json
index 660b569..33467e2 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
"@mui/icons-material": "5.4.1",
"@mui/material": "5.4.1",
"@mui/styled-engine": "5.4.1",
+ "@mui/x-data-grid": "5.13.0",
"@mui/x-data-grid-pro": "5.13.0",
"@mui/x-license-pro": "5.12.3",
"@react-jvectormap/core": "1.0.1",
@@ -36,6 +37,7 @@
"html-react-parser": "1.4.8",
"react": "17.0.2",
"react-chartjs-2": "3.0.4",
+ "react-cookie": "4.1.1",
"react-dom": "17.0.2",
"react-flatpickr": "3.10.7",
"react-github-btn": "1.2.1",
diff --git a/public/apple-icon.png b/public/apple-icon.png
index a20470f..59c68b9 100644
Binary files a/public/apple-icon.png and b/public/apple-icon.png differ
diff --git a/public/favicon.png b/public/favicon.png
index 7d8b7d0..59c68b9 100644
Binary files a/public/favicon.png and b/public/favicon.png differ
diff --git a/scripts/nodeWrapper.sh b/scripts/nodeWrapper.sh
new file mode 100755
index 0000000..fab759d
--- /dev/null
+++ b/scripts/nodeWrapper.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+op run --env-file='.env-op' -- npm "$@"
diff --git a/src/App.tsx b/src/App.tsx
index 7014811..c518743 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -11,6 +11,8 @@ import {
Routes, Route, Navigate, useLocation,
} from "react-router-dom";
+import {useAuth0} from "@auth0/auth0-react";
+
// @mui material components
import {LicenseInfo} from "@mui/x-license-pro";
import {ThemeProvider} from "@mui/material/styles";
@@ -35,9 +37,10 @@ import {useMaterialUIController, setMiniSidenav, setOpenConfigurator} from "cont
// Images
import nfLogo from "assets/images/nutrifresh_one_icon_white.png";
-import brandWhite from "assets/images/logo-ct.png";
-import brandDark from "assets/images/logo-ct-dark.png";
import {Md5} from "ts-md5/dist/md5";
+import AuthenticationButton from "qqq/components/buttons/AuthenticationButton";
+import {useCookies} from "react-cookie";
+import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance";
import EntityCreate from "./qqq/pages/entity-create";
import EntityList from "./qqq/pages/entity-list";
import EntityView from "./qqq/pages/entity-view";
@@ -51,42 +54,12 @@ import Analytics from "./layouts/dashboards/analytics";
import Sales from "./layouts/dashboards/sales";
import QClient from "./qqq/utils/QClient";
-const gravatarBase = "http://www.gravatar.com/avatar/";
-const hash = Md5.hashStr("tim@nutrifreshservices.com");
-const profilePicture = `${gravatarBase}${hash}`;
-
///////////////////////////////////////////////////////////////////////////////////////////////
// define the parts of the nav that are static - before the qqq tables etc get dynamic added //
///////////////////////////////////////////////////////////////////////////////////////////////
function getStaticRoutes()
{
return [
- {
- type: "collapse",
- name: "Tim Chamberlain",
- key: "tim-chamberlain",
- icon: ,
- collapse: [
- {
- name: "My Profile",
- key: "my-profile",
- route: "/pages/profile/profile-overview",
- component: ,
- },
- {
- name: "Settings",
- key: "profile-settings",
- route: "/pages/account/settings",
- component: ,
- },
- {
- name: "Logout",
- key: "logout",
- route: "/authentication/sign-in/basic",
- component: ,
- },
- ],
- },
{type: "divider", key: "divider-0"},
{
type: "collapse",
@@ -113,10 +86,44 @@ function getStaticRoutes()
];
}
-LicenseInfo.setLicenseKey("4ef48a0226ec7b5fb49d99f14c6b3170Tz00NzI0NyxFPTE2ODkyODU1NzUxMDYsUz1wcm8sTE09c3Vic2NyaXB0aW9uLEtWPTI=");
+const SESSION_ID_COOKIE_NAME = "sessionId";
+LicenseInfo.setLicenseKey(process.env.MATERIAL_UI_LICENSE_KEY);
export default function App()
{
+ const [, setCookie] = useCookies([SESSION_ID_COOKIE_NAME]);
+ const {
+ user, getAccessTokenSilently, getIdTokenClaims, logout,
+ } = useAuth0();
+ const [loadingToken, setLoadingToken] = useState(false);
+ const [isFullyAuthenticated, setIsFullyAuthenticated] = useState(false);
+
+ useEffect(() =>
+ {
+ if (loadingToken)
+ {
+ return;
+ }
+ setLoadingToken(true);
+ (async () =>
+ {
+ try
+ {
+ console.log("Loading token...");
+ const accessToken = await getAccessTokenSilently();
+ const idToken = await getIdTokenClaims();
+ setCookie(SESSION_ID_COOKIE_NAME, idToken.__raw, {path: "/"});
+ setIsFullyAuthenticated(true);
+ console.log("Token load complete.");
+ }
+ catch (e)
+ {
+ console.log(`Error loading token: ${JSON.stringify(e)}`);
+ logout();
+ }
+ })();
+ }, [loadingToken]);
+
const [controller, dispatch] = useMaterialUIController();
const {
miniSidenav,
@@ -139,7 +146,7 @@ export default function App()
////////////////////////////////////////////
useEffect(() =>
{
- if (!needToLoadRoutes)
+ if (!needToLoadRoutes || !isFullyAuthenticated)
{
return;
}
@@ -147,43 +154,87 @@ export default function App()
(async () =>
{
- const metaData = await QClient.loadMetaData();
+ try
+ {
+ console.log("ok now loading qqq things");
+ const metaData = await QClient.loadMetaData();
- // get the keys sorted
- const keys = [...metaData.tables.keys()].sort((a, b): number =>
- {
- const labelA = metaData.tables.get(a).label;
- const labelB = metaData.tables.get(b).label;
- return (labelA.localeCompare(labelB));
- });
- const tableList = [] as any[];
- keys.forEach((key) =>
- {
- const table = metaData.tables.get(key);
- if (!table.isHidden)
+ // get the keys sorted
+ const keys = [...metaData.tables.keys()].sort((a, b): number =>
{
- tableList.push({
- name: `${table.label}`,
- key: table.name,
- route: `/${table.name}`,
- component: ,
- });
+ const labelA = metaData.tables.get(a).label;
+ const labelB = metaData.tables.get(b).label;
+ return (labelA.localeCompare(labelB));
+ });
+ const tableList = [] as any[];
+ keys.forEach((key) =>
+ {
+ const table = metaData.tables.get(key);
+ if (!table.isHidden)
+ {
+ tableList.push({
+ name: `${table.label}`,
+ key: table.name,
+ route: `/${table.name}`,
+ component: ,
+ });
+ }
+ });
+
+ let profileRoute = {};
+ const gravatarBase = "http://www.gravatar.com/avatar/";
+ const hash = Md5.hashStr(user.email);
+ const profilePicture = `${gravatarBase}${hash}`;
+ profileRoute = {
+ type: "collapse",
+ name: user.name,
+ key: user.name,
+ icon: ,
+ collapse: [
+ {
+ name: "My Profile",
+ key: "my-profile",
+ route: "/pages/profile/profile-overview",
+ component: ,
+ },
+ {
+ name: "Settings",
+ key: "profile-settings",
+ route: "/pages/account/settings",
+ component: ,
+ },
+ {
+ name: "Logout",
+ key: "logout",
+ route: "/authentication/sign-in/basic",
+ component: ,
+ },
+ ],
+ };
+
+ const tables = {
+ type: "collapse",
+ name: "Tables",
+ key: "tables",
+ icon: dashboard,
+ collapse: tableList,
+ };
+
+ const newDynamicRoutes = getStaticRoutes();
+ // @ts-ignore
+ newDynamicRoutes.unshift(profileRoute);
+ newDynamicRoutes.push(tables);
+ setRoutes(newDynamicRoutes);
+ }
+ catch (e)
+ {
+ if (e.toString().indexOf("status code 401") !== -1)
+ {
+ logout();
}
- });
-
- const tables = {
- type: "collapse",
- name: "Tables",
- key: "tables",
- icon: dashboard,
- collapse: tableList,
- };
-
- const newDynamicRoutes = getStaticRoutes();
- newDynamicRoutes.push(tables);
- setRoutes(newDynamicRoutes);
+ }
})();
- }, [needToLoadRoutes]);
+ }, [needToLoadRoutes, isFullyAuthenticated]);
// Open sidenav when mouse enter on mini sidenav
const handleOnMouseEnter = () =>
@@ -243,6 +294,27 @@ export default function App()
},
);
+ const authButton = (
+
+
+
+ );
+
const configsButton = (
{configsButton}
+ {authButton}
>
)}
- {layout === "vr" && }
} />
diff --git a/src/index.tsx b/src/index.tsx
index 3a535ca..bc76917 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,33 +1,30 @@
-/**
-=========================================================
-* Material Dashboard 2 PRO React TS - v1.0.0
-=========================================================
-
-* Product Page: https://www.creative-tim.com/product/material-dashboard-2-pro-react-ts
-* Copyright 2022 Creative Tim (https://www.creative-tim.com)
-
-Coded by www.creative-tim.com
-
- =========================================================
-
-* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-*/
-
import ReactDOM from "react-dom";
import {BrowserRouter} from "react-router-dom";
+import {Auth0Provider} from "@auth0/auth0-react";
import App from "App";
// Material Dashboard 2 PRO React TS Context Provider
import {MaterialUIControllerProvider} from "context";
import "./qqq/styles/qqq-override-styles.css";
+import ProtectedRoute from "qqq/auth0/protected-route";
+import React from "react";
+
+// Auth0 params from env
+const domain = process.env.REACT_APP_AUTH0_DOMAIN;
+const clientId = process.env.REACT_APP_AUTH0_CLIENT_ID;
ReactDOM.render(
-
-
-
-
- ,
+
+
+
+
+
+
+ ,
document.getElementById("root"),
);
-
export * from "components/MDButton";
diff --git a/src/page.routes.tsx b/src/page.routes.tsx
index 3974ada..01cefc6 100644
--- a/src/page.routes.tsx
+++ b/src/page.routes.tsx
@@ -1,39 +1,39 @@
/**
-=========================================================
-* Material Dashboard 2 PRO React TS - v1.0.0
-=========================================================
+ =========================================================
+ * Material Dashboard 2 PRO React TS - v1.0.0
+ =========================================================
-* Product Page: https://www.creative-tim.com/product/material-dashboard-2-pro-react-ts
-* Copyright 2022 Creative Tim (https://www.creative-tim.com)
+ * Product Page: https://www.creative-tim.com/product/material-dashboard-2-pro-react-ts
+ * Copyright 2022 Creative Tim (https://www.creative-tim.com)
-Coded by www.creative-tim.com
+ Coded by www.creative-tim.com
=========================================================
-* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-*/
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+ */
/**
- All of the routes for the Material Kit 2 PRO React React are added here,
- You can add a new route, customize the routes and delete the routes here.
+ All of the routes for the Material Kit 2 PRO React React are added here,
+ You can add a new route, customize the routes and delete the routes here.
- Once you add a new route on this file it will be visible automatically on
- the Navbar.
+ Once you add a new route on this file it will be visible automatically on
+ the Navbar.
- For adding a new route you can follow the existing routes in the routes array.
- 1. The `name` key is used for the name of the route on the Navbar.
- 2. The `icon` key is used for the icon of the route on the Navbar.
- 3. The `collapse` key is used for making a collapsible item on the Navbar that contains other routes
- inside (nested routes), you need to pass the nested routes inside an array as a value for the `collapse` key.
- 4. The `route` key is used to store the route location which is used for the react router.
- 5. The `href` key is used to store the external links location.
- 7. The `dropdown` key is used to define that the item should open a dropdown for its collapse items .
- 8. The `description` key is used to define the description of
- a route under its name.
- 9. The `columns` key is used to define that how the content should look inside the dropdown menu as columns,
- you can set the columns amount based on this key.
- 10. The `rowsPerColumn` key is used to define that how many rows should be in a column.
-*/
+ For adding a new route you can follow the existing routes in the routes array.
+ 1. The `name` key is used for the name of the route on the Navbar.
+ 2. The `icon` key is used for the icon of the route on the Navbar.
+ 3. The `collapse` key is used for making a collapsible item on the Navbar that contains other routes
+ inside (nested routes), you need to pass the nested routes inside an array as a value for the `collapse` key.
+ 4. The `route` key is used to store the route location which is used for the react router.
+ 5. The `href` key is used to store the external links location.
+ 7. The `dropdown` key is used to define that the item should open a dropdown for its collapse items .
+ 8. The `description` key is used to define the description of
+ a route under its name.
+ 9. The `columns` key is used to define that how the content should look inside the dropdown menu as columns,
+ you can set the columns amount based on this key.
+ 10. The `rowsPerColumn` key is used to define that how many rows should be in a column.
+ */
// @mui material components
import Icon from "@mui/material/Icon";
@@ -76,9 +76,9 @@ const pageRoutes = [
name: "pricing page",
route: "/pages/pricing-page",
},
- { name: "RTL", route: "/pages/rtl" },
- { name: "widgets", route: "/pages/widgets" },
- { name: "charts", route: "/pages/charts" },
+ {name: "RTL", route: "/pages/rtl"},
+ {name: "widgets", route: "/pages/widgets"},
+ {name: "charts", route: "/pages/charts"},
{
name: "notfications",
route: "/pages/notifications",
diff --git a/src/qqq/auth0/code-snippet.tsx b/src/qqq/auth0/code-snippet.tsx
new file mode 100644
index 0000000..e2d55e1
--- /dev/null
+++ b/src/qqq/auth0/code-snippet.tsx
@@ -0,0 +1,28 @@
+import React from "react";
+
+interface CodeSnippetProps
+{
+ code: string;
+ title?: string;
+}
+
+// eslint-disable-next-line react/function-component-definition
+function CodeSnippet({title, code}: CodeSnippetProps): JSX.Element
+{
+ return (
+
+ );
+}
+
+CodeSnippet.defaultProps = {
+ title: undefined,
+};
+
+export default CodeSnippet;
diff --git a/src/qqq/auth0/loader.tsx b/src/qqq/auth0/loader.tsx
new file mode 100644
index 0000000..b38d26e
--- /dev/null
+++ b/src/qqq/auth0/loader.tsx
@@ -0,0 +1,14 @@
+import React from "react";
+
+function Loader() : JSX.Element
+{
+ const loadingImg = "https://cdn.auth0.com/blog/hello-auth0/loader.svg";
+
+ return (
+
+

+
+ );
+}
+
+export default Loader;
diff --git a/src/qqq/auth0/profile.tsx b/src/qqq/auth0/profile.tsx
new file mode 100644
index 0000000..7d51b7a
--- /dev/null
+++ b/src/qqq/auth0/profile.tsx
@@ -0,0 +1,31 @@
+import {useAuth0} from "@auth0/auth0-react";
+import React from "react";
+import CodeSnippet from "./code-snippet";
+
+export function Profile()
+{
+ const {user} = useAuth0();
+
+ if (!user)
+ {
+ console.log("no user");
+ return null;
+ }
+
+ return (
+
+ );
+}
+
+export default Profile;
diff --git a/src/qqq/auth0/protected-route.tsx b/src/qqq/auth0/protected-route.tsx
new file mode 100644
index 0000000..2e66154
--- /dev/null
+++ b/src/qqq/auth0/protected-route.tsx
@@ -0,0 +1,16 @@
+import {withAuthenticationRequired} from "@auth0/auth0-react";
+import React from "react";
+import Loader from "./loader";
+
+// @ts-ignore
+function ProtectedRoute({component}) : JSX.Element
+{
+ const Component = withAuthenticationRequired(component, {
+ // eslint-disable-next-line react/no-unstable-nested-components
+ onRedirecting: () => ,
+ });
+
+ return ;
+}
+
+export default ProtectedRoute;
diff --git a/src/qqq/components/BaseLayout/index.tsx b/src/qqq/components/BaseLayout/index.tsx
index f8c8416..b0c4572 100644
--- a/src/qqq/components/BaseLayout/index.tsx
+++ b/src/qqq/components/BaseLayout/index.tsx
@@ -59,7 +59,7 @@ function BaseLayout({stickyNavbar, children}: Props): JSX.Element
return (
-
+
{children}
diff --git a/src/qqq/pages/entity-list/index.tsx b/src/qqq/pages/entity-list/index.tsx
index 876fb81..2626b41 100644
--- a/src/qqq/pages/entity-list/index.tsx
+++ b/src/qqq/pages/entity-list/index.tsx
@@ -14,6 +14,8 @@
import React, {useEffect, useReducer, useState} from "react";
import {useParams, useSearchParams} from "react-router-dom";
+import {useAuth0} from "@auth0/auth0-react";
+
// @mui material components
import Card from "@mui/material/Card";
import Icon from "@mui/material/Icon";
@@ -57,6 +59,7 @@ import {QFilterCriteria} from "@kingsrook/qqq-frontend-core/lib/model/query/QFil
import {QCriteriaOperator} from "@kingsrook/qqq-frontend-core/lib/model/query/QCriteriaOperator";
import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType";
import QClient from "qqq/utils/QClient";
+import Navbar from "qqq/components/Navbar";
import Footer from "../../components/Footer";
import QProcessUtils from "../../utils/QProcessUtils";
@@ -461,7 +464,7 @@ function EntityList({table}: Props): JSX.Element
return (
-
+
{alertContent ? (
diff --git a/src/qqq/pages/process-run/index.tsx b/src/qqq/pages/process-run/index.tsx
index 1e7f4c4..a024d50 100644
--- a/src/qqq/pages/process-run/index.tsx
+++ b/src/qqq/pages/process-run/index.tsx
@@ -46,8 +46,8 @@ import {QJobComplete} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJo
import {QJobError} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobError";
import {QJobRunning} from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobRunning";
import {
- DataGrid, GridColDef, GridRowParams, GridRowsProp,
-} from "@mui/x-data-grid";
+ DataGridPro, GridColDef, GridRowParams, GridRowsProp,
+} from "@mui/x-data-grid-pro";
import QDynamicForm from "../../components/QDynamicForm";
import MDTypography from "../../../components/MDTypography";
@@ -108,7 +108,7 @@ function getDynamicStepContent(
{" "}
-