committing all group related code
This commit is contained in:
parent
0ec54b2d31
commit
2d98917322
14 changed files with 541 additions and 102 deletions
66
package-lock.json
generated
66
package-lock.json
generated
|
|
@ -23,7 +23,7 @@
|
|||
"moment-timezone": "^0.5.46",
|
||||
"mui-tel-input": "^7.0.0",
|
||||
"notistack": "^3.0.1",
|
||||
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#staging",
|
||||
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#dev",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-image": "^4.1.0",
|
||||
|
|
@ -1515,9 +1515,7 @@
|
|||
},
|
||||
"node_modules/@mui/x-date-pickers": {
|
||||
"version": "7.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-7.22.3.tgz",
|
||||
"integrity": "sha512-shNp92IrST5BiVy2f4jbrmRaD32QhyUthjh1Oexvpcn0v6INyuWgxfodoTi5ZCnE5Ue5UVFSs4R9Xre0UbJ5DQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.25.7",
|
||||
"@mui/utils": "^5.16.6 || ^6.0.0",
|
||||
|
|
@ -1583,7 +1581,6 @@
|
|||
"version": "7.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@mui/x-internals/-/x-internals-7.21.0.tgz",
|
||||
"integrity": "sha512-94YNyZ0BhK5Z+Tkr90RKf47IVCW8R/1MvdUhh6MCQg6sZa74jsX+x+gEZ4kzuCqOsuyTyxikeQ8vVuCIQiP7UQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.25.7",
|
||||
"@mui/utils": "^5.16.6 || ^6.0.0"
|
||||
|
|
@ -1646,32 +1643,27 @@
|
|||
"node_modules/@protobufjs/aspromise": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
|
||||
"integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
|
||||
"license": "BSD-3-Clause"
|
||||
"integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="
|
||||
},
|
||||
"node_modules/@protobufjs/base64": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
|
||||
"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
|
||||
"license": "BSD-3-Clause"
|
||||
"integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
|
||||
},
|
||||
"node_modules/@protobufjs/codegen": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
|
||||
"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
|
||||
"license": "BSD-3-Clause"
|
||||
"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
|
||||
},
|
||||
"node_modules/@protobufjs/eventemitter": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
|
||||
"integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
|
||||
"license": "BSD-3-Clause"
|
||||
"integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="
|
||||
},
|
||||
"node_modules/@protobufjs/fetch": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
|
||||
"integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@protobufjs/aspromise": "^1.1.1",
|
||||
"@protobufjs/inquire": "^1.1.0"
|
||||
|
|
@ -1680,32 +1672,27 @@
|
|||
"node_modules/@protobufjs/float": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
|
||||
"integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
|
||||
"license": "BSD-3-Clause"
|
||||
"integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="
|
||||
},
|
||||
"node_modules/@protobufjs/inquire": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
|
||||
"integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
|
||||
"license": "BSD-3-Clause"
|
||||
"integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="
|
||||
},
|
||||
"node_modules/@protobufjs/path": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
|
||||
"integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
|
||||
"license": "BSD-3-Clause"
|
||||
"integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="
|
||||
},
|
||||
"node_modules/@protobufjs/pool": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
|
||||
"integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
|
||||
"license": "BSD-3-Clause"
|
||||
"integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="
|
||||
},
|
||||
"node_modules/@protobufjs/utf8": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
|
||||
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
|
||||
"license": "BSD-3-Clause"
|
||||
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.21.0",
|
||||
|
|
@ -2136,14 +2123,12 @@
|
|||
"node_modules/@types/long": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz",
|
||||
"integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==",
|
||||
"license": "MIT"
|
||||
"integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA=="
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.1.tgz",
|
||||
"integrity": "sha512-p8Yy/8sw1caA8CdRIQBG5tiLHmxtQKObCijiAa9Ez+d4+PRffM4054xbju0msf+cvhJpnFEeNjxmVT/0ipktrg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.8"
|
||||
}
|
||||
|
|
@ -2180,7 +2165,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/react-infinite-scroller/-/react-infinite-scroller-1.2.5.tgz",
|
||||
"integrity": "sha512-fJU1jhMgoL6NJFrqTM0Ob7tnd2sQWGxe2ESwiU6FZWbJK/VO/Er5+AOhc+e2zbT0dk5pLygqctsulOLJ8xnSzw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
|
|
@ -3764,8 +3748,7 @@
|
|||
"node_modules/libphonenumber-js": {
|
||||
"version": "1.11.15",
|
||||
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.11.15.tgz",
|
||||
"integrity": "sha512-M7+rtYi9l5RvMmHyjyoF3BHHUpXTYdJ0PezZGHNs0GyW1lO+K7jxlXpbdIb7a56h0nqLYdjIw+E+z0ciGaJP7g==",
|
||||
"license": "MIT"
|
||||
"integrity": "sha512-M7+rtYi9l5RvMmHyjyoF3BHHUpXTYdJ0PezZGHNs0GyW1lO+K7jxlXpbdIb7a56h0nqLYdjIw+E+z0ciGaJP7g=="
|
||||
},
|
||||
"node_modules/lines-and-columns": {
|
||||
"version": "1.2.4",
|
||||
|
|
@ -3794,14 +3777,12 @@
|
|||
"node_modules/lodash.debounce": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
|
||||
"license": "MIT"
|
||||
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
|
||||
},
|
||||
"node_modules/lodash.memoize": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
|
||||
"integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
|
||||
"license": "MIT"
|
||||
"integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag=="
|
||||
},
|
||||
"node_modules/lodash.merge": {
|
||||
"version": "4.6.2",
|
||||
|
|
@ -3812,20 +3793,17 @@
|
|||
"node_modules/lodash.reduce": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz",
|
||||
"integrity": "sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw==",
|
||||
"license": "MIT"
|
||||
"integrity": "sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw=="
|
||||
},
|
||||
"node_modules/lodash.startswith": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/lodash.startswith/-/lodash.startswith-4.2.1.tgz",
|
||||
"integrity": "sha512-XClYR1h4/fJ7H+mmCKppbiBmljN/nGs73iq2SjCT9SF4CBPoUHzLvWmH1GtZMhMBZSiRkHXfeA2RY1eIlJ75ww==",
|
||||
"license": "MIT"
|
||||
"integrity": "sha512-XClYR1h4/fJ7H+mmCKppbiBmljN/nGs73iq2SjCT9SF4CBPoUHzLvWmH1GtZMhMBZSiRkHXfeA2RY1eIlJ75ww=="
|
||||
},
|
||||
"node_modules/long": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
|
||||
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==",
|
||||
"license": "Apache-2.0"
|
||||
"integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
|
|
@ -3941,9 +3919,7 @@
|
|||
},
|
||||
"node_modules/mui-tel-input": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mui-tel-input/-/mui-tel-input-7.0.0.tgz",
|
||||
"integrity": "sha512-kLxFmuoSwX5qG3PRO2BQ2hNquy8JfQBOofBhtoQsiRwPsAtwW77OIzQPmXPnftRjuc7uYJt6PW7oVeqx7wkK3g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "^22.9.0",
|
||||
"libphonenumber-js": "^1.11.14"
|
||||
|
|
@ -4220,7 +4196,7 @@
|
|||
},
|
||||
"node_modules/protobuf-ts": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#7fa04da5ae9ec99cf1caa6971ca1541fe44f10c4",
|
||||
"resolved": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#e3d1689e1bf3842b0601cf166be9aff78ef093ff",
|
||||
"dependencies": {
|
||||
"protobufjs": "^6.8.8"
|
||||
}
|
||||
|
|
@ -4230,7 +4206,6 @@
|
|||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz",
|
||||
"integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"@protobufjs/aspromise": "^1.1.2",
|
||||
"@protobufjs/base64": "^1.1.2",
|
||||
|
|
@ -4332,9 +4307,7 @@
|
|||
},
|
||||
"node_modules/react-phone-input-2": {
|
||||
"version": "2.15.1",
|
||||
"resolved": "https://registry.npmjs.org/react-phone-input-2/-/react-phone-input-2-2.15.1.tgz",
|
||||
"integrity": "sha512-W03abwhXcwUoq+vUFvC6ch2+LJYMN8qSOiO889UH6S7SyMCQvox/LF3QWt+cZagZrRdi5z2ON3omnjoCUmlaYw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"classnames": "^2.2.6",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
|
|
@ -4763,8 +4736,7 @@
|
|||
"node_modules/undici-types": {
|
||||
"version": "6.19.8",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
|
||||
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
|
||||
"license": "MIT"
|
||||
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
|
||||
},
|
||||
"node_modules/update-browserslist-db": {
|
||||
"version": "1.1.1",
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
"moment-timezone": "^0.5.46",
|
||||
"mui-tel-input": "^7.0.0",
|
||||
"notistack": "^3.0.1",
|
||||
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#staging",
|
||||
"protobuf-ts": "git+https://gitlab+deploy-token-50627:hv8mB4WkyvtjBpJKU1rN@gitlab.com/brandx/protobuf-ts.git#dev",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-image": "^4.1.0",
|
||||
|
|
|
|||
|
|
@ -20,12 +20,21 @@ const useStyles = makeStyles((theme: Theme) => {
|
|||
// width: "auto"
|
||||
},
|
||||
title: {
|
||||
padding: theme.spacing(1)
|
||||
padding: theme.spacing(1),
|
||||
},
|
||||
subtitle: {
|
||||
padding: theme.spacing(1),
|
||||
marginTop: theme.spacing(-2),
|
||||
},
|
||||
titleComp: {
|
||||
padding: theme.spacing(1),
|
||||
marginLeft: theme.spacing(-1)
|
||||
},
|
||||
subtitleComp: {
|
||||
padding: theme.spacing(1),
|
||||
marginTop: theme.spacing(-2),
|
||||
marginLeft: theme.spacing(-1),
|
||||
},
|
||||
titleContainer: {
|
||||
border: "none",
|
||||
},
|
||||
|
|
@ -184,7 +193,7 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
|||
</Typography>
|
||||
)
|
||||
if (title) return (
|
||||
<Box className={classes.title}>
|
||||
<Box className={classes.titleComp}>
|
||||
{title}
|
||||
</Box>
|
||||
)
|
||||
|
|
@ -198,7 +207,7 @@ export default function ResponsiveTable<T extends Object>(props: Props<T>) {
|
|||
</Typography>
|
||||
)
|
||||
if (subtitle) return (
|
||||
<Box className={classes.subtitle}>
|
||||
<Box className={classes.subtitleComp}>
|
||||
{subtitle}
|
||||
</Box>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import {
|
||||
Box,
|
||||
Breadcrumbs,
|
||||
Chip,
|
||||
IconButton,
|
||||
|
|
@ -13,7 +14,7 @@ import { Replay } from "@mui/icons-material";
|
|||
// import { Skeleton } from "@mui/l";
|
||||
import { useMobile } from "hooks";
|
||||
// import { MatchParams } from "navigation/Routes";
|
||||
import React, { ReactNode } from "react";
|
||||
import { ReactNode } from "react";
|
||||
import { useLocation } from "react-router";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
import { or } from "utils/types";
|
||||
|
|
@ -52,6 +53,11 @@ interface Props {
|
|||
reportTarget?: string;
|
||||
loading?: boolean;
|
||||
reload?: () => void;
|
||||
padding?: number;
|
||||
paddingLeft?: number;
|
||||
paddingRight?: number;
|
||||
paddingTop?: number;
|
||||
paddingBottom?: number;
|
||||
}
|
||||
|
||||
interface LinkRouterProps extends LinkProps {
|
||||
|
|
@ -251,19 +257,17 @@ export default function SmartBreadcrumb(props: Props) {
|
|||
const pathnames = location.pathname.split("/").filter((x: any) => x);
|
||||
const blacklist = breadcrumbBlacklist();
|
||||
|
||||
// console.log(pathnames)
|
||||
|
||||
if (pathnames.length < 1) {
|
||||
return [linkComponent("/", "Dashboard", true)];
|
||||
}
|
||||
|
||||
pathnames.forEach((_value: any, index: any) => {
|
||||
|
||||
const lastPath = index === pathnames.length - 1;
|
||||
const to = `/${pathnames.slice(0, index + 1).join("/")}`;
|
||||
|
||||
let label = breadcrumbMap[to];
|
||||
let result = to.split("/").filter(str => str !== "");
|
||||
// console.log(result)
|
||||
if (!label) {
|
||||
if (result.length > 1) {
|
||||
if (result[result.length - 1] !== "components") {
|
||||
|
|
@ -278,9 +282,8 @@ export default function SmartBreadcrumb(props: Props) {
|
|||
if (!blacklist.includes(to) && label) {
|
||||
links.push(linkComponent(to, label, lastPath));
|
||||
}
|
||||
});
|
||||
|
||||
// console.log(links)
|
||||
});
|
||||
|
||||
return links;
|
||||
};
|
||||
|
|
@ -315,7 +318,13 @@ export default function SmartBreadcrumb(props: Props) {
|
|||
if (loading === true) return <Skeleton variant="text" width="100%" />;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Box
|
||||
padding={props.padding}
|
||||
paddingLeft={props.paddingLeft}
|
||||
paddingRight={props.paddingRight}
|
||||
paddingTop={props.paddingTop}
|
||||
paddingBottom={props.paddingBottom}
|
||||
>
|
||||
<Breadcrumbs
|
||||
maxItems={isMobile ? 1 : 3}
|
||||
itemsBeforeCollapse={0}
|
||||
|
|
@ -331,6 +340,6 @@ export default function SmartBreadcrumb(props: Props) {
|
|||
<Replay />
|
||||
</IconButton>
|
||||
)}
|
||||
</React.Fragment>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
204
src/group/GroupActions.tsx
Normal file
204
src/group/GroupActions.tsx
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
import {
|
||||
IconButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Theme,
|
||||
Tooltip
|
||||
} from "@mui/material";
|
||||
import { blue } from "@mui/material/colors";
|
||||
import RemoveSelfIcon from "@mui/icons-material/ExitToApp";
|
||||
import MoreIcon from "@mui/icons-material/MoreVert";
|
||||
import GroupSettingsIcon from "@mui/icons-material/Settings";
|
||||
import ShareObjectIcon from "@mui/icons-material/Share";
|
||||
import ObjectUsersIcon from "@mui/icons-material/AccountCircle";
|
||||
import ObjectTeamsIcon from "@mui/icons-material/SupervisedUserCircle";
|
||||
import GroupSettings from "group/GroupSettings";
|
||||
import { Device, Group, groupScope } from "models";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { useState } from "react";
|
||||
// import ObjectTeams from "teams/ObjectTeams";
|
||||
import ObjectUsers from "user/ObjectUsers";
|
||||
import RemoveSelfFromObject from "user/RemoveSelfFromObject";
|
||||
import ShareObject from "user/ShareObject";
|
||||
import { isOffline } from "utils/environment";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
|
||||
// const useStyles = makeStyles((theme: Theme) => {
|
||||
// // const isMobile = useMobile()
|
||||
// return ({
|
||||
|
||||
// });
|
||||
// });
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => {
|
||||
return ({
|
||||
shareIcon: {
|
||||
color: blue["500"],
|
||||
"&:hover": {
|
||||
color: blue["600"]
|
||||
}
|
||||
},
|
||||
removeIcon: {
|
||||
color: "var(--status-alert)"
|
||||
},
|
||||
red: {
|
||||
color: "var(--status-alert)"
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
interface Props {
|
||||
group: Group;
|
||||
devices: Device[];
|
||||
permissions: pond.Permission[];
|
||||
refreshCallback: () => void;
|
||||
}
|
||||
|
||||
export default function GroupActions(props: Props) {
|
||||
const classes = useStyles();
|
||||
const { group, permissions, refreshCallback, devices } = props;
|
||||
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
||||
const [groupSettingsOpen, setGroupSettingsOpen] = useState(false);
|
||||
const [shareOpen, setShareOpen] = useState(false);
|
||||
const [usersOpen, setUsersOpen] = useState(false);
|
||||
const [teamsOpen, setTeamsOpen] = useState(false);
|
||||
const [removeSelfOpen, setRemoveSelfOpen] = useState(false);
|
||||
|
||||
const groupMenu = () => {
|
||||
const canShare = permissions.includes(pond.Permission.PERMISSION_SHARE);
|
||||
const canManageUsers = permissions.includes(pond.Permission.PERMISSION_USERS);
|
||||
const canTeams = canManageUsers;
|
||||
return (
|
||||
<Menu
|
||||
id="groupMenu"
|
||||
anchorEl={anchorEl}
|
||||
open={Boolean(anchorEl)}
|
||||
onClose={() => setAnchorEl(null)}
|
||||
keepMounted
|
||||
disableAutoFocusItem>
|
||||
{!isOffline() && canShare && (
|
||||
<MenuItem
|
||||
dense
|
||||
onClick={() => {
|
||||
setShareOpen(true);
|
||||
setAnchorEl(null);
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<ShareObjectIcon className={classes.shareIcon} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Share" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{!isOffline() && canManageUsers && (
|
||||
<MenuItem
|
||||
dense
|
||||
onClick={() => {
|
||||
setUsersOpen(true);
|
||||
setAnchorEl(null);
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<ObjectUsersIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Users" />
|
||||
</MenuItem>
|
||||
)}
|
||||
{!isOffline() && canTeams && (
|
||||
<MenuItem
|
||||
dense
|
||||
onClick={() => {
|
||||
setTeamsOpen(true);
|
||||
setAnchorEl(null);
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<ObjectTeamsIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Teams" />
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem
|
||||
dense
|
||||
onClick={() => {
|
||||
setRemoveSelfOpen(true);
|
||||
setAnchorEl(null);
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<RemoveSelfIcon className={classes.red} />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Leave" />
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
|
||||
const dialogs = () => {
|
||||
const hasWritePermission = permissions.includes(pond.Permission.PERMISSION_WRITE);
|
||||
const key = group.id().toString();
|
||||
const label = group.name();
|
||||
return (
|
||||
<>
|
||||
<GroupSettings
|
||||
mode="update"
|
||||
initialGroup={group}
|
||||
canEdit={hasWritePermission}
|
||||
isDialogOpen={groupSettingsOpen}
|
||||
refreshCallback={refreshCallback}
|
||||
closeDialogCallback={() => setGroupSettingsOpen(false)}
|
||||
groupDevices={devices}
|
||||
/>
|
||||
<ShareObject
|
||||
scope={groupScope(key)}
|
||||
label={label}
|
||||
permissions={permissions}
|
||||
isDialogOpen={shareOpen}
|
||||
closeDialogCallback={() => setShareOpen(false)}
|
||||
/>
|
||||
<ObjectUsers
|
||||
scope={groupScope(key)}
|
||||
label={label}
|
||||
permissions={permissions}
|
||||
isDialogOpen={usersOpen}
|
||||
closeDialogCallback={() => setUsersOpen(false)}
|
||||
refreshCallback={refreshCallback}
|
||||
/>
|
||||
{/* <ObjectTeams
|
||||
scope={groupScope(key)}
|
||||
label={label}
|
||||
permissions={permissions}
|
||||
isDialogOpen={teamsOpen}
|
||||
closeDialogCallback={() => setTeamsOpen(false)}
|
||||
refreshCallback={refreshCallback}
|
||||
/> */}
|
||||
<RemoveSelfFromObject
|
||||
scope={groupScope(key)}
|
||||
label={label}
|
||||
isDialogOpen={removeSelfOpen}
|
||||
closeDialogCallback={() => setRemoveSelfOpen(false)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tooltip title="Group Settings">
|
||||
<IconButton onClick={() => setGroupSettingsOpen(true)}>
|
||||
<GroupSettingsIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<IconButton
|
||||
aria-owns={anchorEl ? "groupMenu" : undefined}
|
||||
aria-haspopup="true"
|
||||
onClick={(event: React.MouseEvent<HTMLButtonElement>) => setAnchorEl(event.currentTarget)}>
|
||||
<MoreIcon />
|
||||
</IconButton>
|
||||
{groupMenu()}
|
||||
{dialogs()}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ import Logout from "pages/Logout";
|
|||
import Devices from "pages/Devices";
|
||||
import DevicePage from "pages/Device";
|
||||
import GroupsPage from "pages/Groups";
|
||||
import GroupPage from "pages/Group";
|
||||
|
||||
interface Props {
|
||||
open: boolean,
|
||||
|
|
@ -90,7 +91,6 @@ export default function Router(props: Props) {
|
|||
|
||||
const GroupsRoute = () => {
|
||||
console.log("groups route")
|
||||
console.log(window.location.pathname)
|
||||
return (
|
||||
<div>
|
||||
<Routes>
|
||||
|
|
@ -98,6 +98,10 @@ export default function Router(props: Props) {
|
|||
path="/"
|
||||
element={<GroupsPage />}
|
||||
/>
|
||||
<Route
|
||||
path="/:groupID"
|
||||
element={<GroupPage />}
|
||||
/>
|
||||
<Route
|
||||
key="Devices page route"
|
||||
path="/:groupID/devices/"
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@ const useStyles = makeStyles((theme: Theme) => {
|
|||
});
|
||||
|
||||
export default function DevicePage() {
|
||||
console.log("device")
|
||||
|
||||
const deviceAPI = useDeviceAPI()
|
||||
const snackbar = useSnackbar()
|
||||
const isMobile = useMobile()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { DeveloperBoard as ProvisionIcon, LibraryAdd as CreateGroupIcon } from "@mui/icons-material";
|
||||
import { Box, Chip, CircularProgress, IconButton, Tab, Tabs, Theme, Tooltip } from "@mui/material";
|
||||
import { Box, Chip, CircularProgress, IconButton, Tab, Tabs, Theme, Tooltip, Typography } from "@mui/material";
|
||||
import { blue, green } from "@mui/material/colors";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
||||
|
|
@ -47,6 +47,14 @@ const useStyles = makeStyles((theme: Theme) => {
|
|||
green: {
|
||||
color: green["600"]
|
||||
},
|
||||
tab: {
|
||||
display: "block",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
maxWidth: theme.spacing(26),
|
||||
whiteSpace: "nowrap",
|
||||
padding: theme.spacing(1.5)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -78,7 +86,7 @@ export default function Devices() {
|
|||
// const [totalGroups, setTotalGroups] = useState(0);
|
||||
|
||||
const updateGroups = (newGroups: Group[]) => {
|
||||
setGroups(newGroups); // Trigger UI update if needed
|
||||
setGroups(newGroups);
|
||||
};
|
||||
|
||||
const [selectedGroup, setSelectedGroup] = useState<Group | undefined>(undefined);
|
||||
|
|
@ -152,7 +160,6 @@ export default function Devices() {
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
const loadDevices = () => {
|
||||
setDevicesLoading(true)
|
||||
deviceAPI.list(
|
||||
|
|
@ -359,14 +366,14 @@ export default function Devices() {
|
|||
|
||||
return(
|
||||
<PageContainer padding={isMobile ? 0 : 2}>
|
||||
<SmartBreadcrumb key={"Device page crumbs"}/>
|
||||
{/* <SmartBreadcrumb /> */}
|
||||
<Box
|
||||
// onMouseEnter={() => setTabsHovered(true)}
|
||||
// onMouseLeave={() => setTabsHovered(false)}
|
||||
sx={{
|
||||
borderRadius: 1,
|
||||
border: "1px solid rgba(150, 150, 150, 0.2)",
|
||||
marginTop: 1,
|
||||
marginTop: 0,
|
||||
marginBottom: 1
|
||||
}}
|
||||
>
|
||||
|
|
@ -377,19 +384,19 @@ export default function Devices() {
|
|||
scrollButtons="auto"
|
||||
sx={{ borderRadius: 1 }}
|
||||
>
|
||||
<Tab value={"all"} label="All" />
|
||||
<Tab wrapped value={"all"} label="All" />
|
||||
{groupsLoading ?
|
||||
<Tab value={"loading"} label={<CircularProgress />}/>
|
||||
: groups.map((group, index) => {
|
||||
if (group.id()) return (
|
||||
<Tab value={group.id().toString()} label={group.name()} key={"group-tab-"+index}/>
|
||||
<Tab className={classes.tab} wrapped value={group.id().toString()} label={<Typography variant="inherit" noWrap>{group.name()}</Typography>} key={"group-tab-"+index}/>
|
||||
)
|
||||
})}
|
||||
<Tab value={"never"} label={<CreateGroupIcon className={classes.green} />} onClick={() => openGroupSettings(undefined, "add")} />
|
||||
<Tab wrapped value={"never"} label={<CreateGroupIcon className={classes.green} />} onClick={() => openGroupSettings(undefined, "add")} />
|
||||
</Tabs>
|
||||
</Box>
|
||||
<ResponsiveTable<pond.Device>
|
||||
title="Devices"
|
||||
title={<SmartBreadcrumb paddingBottom={1}/>}
|
||||
subtitle={subtitle()}
|
||||
rows={devices}
|
||||
columns={columns()}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,230 @@
|
|||
import { Grid2 } from "@mui/material";
|
||||
import { Box, Chip, Grid2, Theme, Tooltip, Typography } from "@mui/material";
|
||||
import SmartBreadcrumb from "common/SmartBreadcrumb";
|
||||
import { Group } from "models"
|
||||
import { useState } from "react"
|
||||
import { useLocation, useParams } from "react-router-dom";
|
||||
import { Device, Group } from "models"
|
||||
import { useEffect, useState } from "react"
|
||||
import { useLocation, useNavigate, useParams } from "react-router-dom";
|
||||
import PageContainer from "./PageContainer";
|
||||
import { useDeviceAPI, useGroupAPI } from "providers";
|
||||
import GroupActions from "group/GroupActions";
|
||||
import { pond } from "protobuf-ts/pond";
|
||||
import { getContextKeys, getContextTypes } from "pbHelpers/Context";
|
||||
import ResponsiveTable, { Column } from "common/ResponsiveTable";
|
||||
import { or } from "utils/types";
|
||||
import { appendToUrl } from "navigation/Router";
|
||||
import { getDeviceStateHelper } from "pbHelpers/DeviceState";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import { blue, green } from "@mui/material/colors";
|
||||
import { permissionToString } from "pbHelpers/Permission";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => {
|
||||
return ({
|
||||
buttonBox: {
|
||||
position: "absolute",
|
||||
zIndex: 1,
|
||||
right: theme.spacing(4),
|
||||
transform: "translateY(-50%)", // Move it up by half its height
|
||||
transition: "opacity 0.2s ease-in-out",
|
||||
opacity: 1,
|
||||
// top: 0,
|
||||
},
|
||||
fadeBox: {
|
||||
opacity: 0, // Fully transparent by default
|
||||
transition: "opacity 0.2s ease-in-out", // Smooth transition
|
||||
"&:hover": {
|
||||
opacity: 1, // Fully opaque on hover
|
||||
},
|
||||
},
|
||||
provisionIcon: {
|
||||
color: blue["700"]
|
||||
},
|
||||
cellContainer: {
|
||||
margin: theme.spacing(1),
|
||||
marginLeft: theme.spacing(2),
|
||||
display: "flex",
|
||||
// justifyContent: "center",
|
||||
},
|
||||
green: {
|
||||
color: green["600"]
|
||||
},
|
||||
tab: {
|
||||
display: "block",
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
maxWidth: theme.spacing(26),
|
||||
whiteSpace: "nowrap",
|
||||
padding: theme.spacing(1.5)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
export default function GroupPage() {
|
||||
|
||||
const groupID = useParams<{ groupID: string }>()?.groupID ?? "";
|
||||
const groupAPI = useGroupAPI()
|
||||
const deviceAPI = useDeviceAPI()
|
||||
const navigate = useNavigate()
|
||||
const classes = useStyles()
|
||||
|
||||
const groupID = parseInt(useParams<{ groupID: string }>()?.groupID ?? "0");
|
||||
const { state } = useLocation();
|
||||
const [group, setGroup] = useState<Group>(state?.device ? Group.create(state.device) : Group.create())
|
||||
const [group, setGroup] = useState<Group>(state?.group ? Group.create(state.group) : Group.create())
|
||||
const [loadingGroup, setLoadingGroup] = useState(false)
|
||||
const [loadingDevices, setLoadingDevices] = useState(false)
|
||||
const [devices, setDevices] = useState<Device[]>([])
|
||||
const [permissions, setPermissions] = useState<pond.Permission[]>([])
|
||||
const [limit, setLimit] = useState(0)
|
||||
const [total, setTotal] = useState(0)
|
||||
const [page, setPage] = useState(1)
|
||||
const [order, setOrder] = useState<"asc" | "desc">("asc")
|
||||
const [orderBy, setOrderBy] = useState("")
|
||||
const [search, setSearch] = useState("")
|
||||
|
||||
const loadGroup = () => {
|
||||
setLoadingGroup(true)
|
||||
groupAPI.getGroupAndPermissions(groupID).then(resp => {
|
||||
if (resp.data.group) setGroup(Group.create(resp.data.group))
|
||||
let newPerms: pond.Permission[] = []
|
||||
resp.data.permissions.forEach(perm => {
|
||||
if (typeof(perm) === "string") {
|
||||
const permNumber = pond.Permission[perm as keyof typeof pond.Permission]
|
||||
newPerms.push(permNumber)
|
||||
} else {
|
||||
newPerms.push(perm)
|
||||
}
|
||||
})
|
||||
setPermissions(newPerms)
|
||||
}).finally(() => {
|
||||
setLoadingGroup(false)
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (group.id() === groupID) return;
|
||||
loadGroup()
|
||||
}, [group, groupID])
|
||||
|
||||
const loadDevices = () => {
|
||||
setLoadingDevices(true)
|
||||
deviceAPI.list(
|
||||
limit,
|
||||
page*limit,
|
||||
order,
|
||||
orderBy,
|
||||
search,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
getContextKeys(),
|
||||
getContextTypes()
|
||||
).then(resp => {
|
||||
let newDevices: Device[] = [];
|
||||
resp.data.devices.forEach(device => {
|
||||
newDevices.push(Device.create(device))
|
||||
})
|
||||
setDevices(newDevices)
|
||||
setTotal(resp.data.total)
|
||||
}).finally(() => {
|
||||
setLoadingDevices(false)
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadDevices()
|
||||
}, [group, limit, page, order, orderBy, search])
|
||||
|
||||
const toDevice = (device: Device) => {
|
||||
navigate(appendToUrl(or(device.settings?.deviceId, "")), { state: {device: device} })
|
||||
};
|
||||
|
||||
const columns = (): Column<Device>[] => {
|
||||
return [
|
||||
{
|
||||
title: "State",
|
||||
render: (device) => {
|
||||
const status = device.status ?? pond.DeviceStatus.create()
|
||||
const deviceStateHelper = getDeviceStateHelper(status.state);
|
||||
return (
|
||||
<Grid2 container justifyContent={"space-between"}>
|
||||
<Grid2>
|
||||
<SmartBreadcrumb groupName={group.name()} />
|
||||
</Grid2>
|
||||
<Grid2>
|
||||
{/* <GroupActions /> */}
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
<Box className={classes.cellContainer}>
|
||||
<Tooltip title={deviceStateHelper.description}>{deviceStateHelper.icon}</Tooltip>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "ID",
|
||||
render: device => <span className={classes.cellContainer}>
|
||||
{device.settings?.deviceId}
|
||||
</span>
|
||||
},
|
||||
{
|
||||
title: "Device",
|
||||
render: (device) => {
|
||||
return (
|
||||
<Box className={classes.cellContainer} >
|
||||
<Chip
|
||||
variant="outlined"
|
||||
label={device.settings?.name ? device.settings.name : "Device " + device.settings?.deviceId}
|
||||
/>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Description",
|
||||
render: device => {
|
||||
const description = device.settings?.description ?? ""
|
||||
return (
|
||||
<Box className={classes.cellContainer}>
|
||||
<Tooltip title={device.settings?.description}>
|
||||
<span>
|
||||
{description.length > 20
|
||||
? description.substring(0, 20) + "..."
|
||||
: description}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
const handleChange = (event: any) => {
|
||||
setLimit(event.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
<Grid2 container justifyContent={"space-between"} alignItems={"center"} paddingBottom={2}>
|
||||
<Grid2 >
|
||||
<SmartBreadcrumb groupName={group.name()} loading={loadingGroup} />
|
||||
</Grid2>
|
||||
<Grid2 marginTop={"auto"} marginBottom="auto">
|
||||
<GroupActions
|
||||
group={group}
|
||||
permissions={permissions ? permissions : []}
|
||||
devices={devices}
|
||||
refreshCallback={() => {}}
|
||||
/>
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
<ResponsiveTable<Device>
|
||||
title={group.name()}
|
||||
subtitle={group.settings.description}
|
||||
rows={devices}
|
||||
columns={columns()}
|
||||
total={total}
|
||||
pageSize={limit}
|
||||
page={page}
|
||||
setPage={setPage}
|
||||
handleRowsPerPageChange={handleChange}
|
||||
onRowClick={toDevice}
|
||||
setSearchText={setSearch}
|
||||
isLoading={loadingDevices}
|
||||
/>
|
||||
</PageContainer>
|
||||
)
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import { useGroupAPI } from "providers";
|
|||
import { useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { or } from "utils/types";
|
||||
import PageContainer from "./PageContainer";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => {
|
||||
const isMobile = useMobile()
|
||||
|
|
@ -115,6 +116,7 @@ export default function GroupsPage() {
|
|||
}
|
||||
|
||||
return (
|
||||
<PageContainer >
|
||||
<ResponsiveTable<pond.Group>
|
||||
title={<SmartBreadcrumb />}
|
||||
rows={groups}
|
||||
|
|
@ -128,5 +130,6 @@ export default function GroupsPage() {
|
|||
setSearchText={setSearch}
|
||||
onRowClick={handleRowClick}
|
||||
/>
|
||||
</PageContainer>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
import { Container, SxProps, Theme } from "@mui/material";
|
||||
import { makeStyles } from "@mui/styles";
|
||||
import classNames from "classnames";
|
||||
import React, { PropsWithChildren } from "react";
|
||||
import { useMobile } from "hooks";
|
||||
import { PropsWithChildren } from "react";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) => ({
|
||||
pageContainer: {
|
||||
|
|
@ -41,11 +42,13 @@ interface Props extends PropsWithChildren{
|
|||
padding?: number;
|
||||
}
|
||||
|
||||
export const PageContainer: React.FunctionComponent<Props> = props => {
|
||||
export const PageContainer: React.FunctionComponent<Props> = (props: Props) => {
|
||||
const classes = useStyles();
|
||||
const { children, fullViewport, isCenterCenter, sx, padding } = props;
|
||||
const isMobile = useMobile();
|
||||
const { children, fullViewport, isCenterCenter, sx } = props;
|
||||
// let fullViewport = false
|
||||
// let isCenterCenter = false
|
||||
const padding = props.padding ? props.padding : isMobile ? 1 : 2;
|
||||
return (
|
||||
<Container
|
||||
className={classNames(
|
||||
|
|
@ -58,7 +61,7 @@ export const PageContainer: React.FunctionComponent<Props> = props => {
|
|||
}}
|
||||
disableGutters
|
||||
maxWidth={false}
|
||||
children={<React.Fragment>{children}</React.Fragment>}
|
||||
children={<>{children}</>}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ export interface IGroupAPIContext {
|
|||
updateGroup: (id: number, group: pond.GroupSettings) => Promise<any>;
|
||||
removeGroup: (id: number) => Promise<any>;
|
||||
getGroup: (id: number) => Promise<any>;
|
||||
getGroupAndPermissions: (id: number) => Promise<AxiosResponse<pond.GetGroupAndPermissionsResponse>>;
|
||||
listGroups: (
|
||||
limit: number,
|
||||
offset: number,
|
||||
|
|
@ -78,6 +79,27 @@ export default function GroupProvider(props: PropsWithChildren<Props>) {
|
|||
return get(pondURL("/groups/" + id));
|
||||
};
|
||||
|
||||
const getGroupAndPermissions = (
|
||||
id: number,
|
||||
keys?: string[],
|
||||
types?: string[],
|
||||
) => {
|
||||
keys = keys ? keys : getContextKeys();
|
||||
types = types? types : getContextTypes();
|
||||
let url = "/groupAndPermissions/" + id
|
||||
if (as) {
|
||||
url = url + "?as=" + as +
|
||||
+
|
||||
(keys ? "?keys=" + keys.toString() : "") +
|
||||
(types ? "&types=" + types.toString() : "")
|
||||
} else {
|
||||
url = url +
|
||||
(keys ? "?keys=" + keys.toString() : "") +
|
||||
(types ? "&types=" + types.toString() : "")
|
||||
}
|
||||
return get<pond.GetGroupAndPermissionsResponse>(pondURL(url));
|
||||
};
|
||||
|
||||
const listGroups = (
|
||||
limit: number,
|
||||
offset: number,
|
||||
|
|
@ -152,6 +174,7 @@ export default function GroupProvider(props: PropsWithChildren<Props>) {
|
|||
updateGroup,
|
||||
removeGroup,
|
||||
getGroup,
|
||||
getGroupAndPermissions,
|
||||
listGroups,
|
||||
listGroupDevices,
|
||||
updateGroupPermissions
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ const useStyles = makeStyles((theme: Theme) => ({
|
|||
titleBox: {
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
marginLeft: theme.spacing(1),
|
||||
}
|
||||
}))
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
//"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
//"moduleDetection": "force",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue