From 1a750e8279ce265895bdb45945ded75b6764d018 Mon Sep 17 00:00:00 2001 From: miloschwartz Date: Sat, 12 Apr 2025 15:04:32 -0400 Subject: [PATCH] test new layout --- package-lock.json | 219 ++++++++-------- package.json | 4 +- .../access/AccessPageHeaderAndNav.tsx | 29 +-- .../invitations/InvitationsDataTable.tsx | 86 +------ .../settings/access/roles/RolesDataTable.tsx | 146 +---------- .../settings/access/roles/RolesTable.tsx | 2 +- .../[orgId]/settings/access/roles/page.tsx | 13 +- .../settings/access/users/UsersDataTable.tsx | 144 +---------- .../settings/access/users/[userId]/layout.tsx | 13 +- .../[orgId]/settings/access/users/page.tsx | 17 +- src/app/[orgId]/settings/general/layout.tsx | 8 +- src/app/[orgId]/settings/layout.tsx | 46 ++-- .../settings/resources/ResourcesDataTable.tsx | 150 ++--------- .../settings/resources/ResourcesTable.tsx | 2 +- .../resources/[resourceId]/layout.tsx | 20 +- src/app/[orgId]/settings/resources/page.tsx | 2 +- .../share-links/ShareLinksDataTable.tsx | 150 ++--------- .../settings/share-links/ShareLinksTable.tsx | 2 +- src/app/[orgId]/settings/share-links/page.tsx | 2 +- .../[orgId]/settings/sites/SitesDataTable.tsx | 146 +---------- src/app/[orgId]/settings/sites/SitesTable.tsx | 47 +--- .../settings/sites/[niceId]/layout.tsx | 37 +-- src/app/[orgId]/settings/sites/page.tsx | 2 +- src/app/admin/layout.tsx | 26 +- src/app/admin/users/AdminUsersDataTable.tsx | 131 +--------- src/app/layout.tsx | 71 +---- src/components/Breadcrumbs.tsx | 72 ++++++ src/components/Header.tsx | 156 +---------- src/components/HorizontalTabs.tsx | 74 ++++++ src/components/Layout.tsx | 107 ++++++++ src/components/OrgSelector.tsx | 124 +++++++++ src/components/ProfileIcon.tsx | 11 +- src/components/SidebarNav.tsx | 243 +++++------------- src/components/SupporterStatus.tsx | 2 +- src/components/TopBar.tsx | 37 +++ src/components/ui/data-table.tsx | 148 +++++++++++ src/components/ui/table.tsx | 122 ++++----- tsconfig.json | 3 +- 38 files changed, 992 insertions(+), 1622 deletions(-) create mode 100644 src/components/Breadcrumbs.tsx create mode 100644 src/components/HorizontalTabs.tsx create mode 100644 src/components/Layout.tsx create mode 100644 src/components/OrgSelector.tsx create mode 100644 src/components/TopBar.tsx create mode 100644 src/components/ui/data-table.tsx diff --git a/package-lock.json b/package-lock.json index d0bd1a47..20bc0462 100644 --- a/package-lock.json +++ b/package-lock.json @@ -90,8 +90,8 @@ "@types/js-yaml": "4.0.9", "@types/node": "^22", "@types/nodemailer": "6.4.17", - "@types/react": "19.0.2", - "@types/react-dom": "19.0.2", + "@types/react": "19.1.1", + "@types/react-dom": "19.1.2", "@types/semver": "7.5.8", "@types/swagger-ui-express": "^4.1.8", "@types/ws": "8.5.13", @@ -372,9 +372,9 @@ } }, "node_modules/@emnapi/core": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.0.tgz", - "integrity": "sha512-H+N/FqT07NmLmt6OFFtDfwe8PNygprzBikrEMyQfgqSmT0vzE515Pz7R8izwB9q/zsH/MA64AKoul3sA6/CzVg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.1.tgz", + "integrity": "sha512-4JFstCTaToCFrPqrGzgkF8N2NHjtsaY4uRh6brZQ5L9e4wbMieX8oDT8N7qfVFTQecHFEtkj4ve49VIZ3mKVqw==", "license": "MIT", "optional": true, "dependencies": { @@ -383,9 +383,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.0.tgz", - "integrity": "sha512-64WYIf4UYcdLnbKn/umDlNjQDSS8AgZrI/R9+x5ilkUVFxXcA1Ebl+gQLc/6mERA4407Xof0R7wEyEuj091CVw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.1.tgz", + "integrity": "sha512-LMshMVP0ZhACNjQNYXiU1iZJ6QCcv0lUdPDPugqGvCGXt5xtRVBPdtA0qU12pEXZzpWAhWlZYptfdAFq10DOVQ==", "license": "MIT", "optional": true, "dependencies": { @@ -1280,9 +1280,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz", - "integrity": "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.0.tgz", + "integrity": "sha512-WhCn7Z7TauhBtmzhvKpoQs0Wwb/kBcy4CwpuI0/eEIr2Lx2auxmulAzLr91wVZJaz47iUZdkXOK7WlAfxGKCnA==", "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.4.3" @@ -4061,16 +4061,6 @@ "tailwindcss": "4.1.3" } }, - "node_modules/@tailwindcss/node/node_modules/jiti": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", - "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, "node_modules/@tailwindcss/oxide": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.3.tgz", @@ -4455,9 +4445,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.14.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.0.tgz", - "integrity": "sha512-Kmpl+z84ILoG+3T/zQFyAJsU6EPTmOCj8/2+83fSN6djd6I4o7uOuGIH6vq3PrjY5BGitSbFuMN18j3iknubbA==", + "version": "22.14.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz", + "integrity": "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==", "devOptional": true, "license": "MIT", "dependencies": { @@ -4489,9 +4479,9 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.2.tgz", - "integrity": "sha512-USU8ZI/xyKJwFTpjSVIrSeHBVAGagkHQKPNbxeWwql/vDmnTIBgx+TJnhFnj1NXgz8XfprU0egV2dROLGpsBEg==", + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.1.tgz", + "integrity": "sha512-ePapxDL7qrgqSF67s0h9m412d9DbXyC1n59O2st+9rjuuamWsZuD2w55rqY12CbzsZ7uVXb5Nw0gEp9Z8MMutQ==", "devOptional": true, "license": "MIT", "dependencies": { @@ -4499,9 +4489,9 @@ } }, "node_modules/@types/react-dom": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.2.tgz", - "integrity": "sha512-c1s+7TKFaDRRxr1TxccIX2u7sfCnc3RxkVyBIUA2lCpyqCF+QoAwQ/CBg7bsMdVwP120HEH143VQezKtef5nCg==", + "version": "19.1.2", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.2.tgz", + "integrity": "sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw==", "devOptional": true, "license": "MIT", "peerDependencies": { @@ -4807,9 +4797,9 @@ } }, "node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.4.1.tgz", - "integrity": "sha512-8Tv+Bsd0BjGwfEedIyor4inw8atppRxM5BdUnIt+3mAm/QXUm7Dw74CHnXpfZKXkp07EXJGiA8hStqCINAWhdw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.5.0.tgz", + "integrity": "sha512-YmocNlEcX/AgJv8gI41bhjMOTcKcea4D2nRIbZj+MhRtSH5+vEU8r/pFuTuoF+JjVplLsBueU+CILfBPVISyGQ==", "cpu": [ "arm64" ], @@ -4820,9 +4810,9 @@ ] }, "node_modules/@unrs/resolver-binding-darwin-x64": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.4.1.tgz", - "integrity": "sha512-X8c3PhWziEMKAzZz+YAYWfwawi5AEgzy/hmfizAB4C70gMHLKmInJcp1270yYAOs7z07YVFI220pp50z24Jk3A==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.5.0.tgz", + "integrity": "sha512-qpUrXgH4e/0xu1LOhPEdfgSY3vIXOxDQv370NEL8npN8h40HcQDA+Pl2r4HBW6tTXezWIjxUFcP7tj529RZtDw==", "cpu": [ "x64" ], @@ -4833,9 +4823,9 @@ ] }, "node_modules/@unrs/resolver-binding-freebsd-x64": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.4.1.tgz", - "integrity": "sha512-UUr/nREy1UdtxXQnmLaaTXFGOcGxPwNIzeJdb3KXai3TKtC1UgNOB9s8KOA4TaxOUBR/qVgL5BvBwmUjD5yuVA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.5.0.tgz", + "integrity": "sha512-3tX8r8vgjvZzaJZB4jvxUaaFCDCb3aWDCpZN3EjhGnnwhztslI05KSG5NY/jNjlcZ5QWZ7dEZZ/rNBFsmTaSPw==", "cpu": [ "x64" ], @@ -4846,9 +4836,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.4.1.tgz", - "integrity": "sha512-e3pII53dEeS8inkX6A1ad2UXE0nuoWCqik4kOxaDnls0uJUq0ntdj5d9IYd+bv5TDwf9DSge/xPOvCmRYH+Tsw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.5.0.tgz", + "integrity": "sha512-FH+ixzBKaUU9fWOj3TYO+Yn/eO6kYvMLV9eNJlJlkU7OgrxkCmiMS6wUbyT0KA3FOZGxnEQ2z3/BHgYm2jqeLA==", "cpu": [ "arm" ], @@ -4859,9 +4849,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.4.1.tgz", - "integrity": "sha512-e/AKKd9gR+HNmVyDEPI/PIz2t0DrA3cyonHNhHVjrkxe8pMCiYiqhtn1+h+yIpHUtUlM6Y1FNIdivFa+r7wrEQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.5.0.tgz", + "integrity": "sha512-pxCgXMgwB/4PfqFQg73lMhmWwcC0j5L+dNXhZoz/0ek0iS/oAWl65fxZeT/OnU7fVs52MgdP2q02EipqJJXHSg==", "cpu": [ "arm" ], @@ -4872,9 +4862,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.4.1.tgz", - "integrity": "sha512-vtIu34luF1jRktlHtiwm2mjuE8oJCsFiFr8hT5+tFQdqFKjPhbJXn83LswKsOhy0GxAEevpXDI4xxEwkjuXIPA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.5.0.tgz", + "integrity": "sha512-FX2FV7vpLE/+Z0NZX9/1pwWud5Wocm/2PgpUXbT5aSV3QEB10kBPJAzssOQylvdj8mOHoKl5pVkXpbCwww/T2g==", "cpu": [ "arm64" ], @@ -4885,9 +4875,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.4.1.tgz", - "integrity": "sha512-H3PaOuGyhFXiyJd+09uPhGl4gocmhyi1BRzvsP8Lv5AQO3p3/ZY7WjV4t2NkBksm9tMjf3YbOVHyPWi2eWsNYw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.5.0.tgz", + "integrity": "sha512-+gF97xst1BZb28T3nwwzEtq2ewCoMDGKsenYsZuvpmNrW0019G1iUAunZN+FG55L21y+uP7zsGX06OXDQ/viKw==", "cpu": [ "arm64" ], @@ -4898,9 +4888,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.4.1.tgz", - "integrity": "sha512-4+GmJcaaFntCi1S01YByqp8wLMjV/FyQyHVGm0vedIhL1Vfx7uHkz/sZmKsidRwokBGuxi92GFmSzqT2O8KcNA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.5.0.tgz", + "integrity": "sha512-5bEmVcQw9js8JYM2LkUBw5SeELSIxX+qKf9bFrfFINKAp4noZ//hUxLpbF7u/3gTBN1GsER6xOzIZlw/VTdXtA==", "cpu": [ "ppc64" ], @@ -4910,10 +4900,23 @@ "linux" ] }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.5.0.tgz", + "integrity": "sha512-GGk/8TPUsf1Q99F+lzMdjE6sGL26uJCwQ9TlvBs8zR3cLQNw/MIumPN7zrs3GFGySjnwXc8gA6J3HKbejywmqA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.4.1.tgz", - "integrity": "sha512-6RDQVCmtFYTlhy89D5ixTqo9bTQqFhvNN0Ey1wJs5r+01Dq15gPHRXv2jF2bQATtMrOfYwv+R2ZR9ew1N1N3YQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.5.0.tgz", + "integrity": "sha512-5uRkFYYVNAeVaA4W/CwugjFN3iDOHCPqsBLCCOoJiMfFMMz4evBRsg+498OFa9w6VcTn2bD5aI+RRayaIgk2Sw==", "cpu": [ "s390x" ], @@ -4924,9 +4927,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.4.1.tgz", - "integrity": "sha512-XpU9uzIkD86+19NjCXxlVPISMUrVXsXo5htxtuG+uJ59p5JauSRZsIxQxzzfKzkxEjdvANPM/lS1HFoX6A6QeA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.5.0.tgz", + "integrity": "sha512-j905CZH3nehYy6NimNqC2B14pxn4Ltd7guKMyPTzKehbFXTUgihQS/ZfHQTdojkMzbSwBOSgq1dOrY+IpgxDsA==", "cpu": [ "x64" ], @@ -4937,9 +4940,9 @@ ] }, "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.4.1.tgz", - "integrity": "sha512-3CDjG/spbTKCSHl66QP2ekHSD+H34i7utuDIM5gzoNBcZ1gTO0Op09Wx5cikXnhORRf9+HyDWzm37vU1PLSM1A==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.5.0.tgz", + "integrity": "sha512-dmLevQTuzQRwu5A+mvj54R5aye5I4PVKiWqGxg8tTaYP2k2oTs/3Mo8mgnhPk28VoYCi0fdFYpgzCd4AJndQvQ==", "cpu": [ "x64" ], @@ -4950,9 +4953,9 @@ ] }, "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.4.1.tgz", - "integrity": "sha512-50tYhvbCTnuzMn7vmP8IV2UKF7ITo1oihygEYq9wW2DUb/Y+QMqBHJUSCABRngATjZ4shOK6f2+s0gQX6ElENQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.5.0.tgz", + "integrity": "sha512-LtJMhwu7avhoi+kKfAZOKN773RtzLBVVF90YJbB0wyMpUj9yQPeA+mteVUI9P70OG/opH47FeV5AWeaNWWgqJg==", "cpu": [ "wasm32" ], @@ -4966,9 +4969,9 @@ } }, "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.4.1.tgz", - "integrity": "sha512-KyJiIne/AqV4IW0wyQO34wSMuJwy3VxVQOfIXIPyQ/Up6y/zi2P/WwXb78gHsLiGRUqCA9LOoCX+6dQZde0g1g==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.5.0.tgz", + "integrity": "sha512-FTZBxLL4SO1mgIM86KykzJmPeTPisBDHQV6xtfDXbTMrentuZ6SdQKJUV5BWaoUK3p8kIULlrCcucqdCnk8Npg==", "cpu": [ "arm64" ], @@ -4979,9 +4982,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.4.1.tgz", - "integrity": "sha512-y2NUD7pygrBolN2NoXUrwVqBpKPhF8DiSNE5oB5/iFO49r2DpoYqdj5HPb3F42fPBH5qNqj6Zg63+xCEzAD2hw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.5.0.tgz", + "integrity": "sha512-i5bB7vJ1waUsFciU/FKLd4Zw0VnAkvhiJ4//jYQXyDUuiLKodmtQZVTcOPU7pp97RrNgCFtXfC1gnvj/DHPJTw==", "cpu": [ "ia32" ], @@ -4992,9 +4995,9 @@ ] }, "node_modules/@unrs/resolver-binding-win32-x64-msvc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.4.1.tgz", - "integrity": "sha512-hVXaObGI2lGFmrtT77KSbPQ3I+zk9IU500wobjk0+oX59vg/0VqAzABNtt3YSQYgXTC2a/LYxekLfND/wlt0yQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.5.0.tgz", + "integrity": "sha512-wAvXp4k7jhioi4SebXW/yfzzYwsUCr9kIX4gCsUFKpCTUf8Mi7vScJXI3S+kupSUf0LbVHudR8qBbe2wFMSNUw==", "cpu": [ "x64" ], @@ -5633,9 +5636,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001712", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001712.tgz", - "integrity": "sha512-MBqPpGYYdQ7/hfKiet9SCI+nmN5/hp4ZzveOJubl5DTAMa5oggjAuoi0Z4onBpKPFI2ePGnQuQIzF3VxDjDJig==", + "version": "1.0.30001713", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001713.tgz", + "integrity": "sha512-wCIWIg+A4Xr7NfhTuHdX+/FKh3+Op3LBbSp2N5Pfx6T/LhdQy3GTyoTg48BReaW/MyMNZAkTadsBtai3ldWK0Q==", "funding": [ { "type": "opencollective", @@ -6381,9 +6384,9 @@ } }, "node_modules/dotenv": { - "version": "16.4.7", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", - "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", + "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -9349,14 +9352,13 @@ } }, "node_modules/jiti": { - "version": "1.21.7", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "devOptional": true, "license": "MIT", - "optional": true, - "peer": true, "bin": { - "jiti": "bin/jiti.js" + "jiti": "lib/jiti-cli.mjs" } }, "node_modules/js-tokens": { @@ -15579,9 +15581,9 @@ } }, "node_modules/swagger-ui-dist": { - "version": "5.20.7", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.20.7.tgz", - "integrity": "sha512-gLpb1wrWinUwMFKfSvDYsIlCyGQSryftzi6uWc9Qo98zO3mFT6oHOqmDUu5OoahvepuS6HGTe/3MsGUCVtpLig==", + "version": "5.20.8", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.20.8.tgz", + "integrity": "sha512-VXVhdRh5vuKVpkegw0n0wCXuFFG+pxNmXa0vDcf76r1yP2cYKqcpOE5g8l5crbtLGx+j2EiDnG4/EU5T0jyN1w==", "license": "Apache-2.0", "dependencies": { "@scarf/scarf": "=1.4.0" @@ -16018,29 +16020,30 @@ } }, "node_modules/unrs-resolver": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.4.1.tgz", - "integrity": "sha512-MhPB3wBI5BR8TGieTb08XuYlE8oFVEXdSAgat3psdlRyejl8ojQ8iqPcjh094qCZ1r+TnkxzP6BeCd/umfHckQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.5.0.tgz", + "integrity": "sha512-6aia3Oy7SEe0MuUGQm2nsyob0L2+g57w178K5SE/3pvSGAIp28BB2O921fKx424Ahc/gQ6v0DXFbhcpyhGZdOA==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/JounQin" }, "optionalDependencies": { - "@unrs/resolver-binding-darwin-arm64": "1.4.1", - "@unrs/resolver-binding-darwin-x64": "1.4.1", - "@unrs/resolver-binding-freebsd-x64": "1.4.1", - "@unrs/resolver-binding-linux-arm-gnueabihf": "1.4.1", - "@unrs/resolver-binding-linux-arm-musleabihf": "1.4.1", - "@unrs/resolver-binding-linux-arm64-gnu": "1.4.1", - "@unrs/resolver-binding-linux-arm64-musl": "1.4.1", - "@unrs/resolver-binding-linux-ppc64-gnu": "1.4.1", - "@unrs/resolver-binding-linux-s390x-gnu": "1.4.1", - "@unrs/resolver-binding-linux-x64-gnu": "1.4.1", - "@unrs/resolver-binding-linux-x64-musl": "1.4.1", - "@unrs/resolver-binding-wasm32-wasi": "1.4.1", - "@unrs/resolver-binding-win32-arm64-msvc": "1.4.1", - "@unrs/resolver-binding-win32-ia32-msvc": "1.4.1", - "@unrs/resolver-binding-win32-x64-msvc": "1.4.1" + "@unrs/resolver-binding-darwin-arm64": "1.5.0", + "@unrs/resolver-binding-darwin-x64": "1.5.0", + "@unrs/resolver-binding-freebsd-x64": "1.5.0", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.5.0", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.5.0", + "@unrs/resolver-binding-linux-arm64-gnu": "1.5.0", + "@unrs/resolver-binding-linux-arm64-musl": "1.5.0", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.5.0", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.5.0", + "@unrs/resolver-binding-linux-s390x-gnu": "1.5.0", + "@unrs/resolver-binding-linux-x64-gnu": "1.5.0", + "@unrs/resolver-binding-linux-x64-musl": "1.5.0", + "@unrs/resolver-binding-wasm32-wasi": "1.5.0", + "@unrs/resolver-binding-win32-arm64-msvc": "1.5.0", + "@unrs/resolver-binding-win32-ia32-msvc": "1.5.0", + "@unrs/resolver-binding-win32-x64-msvc": "1.5.0" } }, "node_modules/uri-js": { diff --git a/package.json b/package.json index 918cbe74..c1f9fd64 100644 --- a/package.json +++ b/package.json @@ -101,8 +101,8 @@ "@types/js-yaml": "4.0.9", "@types/node": "^22", "@types/nodemailer": "6.4.17", - "@types/react": "19.0.2", - "@types/react-dom": "19.0.2", + "@types/react": "19.1.1", + "@types/react-dom": "19.1.2", "@types/semver": "7.5.8", "@types/swagger-ui-express": "^4.1.8", "@types/ws": "8.5.13", diff --git a/src/app/[orgId]/settings/access/AccessPageHeaderAndNav.tsx b/src/app/[orgId]/settings/access/AccessPageHeaderAndNav.tsx index a9d3b4a1..a3053e7e 100644 --- a/src/app/[orgId]/settings/access/AccessPageHeaderAndNav.tsx +++ b/src/app/[orgId]/settings/access/AccessPageHeaderAndNav.tsx @@ -1,29 +1,21 @@ "use client"; +import { HorizontalTabs } from "@app/components/HorizontalTabs"; import SettingsSectionTitle from "@app/components/SettingsSectionTitle"; -import { SidebarSettings } from "@app/components/SidebarSettings"; -type AccessPageHeaderAndNavProps = { +interface AccessPageHeaderAndNavProps { children: React.ReactNode; hasInvitations: boolean; -}; +} export default function AccessPageHeaderAndNav({ children, hasInvitations }: AccessPageHeaderAndNavProps) { - const sidebarNavItems = [ + const navItems = [ { title: "Users", - href: `/{orgId}/settings/access/users`, - children: hasInvitations - ? [ - { - title: "Invitations", - href: `/{orgId}/settings/access/invitations` - } - ] - : [] + href: `/{orgId}/settings/access/users` }, { title: "Roles", @@ -31,6 +23,13 @@ export default function AccessPageHeaderAndNav({ } ]; + if (hasInvitations) { + navItems.push({ + title: "Invitations", + href: `/{orgId}/settings/access/invitations` + }); + } + return ( <> - + {children} - + ); } diff --git a/src/app/[orgId]/settings/access/invitations/InvitationsDataTable.tsx b/src/app/[orgId]/settings/access/invitations/InvitationsDataTable.tsx index 0884a279..e2154b2d 100644 --- a/src/app/[orgId]/settings/access/invitations/InvitationsDataTable.tsx +++ b/src/app/[orgId]/settings/access/invitations/InvitationsDataTable.tsx @@ -2,21 +2,8 @@ import { ColumnDef, - flexRender, - getCoreRowModel, - useReactTable, - getPaginationRowModel } from "@tanstack/react-table"; -import { - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableHeader, - TableRow -} from "@/components/ui/table"; -import { DataTablePagination } from "@app/components/DataTablePagination"; +import { DataTable } from "@app/components/ui/data-table"; interface DataTableProps { columns: ColumnDef[]; @@ -27,70 +14,13 @@ export function InvitationsDataTable({ columns, data }: DataTableProps) { - const table = useReactTable({ - data, - columns, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - initialState: { - pagination: { - pageSize: 20, - pageIndex: 0 - } - } - }); - return ( -
- - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ))} - - ))} - - - {table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - )) - ) : ( - - - No invitations found. - - - )} - -
-
-
- -
-
+ ); } diff --git a/src/app/[orgId]/settings/access/roles/RolesDataTable.tsx b/src/app/[orgId]/settings/access/roles/RolesDataTable.tsx index e4e0fb9c..93ddd1cc 100644 --- a/src/app/[orgId]/settings/access/roles/RolesDataTable.tsx +++ b/src/app/[orgId]/settings/access/roles/RolesDataTable.tsx @@ -2,149 +2,29 @@ import { ColumnDef, - flexRender, - getCoreRowModel, - useReactTable, - getPaginationRowModel, - SortingState, - getSortedRowModel, - ColumnFiltersState, - getFilteredRowModel } from "@tanstack/react-table"; -import { - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableHeader, - TableRow -} from "@/components/ui/table"; -import { Button } from "@app/components/ui/button"; -import { useState } from "react"; -import { Input } from "@app/components/ui/input"; -import { Plus, Search } from "lucide-react"; -import { DataTablePagination } from "@app/components/DataTablePagination"; +import { DataTable } from "@app/components/ui/data-table"; interface DataTableProps { columns: ColumnDef[]; data: TData[]; - addRole?: () => void; + createRole?: () => void; } export function RolesDataTable({ - addRole, columns, - data + data, + createRole }: DataTableProps) { - const [sorting, setSorting] = useState([]); - const [columnFilters, setColumnFilters] = useState([]); - const [globalFilter, setGlobalFilter] = useState([]); - - const table = useReactTable({ - data, - columns, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - onSortingChange: setSorting, - getSortedRowModel: getSortedRowModel(), - onColumnFiltersChange: setColumnFilters, - getFilteredRowModel: getFilteredRowModel(), - onGlobalFilterChange: setGlobalFilter, - initialState: { - pagination: { - pageSize: 20, - pageIndex: 0 - } - }, - state: { - sorting, - columnFilters, - globalFilter - } - }); - return ( -
-
-
- - table.setGlobalFilter(String(e.target.value)) - } - className="w-full pl-8" - /> - -
- -
- - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ); - })} - - ))} - - - {table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - )) - ) : ( - - - No roles. Create a role, then add users to - the it. - - - )} - -
-
-
- -
-
+ ); } diff --git a/src/app/[orgId]/settings/access/roles/RolesTable.tsx b/src/app/[orgId]/settings/access/roles/RolesTable.tsx index e8e98265..7ebcfbce 100644 --- a/src/app/[orgId]/settings/access/roles/RolesTable.tsx +++ b/src/app/[orgId]/settings/access/roles/RolesTable.tsx @@ -131,7 +131,7 @@ export default function UsersTable({ roles: r }: RolesTableProps) { { + createRole={() => { setIsCreateModalOpen(true); }} /> diff --git a/src/app/[orgId]/settings/access/roles/page.tsx b/src/app/[orgId]/settings/access/roles/page.tsx index 2548257c..16fefd7d 100644 --- a/src/app/[orgId]/settings/access/roles/page.tsx +++ b/src/app/[orgId]/settings/access/roles/page.tsx @@ -8,6 +8,7 @@ import { ListRolesResponse } from "@server/routers/role"; import RolesTable, { RoleRow } from "./RolesTable"; import { SidebarSettings } from "@app/components/SidebarSettings"; import AccessPageHeaderAndNav from "../AccessPageHeaderAndNav"; +import SettingsSectionTitle from "@app/components/SettingsSectionTitle"; type RolesPageProps = { params: Promise<{ orgId: string }>; @@ -64,11 +65,13 @@ export default async function RolesPage(props: RolesPageProps) { return ( <> - - - - - + + + + ); } diff --git a/src/app/[orgId]/settings/access/users/UsersDataTable.tsx b/src/app/[orgId]/settings/access/users/UsersDataTable.tsx index b47424ba..1ce169e0 100644 --- a/src/app/[orgId]/settings/access/users/UsersDataTable.tsx +++ b/src/app/[orgId]/settings/access/users/UsersDataTable.tsx @@ -2,29 +2,8 @@ import { ColumnDef, - flexRender, - getCoreRowModel, - useReactTable, - getPaginationRowModel, - SortingState, - getSortedRowModel, - ColumnFiltersState, - getFilteredRowModel } from "@tanstack/react-table"; -import { - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableHeader, - TableRow -} from "@/components/ui/table"; -import { Button } from "@app/components/ui/button"; -import { useState } from "react"; -import { Input } from "@app/components/ui/input"; -import { DataTablePagination } from "@app/components/DataTablePagination"; -import { Plus, Search } from "lucide-react"; +import { DataTable } from "@app/components/ui/data-table"; interface DataTableProps { columns: ColumnDef[]; @@ -33,118 +12,19 @@ interface DataTableProps { } export function UsersDataTable({ - inviteUser, columns, - data + data, + inviteUser }: DataTableProps) { - const [sorting, setSorting] = useState([]); - const [columnFilters, setColumnFilters] = useState([]); - const [globalFilter, setGlobalFilter] = useState([]); - - const table = useReactTable({ - data, - columns, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - onSortingChange: setSorting, - getSortedRowModel: getSortedRowModel(), - onColumnFiltersChange: setColumnFilters, - getFilteredRowModel: getFilteredRowModel(), - onGlobalFilterChange: setGlobalFilter, - initialState: { - pagination: { - pageSize: 20, - pageIndex: 0 - } - }, - state: { - sorting, - columnFilters, - globalFilter - } - }); - return ( -
-
-
- - table.setGlobalFilter(String(e.target.value)) - } - className="w-full pl-8" - /> - -
- -
- - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ); - })} - - ))} - - - {table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - )) - ) : ( - - - No Users. Invite one to share access to - resources. - - - )} - -
-
-
- -
-
+ ); } diff --git a/src/app/[orgId]/settings/access/users/[userId]/layout.tsx b/src/app/[orgId]/settings/access/users/[userId]/layout.tsx index 135c47a3..1419de92 100644 --- a/src/app/[orgId]/settings/access/users/[userId]/layout.tsx +++ b/src/app/[orgId]/settings/access/users/[userId]/layout.tsx @@ -2,17 +2,16 @@ import { internal } from "@app/lib/api"; import { AxiosResponse } from "axios"; import { redirect } from "next/navigation"; import { authCookieHeader } from "@app/lib/api/cookies"; -import { SidebarSettings } from "@app/components/SidebarSettings"; import { GetOrgUserResponse } from "@server/routers/user"; import OrgUserProvider from "@app/providers/OrgUserProvider"; +import { HorizontalTabs } from "@app/components/HorizontalTabs"; import { Breadcrumb, BreadcrumbItem, - BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator -} from "@/components/ui/breadcrumb"; +} from "@app/components/ui/breadcrumb"; import Link from "next/link"; import { cache } from "react"; @@ -40,7 +39,7 @@ export default async function UserLayoutProps(props: UserLayoutProps) { redirect(`/${params.orgId}/settings/sites`); } - const sidebarNavItems = [ + const navItems = [ { title: "Access Controls", href: "/{orgId}/settings/access/users/{userId}/access-controls" @@ -71,11 +70,9 @@ export default async function UserLayoutProps(props: UserLayoutProps) {

Manage user

- + {children} - + ); diff --git a/src/app/[orgId]/settings/access/users/page.tsx b/src/app/[orgId]/settings/access/users/page.tsx index a39a4e3a..8049ff96 100644 --- a/src/app/[orgId]/settings/access/users/page.tsx +++ b/src/app/[orgId]/settings/access/users/page.tsx @@ -9,6 +9,7 @@ import OrgProvider from "@app/providers/OrgProvider"; import UserProvider from "@app/providers/UserProvider"; import { verifySession } from "@app/lib/auth/verifySession"; import AccessPageHeaderAndNav from "../AccessPageHeaderAndNav"; +import SettingsSectionTitle from "@app/components/SettingsSectionTitle"; type UsersPageProps = { params: Promise<{ orgId: string }>; @@ -78,13 +79,15 @@ export default async function UsersPage(props: UsersPageProps) { return ( <> - - - - - - - + + + + + + ); } diff --git a/src/app/[orgId]/settings/general/layout.tsx b/src/app/[orgId]/settings/general/layout.tsx index 4b41b8c3..a2d9cc0a 100644 --- a/src/app/[orgId]/settings/general/layout.tsx +++ b/src/app/[orgId]/settings/general/layout.tsx @@ -1,7 +1,7 @@ import { internal } from "@app/lib/api"; import { authCookieHeader } from "@app/lib/api/cookies"; import SettingsSectionTitle from "@app/components/SettingsSectionTitle"; -import { SidebarSettings } from "@app/components/SidebarSettings"; +import { HorizontalTabs } from "@app/components/HorizontalTabs"; import { verifySession } from "@app/lib/auth/verifySession"; import OrgProvider from "@app/providers/OrgProvider"; import OrgUserProvider from "@app/providers/OrgUserProvider"; @@ -57,7 +57,7 @@ export default async function GeneralSettingsPage({ redirect(`/${orgId}`); } - const sidebarNavItems = [ + const navItems = [ { title: "General", href: `/{orgId}/settings/general`, @@ -73,9 +73,9 @@ export default async function GeneralSettingsPage({ description="Configure your organization's general settings" /> - + {children} - + diff --git a/src/app/[orgId]/settings/layout.tsx b/src/app/[orgId]/settings/layout.tsx index 2618c1fb..bd5e8bf1 100644 --- a/src/app/[orgId]/settings/layout.tsx +++ b/src/app/[orgId]/settings/layout.tsx @@ -1,5 +1,4 @@ import { Metadata } from "next"; -import { TopbarNav } from "@app/components/TopbarNav"; import { Cog, Combine, @@ -8,7 +7,6 @@ import { Users, Waypoints } from "lucide-react"; -import { Header } from "@app/components/Header"; import { verifySession } from "@app/lib/auth/verifySession"; import { redirect } from "next/navigation"; import { internal } from "@app/lib/api"; @@ -18,14 +16,7 @@ import { authCookieHeader } from "@app/lib/api/cookies"; import { cache } from "react"; import { GetOrgUserResponse } from "@server/routers/user"; import UserProvider from "@app/providers/UserProvider"; -import { - Breadcrumb, - BreadcrumbItem, - BreadcrumbList, - BreadcrumbPage, - BreadcrumbSeparator -} from "@app/components/ui/breadcrumb"; -import Link from "next/link"; +import { Layout } from "@app/components/Layout"; export const dynamic = "force-dynamic"; @@ -34,7 +25,7 @@ export const metadata: Metadata = { description: "" }; -const topNavItems = [ +const navItems = [ { title: "Sites", href: "/{orgId}/settings/sites", @@ -46,9 +37,19 @@ const topNavItems = [ icon: }, { - title: "Users & Roles", + title: "Access Control", href: "/{orgId}/settings/access", - icon: + icon: , + children: [ + { + title: "Users", + href: "/{orgId}/settings/access/users" + }, + { + title: "Roles", + href: "/{orgId}/settings/access/roles" + } + ] }, { title: "Shareable Links", @@ -109,21 +110,10 @@ export default async function SettingsLayout(props: SettingsLayoutProps) { } catch (e) {} return ( - <> -
-
-
- -
- -
- -
-
- -
+ + {children} -
- + + ); } diff --git a/src/app/[orgId]/settings/resources/ResourcesDataTable.tsx b/src/app/[orgId]/settings/resources/ResourcesDataTable.tsx index 9cc0f79f..a9db3e79 100644 --- a/src/app/[orgId]/settings/resources/ResourcesDataTable.tsx +++ b/src/app/[orgId]/settings/resources/ResourcesDataTable.tsx @@ -2,149 +2,29 @@ import { ColumnDef, - flexRender, - getCoreRowModel, - useReactTable, - getPaginationRowModel, - SortingState, - getSortedRowModel, - ColumnFiltersState, - getFilteredRowModel } from "@tanstack/react-table"; +import { DataTable } from "@app/components/ui/data-table"; -import { - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableHeader, - TableRow -} from "@/components/ui/table"; -import { Button } from "@app/components/ui/button"; -import { useState } from "react"; -import { Input } from "@app/components/ui/input"; -import { DataTablePagination } from "@app/components/DataTablePagination"; -import { Plus, Search } from "lucide-react"; - -interface ResourcesDataTableProps { +interface DataTableProps { columns: ColumnDef[]; data: TData[]; - addResource?: () => void; + createResource?: () => void; } export function ResourcesDataTable({ - addResource, columns, - data -}: ResourcesDataTableProps) { - const [sorting, setSorting] = useState([]); - const [columnFilters, setColumnFilters] = useState([]); - const [globalFilter, setGlobalFilter] = useState([]); - - const table = useReactTable({ - data, - columns, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - onSortingChange: setSorting, - getSortedRowModel: getSortedRowModel(), - onColumnFiltersChange: setColumnFilters, - getFilteredRowModel: getFilteredRowModel(), - onGlobalFilterChange: setGlobalFilter, - initialState: { - pagination: { - pageSize: 20, - pageIndex: 0 - } - }, - state: { - sorting, - columnFilters, - globalFilter - } - }); - + data, + createResource +}: DataTableProps) { return ( -
-
-
- - table.setGlobalFilter(String(e.target.value)) - } - className="w-full pl-8" - /> - -
- -
- - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ); - })} - - ))} - - - {table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - )) - ) : ( - - - No resources. Create one to get started. - - - )} - -
-
-
- -
-
+ ); } diff --git a/src/app/[orgId]/settings/resources/ResourcesTable.tsx b/src/app/[orgId]/settings/resources/ResourcesTable.tsx index 63a2b416..fa83a761 100644 --- a/src/app/[orgId]/settings/resources/ResourcesTable.tsx +++ b/src/app/[orgId]/settings/resources/ResourcesTable.tsx @@ -327,7 +327,7 @@ export default function SitesTable({ resources, orgId }: ResourcesTableProps) { { + createResource={() => { setIsCreateModalOpen(true); }} /> diff --git a/src/app/[orgId]/settings/resources/[resourceId]/layout.tsx b/src/app/[orgId]/settings/resources/[resourceId]/layout.tsx index af335c42..2c5983a5 100644 --- a/src/app/[orgId]/settings/resources/[resourceId]/layout.tsx +++ b/src/app/[orgId]/settings/resources/[resourceId]/layout.tsx @@ -7,7 +7,7 @@ import { import { AxiosResponse } from "axios"; import { redirect } from "next/navigation"; import { authCookieHeader } from "@app/lib/api/cookies"; -import { SidebarSettings } from "@app/components/SidebarSettings"; +import { HorizontalTabs } from "@app/components/HorizontalTabs"; import SettingsSectionTitle from "@app/components/SettingsSectionTitle"; import { GetOrgResponse } from "@server/routers/org"; import OrgProvider from "@app/providers/OrgProvider"; @@ -80,29 +80,25 @@ export default async function ResourceLayout(props: ResourceLayoutProps) { redirect(`/${params.orgId}/settings/resources`); } - const sidebarNavItems = [ + const navItems = [ { title: "General", href: `/{orgId}/settings/resources/{resourceId}/general` - // icon: , }, { title: "Connectivity", href: `/{orgId}/settings/resources/{resourceId}/connectivity` - // icon: , } ]; if (resource.http) { - sidebarNavItems.push({ + navItems.push({ title: "Authentication", href: `/{orgId}/settings/resources/{resourceId}/authentication` - // icon: , }); - sidebarNavItems.push({ + navItems.push({ title: "Rules", href: `/{orgId}/settings/resources/{resourceId}/rules` - // icon: , }); } @@ -129,10 +125,12 @@ export default async function ResourceLayout(props: ResourceLayoutProps) { - +
- {children} - + + {children} + +
diff --git a/src/app/[orgId]/settings/resources/page.tsx b/src/app/[orgId]/settings/resources/page.tsx index 496ce2a3..40f6296e 100644 --- a/src/app/[orgId]/settings/resources/page.tsx +++ b/src/app/[orgId]/settings/resources/page.tsx @@ -70,7 +70,7 @@ export default async function ResourcesPage(props: ResourcesPageProps) { return ( <> - + {/* */} { +interface DataTableProps { columns: ColumnDef[]; data: TData[]; - addShareLink?: () => void; + createShareLink?: () => void; } export function ShareLinksDataTable({ - addShareLink, columns, - data -}: ShareLinksDataTableProps) { - const [sorting, setSorting] = useState([]); - const [columnFilters, setColumnFilters] = useState([]); - const [globalFilter, setGlobalFilter] = useState([]); - - const table = useReactTable({ - data, - columns, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - onSortingChange: setSorting, - getSortedRowModel: getSortedRowModel(), - onColumnFiltersChange: setColumnFilters, - getFilteredRowModel: getFilteredRowModel(), - onGlobalFilterChange: setGlobalFilter, - initialState: { - pagination: { - pageSize: 20, - pageIndex: 0 - } - }, - state: { - sorting, - columnFilters, - globalFilter - } - }); - + data, + createShareLink +}: DataTableProps) { return ( -
-
-
- - table.setGlobalFilter(String(e.target.value)) - } - className="w-full pl-8" - /> - -
- -
- - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ); - })} - - ))} - - - {table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - )) - ) : ( - - - No links. Create one to get started. - - - )} - -
-
-
- -
-
+ ); } diff --git a/src/app/[orgId]/settings/share-links/ShareLinksTable.tsx b/src/app/[orgId]/settings/share-links/ShareLinksTable.tsx index 7d19b2b6..69c88cf7 100644 --- a/src/app/[orgId]/settings/share-links/ShareLinksTable.tsx +++ b/src/app/[orgId]/settings/share-links/ShareLinksTable.tsx @@ -306,7 +306,7 @@ export default function ShareLinksTable({ { + createShareLink={() => { setIsCreateModalOpen(true); }} /> diff --git a/src/app/[orgId]/settings/share-links/page.tsx b/src/app/[orgId]/settings/share-links/page.tsx index e09a6b54..0bfa023d 100644 --- a/src/app/[orgId]/settings/share-links/page.tsx +++ b/src/app/[orgId]/settings/share-links/page.tsx @@ -53,7 +53,7 @@ export default async function ShareLinksPage(props: ShareLinksPageProps) { return ( <> - + {/* */} { columns: ColumnDef[]; data: TData[]; - addSite?: () => void; + createSite?: () => void; } export function SitesDataTable({ - addSite, columns, - data + data, + createSite }: DataTableProps) { - const [sorting, setSorting] = useState([]); - const [columnFilters, setColumnFilters] = useState([]); - const [globalFilter, setGlobalFilter] = useState([]); - - const table = useReactTable({ - data, - columns, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - onSortingChange: setSorting, - getSortedRowModel: getSortedRowModel(), - onColumnFiltersChange: setColumnFilters, - getFilteredRowModel: getFilteredRowModel(), - onGlobalFilterChange: setGlobalFilter, - initialState: { - pagination: { - pageSize: 20, - pageIndex: 0 - } - }, - state: { - sorting, - columnFilters, - globalFilter - } - }); - return ( -
-
-
- - table.setGlobalFilter(String(e.target.value)) - } - className="w-full pl-8" - /> - -
- -
- - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ); - })} - - ))} - - - {table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - )) - ) : ( - - - No sites. Create one to get started. - - - )} - -
-
-
- -
-
+ ); } diff --git a/src/app/[orgId]/settings/sites/SitesTable.tsx b/src/app/[orgId]/settings/sites/SitesTable.tsx index 43ae82a1..801cb909 100644 --- a/src/app/[orgId]/settings/sites/SitesTable.tsx +++ b/src/app/[orgId]/settings/sites/SitesTable.tsx @@ -47,7 +47,6 @@ type SitesTableProps = { export default function SitesTable({ sites, orgId }: SitesTableProps) { const router = useRouter(); - const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [selectedSite, setSelectedSite] = useState(null); const [rows, setRows] = useState(sites); @@ -281,58 +280,20 @@ export default function SitesTable({ sites, orgId }: SitesTableProps) { return ( <> - { - setRows([val, ...rows]); - }} - orgId={orgId} - /> - {selectedSite && ( { - setIsDeleteModalOpen(val); - setSelectedSite(null); - }} - dialog={ -
-

- Are you sure you want to remove the site{" "} - {selectedSite?.name || selectedSite?.id}{" "} - from the organization? -

- -

- Once removed, the site will no longer be - accessible.{" "} - - All resources and targets associated with - the site will also be removed. - -

- -

- To confirm, please type the name of the site - below. -

-
- } - buttonText="Confirm Delete Site" - onConfirm={async () => deleteSite(selectedSite!.id)} - string={selectedSite.name} + setOpen={setIsDeleteModalOpen} + onConfirm={() => deleteSite(selectedSite.id)} title="Delete Site" + description="Are you sure you want to delete this site? This action cannot be undone." /> )} { - router.push(`/${orgId}/settings/sites/create`); - }} + createSite={() => router.push(`/${orgId}/settings/sites/create`)} /> ); diff --git a/src/app/[orgId]/settings/sites/[niceId]/layout.tsx b/src/app/[orgId]/settings/sites/[niceId]/layout.tsx index 6b6a58e2..b5b10b7e 100644 --- a/src/app/[orgId]/settings/sites/[niceId]/layout.tsx +++ b/src/app/[orgId]/settings/sites/[niceId]/layout.tsx @@ -4,7 +4,7 @@ import { GetSiteResponse } from "@server/routers/site"; import { AxiosResponse } from "axios"; import { redirect } from "next/navigation"; import { authCookieHeader } from "@app/lib/api/cookies"; -import { SidebarSettings } from "@app/components/SidebarSettings"; +import { HorizontalTabs } from "@app/components/HorizontalTabs"; import Link from "next/link"; import { ArrowLeft } from "lucide-react"; import SettingsSectionTitle from "@app/components/SettingsSectionTitle"; @@ -38,7 +38,7 @@ export default async function SettingsLayout(props: SettingsLayoutProps) { redirect(`/${params.orgId}/settings/sites`); } - const sidebarNavItems = [ + const navItems = [ { title: "General", href: "/{orgId}/settings/sites/{niceId}/general" @@ -46,32 +46,13 @@ export default async function SettingsLayout(props: SettingsLayoutProps) { ]; return ( - <> -
- - - - Sites - - - - {site.name} - - - -
- - - - - - + +
+ + {children} - - - + +
+
); } diff --git a/src/app/[orgId]/settings/sites/page.tsx b/src/app/[orgId]/settings/sites/page.tsx index f3fa4957..917a74a3 100644 --- a/src/app/[orgId]/settings/sites/page.tsx +++ b/src/app/[orgId]/settings/sites/page.tsx @@ -51,7 +51,7 @@ export default async function SitesPage(props: SitesPageProps) { return ( <> - + {/* */} -
-
-
- -
- -
- -
-
- -
+ + {props.children} -
- + + ); } diff --git a/src/app/admin/users/AdminUsersDataTable.tsx b/src/app/admin/users/AdminUsersDataTable.tsx index b125c539..7532a8cc 100644 --- a/src/app/admin/users/AdminUsersDataTable.tsx +++ b/src/app/admin/users/AdminUsersDataTable.tsx @@ -2,29 +2,8 @@ import { ColumnDef, - flexRender, - getCoreRowModel, - useReactTable, - getPaginationRowModel, - SortingState, - getSortedRowModel, - ColumnFiltersState, - getFilteredRowModel } from "@tanstack/react-table"; - -import { - Table, - TableBody, - TableCell, - TableContainer, - TableHead, - TableHeader, - TableRow -} from "@/components/ui/table"; -import { useState } from "react"; -import { Input } from "@app/components/ui/input"; -import { DataTablePagination } from "@app/components/DataTablePagination"; -import { Search } from "lucide-react"; +import { DataTable } from "@app/components/ui/data-table"; interface DataTableProps { columns: ColumnDef[]; @@ -35,107 +14,13 @@ export function UsersDataTable({ columns, data }: DataTableProps) { - const [sorting, setSorting] = useState([]); - const [columnFilters, setColumnFilters] = useState([]); - - const table = useReactTable({ - data, - columns, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - onSortingChange: setSorting, - getSortedRowModel: getSortedRowModel(), - onColumnFiltersChange: setColumnFilters, - getFilteredRowModel: getFilteredRowModel(), - initialState: { - pagination: { - pageSize: 20, - pageIndex: 0 - } - }, - state: { - sorting, - columnFilters - } - }); - return ( -
-
-
- - table - .getColumn("name") - ?.setFilterValue(event.target.value) - } - className="w-full pl-8" - /> - -
-
- - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef - .header, - header.getContext() - )} - - ); - })} - - ))} - - - {table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - )) - ) : ( - - - This server has no users. - - - )} - -
-
-
- -
-
+ ); } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 53810c18..c8144c6c 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -41,8 +41,6 @@ export default async function RootLayout({ supporterData.visible = res.data.data.visible; supporterData.tier = res.data.data.tier; - const version = env.app.version; - return ( @@ -55,72 +53,11 @@ export default async function RootLayout({ {/* Main content */} -
- {children} -
- - {/* Footer */} - +
diff --git a/src/components/Breadcrumbs.tsx b/src/components/Breadcrumbs.tsx new file mode 100644 index 00000000..bec0973f --- /dev/null +++ b/src/components/Breadcrumbs.tsx @@ -0,0 +1,72 @@ +"use client"; + +import { usePathname } from "next/navigation"; +import Link from "next/link"; +import { ChevronRight } from "lucide-react"; +import { cn } from "@app/lib/cn"; + +interface BreadcrumbItem { + label: string; + href: string; +} + +export function Breadcrumbs() { + const pathname = usePathname(); + const segments = pathname.split("/").filter(Boolean); + + const breadcrumbs: BreadcrumbItem[] = segments.map((segment, index) => { + const href = `/${segments.slice(0, index + 1).join("/")}`; + let label = segment; + + // Format labels + if (segment === "settings") { + label = "Settings"; + } else if (segment === "sites") { + label = "Sites"; + } else if (segment === "resources") { + label = "Resources"; + } else if (segment === "access") { + label = "Users & Roles"; + } else if (segment === "general") { + label = "General"; + } else if (segment === "share-links") { + label = "Shareable Links"; + } else if (segment === "users") { + label = "Users"; + } else if (segment === "roles") { + label = "Roles"; + } else if (segment === "invitations") { + label = "Invitations"; + } else if (segment === "connectivity") { + label = "Connectivity"; + } else if (segment === "authentication") { + label = "Authentication"; + } + + return { label, href }; + }); + + return ( +
+ +
+ ); +} \ No newline at end of file diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 8b6e9ad2..6c0fc65a 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,160 +1,22 @@ "use client"; -import { Button } from "@app/components/ui/button"; -import { - Command, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, - CommandSeparator -} from "@app/components/ui/command"; -import { - Popover, - PopoverContent, - PopoverTrigger -} from "@app/components/ui/popover"; -import { useEnvContext } from "@app/hooks/useEnvContext"; -import { cn } from "@app/lib/cn"; -import { ListOrgsResponse } from "@server/routers/org"; -import { Check, ChevronsUpDown, Plus } from "lucide-react"; import Link from "next/link"; -import { useRouter } from "next/navigation"; -import { useState } from "react"; -import { useUserContext } from "@app/hooks/useUserContext"; -import ProfileIcon from "./ProfileIcon"; -import SupporterStatus from "./SupporterStatus"; +import { useEnvContext } from "@app/hooks/useEnvContext"; -type HeaderProps = { +interface HeaderProps { orgId?: string; - orgs?: ListOrgsResponse["orgs"]; -}; + orgs?: any; +} export function Header({ orgId, orgs }: HeaderProps) { - const { user, updateUser } = useUserContext(); - - const [open, setOpen] = useState(false); - - const router = useRouter(); - const { env } = useEnvContext(); return ( - <> -
- - -
-
-
- - Documentation - - - Support - -
-
- - {orgs && ( - - - - - - - - - No organizations found. - - {(!env.flags.disableUserCreateOrg || - user.serverAdmin) && ( - <> - - - { - router.push( - "/setup" - ); - }} - > - - New Organization - - - - - - )} - - - {orgs.map((org) => ( - { - router.push( - `/${org.orgId}/settings` - ); - }} - > - - {org.name} - - ))} - - - - - - )} -
-
- +
+ + Pangolin + +
); } diff --git a/src/components/HorizontalTabs.tsx b/src/components/HorizontalTabs.tsx new file mode 100644 index 00000000..f79b6fc8 --- /dev/null +++ b/src/components/HorizontalTabs.tsx @@ -0,0 +1,74 @@ +"use client"; + +import React from "react"; +import Link from "next/link"; +import { useParams, usePathname } from "next/navigation"; +import { cn } from "@app/lib/cn"; +import { buttonVariants } from "@/components/ui/button"; + +interface HorizontalTabsProps { + children: React.ReactNode; + items: Array<{ + title: string; + href: string; + icon?: React.ReactNode; + }>; + disabled?: boolean; +} + +export function HorizontalTabs({ + children, + items, + disabled = false +}: HorizontalTabsProps) { + const pathname = usePathname(); + const params = useParams(); + + function hydrateHref(href: string) { + return href.replace("{orgId}", params.orgId as string); + } + + return ( +
+
+
+
+ {items.map((item) => { + const hydratedHref = hydrateHref(item.href); + const isActive = pathname.startsWith(hydratedHref) && !pathname.includes("create"); + + return ( + e.preventDefault() : undefined} + tabIndex={disabled ? -1 : undefined} + aria-disabled={disabled} + > + {item.icon ? ( +
+ {item.icon} + {item.title} +
+ ) : ( + item.title + )} + + ); + })} +
+
+
+
+ {children} +
+
+ ); +} \ No newline at end of file diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx new file mode 100644 index 00000000..9c327019 --- /dev/null +++ b/src/components/Layout.tsx @@ -0,0 +1,107 @@ +"use client"; + +import React, { useState } from "react"; +import { Header } from "@app/components/Header"; +import { SidebarNav } from "@app/components/SidebarNav"; +import { TopBar } from "@app/components/TopBar"; +import { OrgSelector } from "@app/components/OrgSelector"; +import { cn } from "@app/lib/cn"; +import { ListOrgsResponse } from "@server/routers/org"; +import SupporterStatus from "@app/components/SupporterStatus"; +import { Separator } from "@app/components/ui/separator"; +import { Button } from "@app/components/ui/button"; +import { Menu, X } from "lucide-react"; +import { Sheet, SheetContent, SheetTrigger, SheetTitle, SheetDescription } from "@app/components/ui/sheet"; +import { useEnvContext } from "@app/hooks/useEnvContext"; +import { Breadcrumbs } from "@app/components/Breadcrumbs"; + +interface LayoutProps { + children: React.ReactNode; + orgId?: string; + orgs?: ListOrgsResponse["orgs"]; + navItems: Array<{ + title: string; + href: string; + icon?: React.ReactNode; + children?: Array<{ + title: string; + href: string; + icon?: React.ReactNode; + }>; + }>; +} + +export function Layout({ children, orgId, orgs, navItems }: LayoutProps) { + const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false); + const { env } = useEnvContext(); + + return ( +
+ {/* Mobile Menu Button */} +
+ + + + + + Navigation Menu + + Main navigation menu for the application + +
+
+
+
+ +
+
+ + + {env?.app?.version && ( +
+ v{env.app.version} +
+ )} +
+
+
+
+ + {/* Desktop Sidebar */} +
+
+
+
+
+ +
+
+ + + {env?.app?.version && ( +
+ v{env.app.version} +
+ )} +
+
+ + {/* Main content */} +
+
+
+ +
+
+ +
+
+ {children} +
+
+
+
+ ); +} diff --git a/src/components/OrgSelector.tsx b/src/components/OrgSelector.tsx new file mode 100644 index 00000000..c6a66725 --- /dev/null +++ b/src/components/OrgSelector.tsx @@ -0,0 +1,124 @@ +"use client"; + +import { Button } from "@app/components/ui/button"; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + CommandSeparator +} from "@app/components/ui/command"; +import { + Popover, + PopoverContent, + PopoverTrigger +} from "@app/components/ui/popover"; +import { useEnvContext } from "@app/hooks/useEnvContext"; +import { cn } from "@app/lib/cn"; +import { ListOrgsResponse } from "@server/routers/org"; +import { Check, ChevronsUpDown, Plus } from "lucide-react"; +import { useRouter } from "next/navigation"; +import { useState } from "react"; +import { useUserContext } from "@app/hooks/useUserContext"; + +interface OrgSelectorProps { + orgId?: string; + orgs?: ListOrgsResponse["orgs"]; +} + +export function OrgSelector({ orgId, orgs }: OrgSelectorProps) { + const { user } = useUserContext(); + const [open, setOpen] = useState(false); + const router = useRouter(); + const { env } = useEnvContext(); + + return ( + + + + + + + + + No organizations found. + + {(!env.flags.disableUserCreateOrg || + user.serverAdmin) && ( + <> + + + { + router.push( + "/setup" + ); + }} + > + + New Organization + + + + + + )} + + + {orgs?.map((org) => ( + { + router.push( + `/${org.orgId}/settings` + ); + }} + > + + {org.name} + + ))} + + + + + + ); +} \ No newline at end of file diff --git a/src/components/ProfileIcon.tsx b/src/components/ProfileIcon.tsx index b8d13d7a..39f89377 100644 --- a/src/components/ProfileIcon.tsx +++ b/src/components/ProfileIcon.tsx @@ -66,7 +66,10 @@ export default function ProfileIcon() { -
+
+ + {user.email} +
); diff --git a/src/components/SidebarNav.tsx b/src/components/SidebarNav.tsx index 20ef5bd1..318a8091 100644 --- a/src/components/SidebarNav.tsx +++ b/src/components/SidebarNav.tsx @@ -1,17 +1,9 @@ "use client"; -import React, { useEffect } from "react"; +import React from "react"; import Link from "next/link"; -import { useParams, usePathname, useRouter } from "next/navigation"; +import { useParams, usePathname } from "next/navigation"; import { cn } from "@app/lib/cn"; -import { buttonVariants } from "@/components/ui/button"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue -} from "@/components/ui/select"; import { CornerDownRight } from "lucide-react"; interface SidebarNavItem { @@ -39,43 +31,6 @@ export function SidebarNav({ const resourceId = params.resourceId as string; const userId = params.userId as string; - const [selectedValue, setSelectedValue] = - React.useState(getSelectedValue()); - - useEffect(() => { - setSelectedValue(getSelectedValue()); - }, [usePathname()]); - - const router = useRouter(); - - const handleSelectChange = (value: string) => { - if (!disabled) { - router.push(value); - } - }; - - function getSelectedValue() { - let foundHref = ""; - for (const item of items) { - const hydratedHref = hydrateHref(item.href); - if (hydratedHref === pathname) { - foundHref = hydratedHref; - break; - } - if (item.children) { - for (const child of item.children) { - const hydratedChildHref = hydrateHref(child.href); - if (hydratedChildHref === pathname) { - foundHref = hydratedChildHref; - break; - } - } - } - if (foundHref) break; - } - return foundHref; - } - function hydrateHref(val: string): string { return val .replace("{orgId}", orgId) @@ -85,142 +40,72 @@ export function SidebarNav({ } function renderItems(items: SidebarNavItem[]) { - return items.map((item) => ( -
- e.preventDefault() : undefined} - tabIndex={disabled ? -1 : undefined} - aria-disabled={disabled} - > - {item.icon ? ( -
- {item.icon} - {item.title} + return items.map((item) => { + const hydratedHref = hydrateHref(item.href); + const isActive = pathname.startsWith(hydratedHref) && !pathname.includes("create"); + + return ( +
+ e.preventDefault() : undefined} + tabIndex={disabled ? -1 : undefined} + aria-disabled={disabled} + > + {item.icon && {item.icon}} + {item.title} + + {item.children && ( +
+ {item.children.map((child) => { + const hydratedChildHref = hydrateHref(child.href); + const isChildActive = pathname.startsWith(hydratedChildHref) && !pathname.includes("create"); + + return ( + e.preventDefault() : undefined} + tabIndex={disabled ? -1 : undefined} + aria-disabled={disabled} + > + + {child.icon && {child.icon}} + {child.title} + + ); + })}
- ) : ( - item.title )} - - {item.children && ( -
- {item.children.map((child) => ( -
- e.preventDefault() - : undefined - } - tabIndex={disabled ? -1 : undefined} - aria-disabled={disabled} - > - - {child.icon ? ( -
- {child.icon} - {child.title} -
- ) : ( - child.title - )} - -
- ))} -
- )} -
- )); +
+ ); + }); } return ( -
-
- -
- -
+ ); } diff --git a/src/components/SupporterStatus.tsx b/src/components/SupporterStatus.tsx index a08fdf77..baeeb545 100644 --- a/src/components/SupporterStatus.tsx +++ b/src/components/SupporterStatus.tsx @@ -419,7 +419,7 @@ export default function SupporterStatus() { + )} + + + + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext() + )} + + ))} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext() + )} + + ))} + + )) + ) : ( + + + No results found. + + + )} + +
+
+ +
+
+ +
+ ); +} diff --git a/src/components/ui/table.tsx b/src/components/ui/table.tsx index fad6b864..c85b3b97 100644 --- a/src/components/ui/table.tsx +++ b/src/components/ui/table.tsx @@ -23,30 +23,24 @@ const Table = (
) Table.displayName = "Table" -const TableHeader = ( - { - ref, - className, - ...props - }: React.HTMLAttributes & { - ref: React.RefObject; - } -) => () +const TableHeader = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) TableHeader.displayName = "TableHeader" -const TableBody = ( - { - ref, - className, - ...props - }: React.HTMLAttributes & { - ref: React.RefObject; - } -) => () +const TableBody = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) TableBody.displayName = "TableBody" const TableFooter = ( @@ -67,55 +61,49 @@ const TableFooter = ( />) TableFooter.displayName = "TableFooter" -const TableRow = ( - { - ref, - className, - ...props - }: React.HTMLAttributes & { - ref: React.RefObject; - } -) => () +const TableRow = React.forwardRef< + HTMLTableRowElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) TableRow.displayName = "TableRow" -const TableHead = ( - { - ref, - className, - ...props - }: React.ThHTMLAttributes & { - ref: React.RefObject; - } -) => () +const TableHead = React.forwardRef< + HTMLTableCellElement, + React.ThHTMLAttributes +>(({ className, ...props }, ref) => ( + [role=checkbox]]:translate-y-[2px]", + className + )} + {...props} + /> +)) TableHead.displayName = "TableHead" -const TableCell = ( - { - ref, - className, - ...props - }: React.TdHTMLAttributes & { - ref: React.RefObject; - } -) => () +const TableCell = React.forwardRef< + HTMLTableCellElement, + React.TdHTMLAttributes +>(({ className, ...props }, ref) => ( + [role=checkbox]]:translate-y-[2px]", + className + )} + {...props} + /> +)) TableCell.displayName = "TableCell" const TableCaption = ( diff --git a/tsconfig.json b/tsconfig.json index 94729399..85c0e6f5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,7 +17,8 @@ "@server/*": ["../server/*"], "@test/*": ["../test/*"], "@app/*": ["*"], - "@/*": ["./*"] + "@/*": ["./*"], + "react": [ "./node_modules/@types/react" ] }, "plugins": [ {