mirror of
https://github.com/fosrl/pangolin.git
synced 2025-08-25 19:55:41 +02:00
- Fix duplicate db import in PostgreSQL migration scripts
- Fix FormLabel syntax in user creation page - Add missing SidebarNavItem type properties (autoExpand, children) - Update SidebarNav component to handle nested navigation - Successfully build both SQLite and PostgreSQL images
This commit is contained in:
parent
a140f27d04
commit
c3a1e082f1
9 changed files with 139 additions and 283 deletions
110
package-lock.json
generated
110
package-lock.json
generated
|
@ -61,7 +61,6 @@
|
||||||
"http-errors": "2.0.0",
|
"http-errors": "2.0.0",
|
||||||
"i": "^0.3.7",
|
"i": "^0.3.7",
|
||||||
"input-otp": "1.4.2",
|
"input-otp": "1.4.2",
|
||||||
"ioredis": "^5.6.1",
|
|
||||||
"jmespath": "^0.16.0",
|
"jmespath": "^0.16.0",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"jsonwebtoken": "^9.0.2",
|
"jsonwebtoken": "^9.0.2",
|
||||||
|
@ -77,7 +76,6 @@
|
||||||
"oslo": "1.2.1",
|
"oslo": "1.2.1",
|
||||||
"pg": "^8.16.2",
|
"pg": "^8.16.2",
|
||||||
"qrcode.react": "4.2.0",
|
"qrcode.react": "4.2.0",
|
||||||
"rate-limit-redis": "^4.2.1",
|
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-dom": "19.1.0",
|
"react-dom": "19.1.0",
|
||||||
"react-easy-sort": "^1.6.0",
|
"react-easy-sort": "^1.6.0",
|
||||||
|
@ -2010,12 +2008,6 @@
|
||||||
"url": "https://opencollective.com/libvips"
|
"url": "https://opencollective.com/libvips"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@ioredis/commands": {
|
|
||||||
"version": "1.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
|
|
||||||
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@isaacs/balanced-match": {
|
"node_modules/@isaacs/balanced-match": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
|
||||||
|
@ -2058,6 +2050,7 @@
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
|
||||||
"integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
|
"integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
|
||||||
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minipass": "^7.0.4"
|
"minipass": "^7.0.4"
|
||||||
|
@ -6309,6 +6302,7 @@
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
|
||||||
"integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
|
"integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
|
||||||
|
"dev": true,
|
||||||
"license": "BlueOak-1.0.0",
|
"license": "BlueOak-1.0.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
|
@ -6455,15 +6449,6 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/cluster-key-slot": {
|
|
||||||
"version": "1.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
|
|
||||||
"integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/cmdk": {
|
"node_modules/cmdk": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz",
|
||||||
|
@ -6947,15 +6932,6 @@
|
||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/denque": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
|
||||||
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=0.10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/depd": {
|
"node_modules/depd": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||||
|
@ -8835,6 +8811,7 @@
|
||||||
"version": "4.2.11",
|
"version": "4.2.11",
|
||||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/graphemer": {
|
"node_modules/graphemer": {
|
||||||
|
@ -9122,30 +9099,6 @@
|
||||||
"tslib": "^2.8.0"
|
"tslib": "^2.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ioredis": {
|
|
||||||
"version": "5.6.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.6.1.tgz",
|
|
||||||
"integrity": "sha512-UxC0Yv1Y4WRJiGQxQkP0hfdL0/5/6YvdfOOClRgJ0qppSarkhneSa6UvkMkms0AkdGimSH3Ikqm+6mkMmX7vGA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@ioredis/commands": "^1.1.1",
|
|
||||||
"cluster-key-slot": "^1.1.0",
|
|
||||||
"debug": "^4.3.4",
|
|
||||||
"denque": "^2.1.0",
|
|
||||||
"lodash.defaults": "^4.2.0",
|
|
||||||
"lodash.isarguments": "^3.1.0",
|
|
||||||
"redis-errors": "^1.2.0",
|
|
||||||
"redis-parser": "^3.0.0",
|
|
||||||
"standard-as-callback": "^2.1.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12.22.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/ioredis"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ipaddr.js": {
|
"node_modules/ipaddr.js": {
|
||||||
"version": "1.9.1",
|
"version": "1.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||||
|
@ -9606,6 +9559,7 @@
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz",
|
||||||
"integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==",
|
"integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==",
|
||||||
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16"
|
"node": ">=16"
|
||||||
|
@ -10112,24 +10066,12 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lodash.defaults": {
|
|
||||||
"version": "4.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
|
||||||
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/lodash.includes": {
|
"node_modules/lodash.includes": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||||
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
|
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/lodash.isarguments": {
|
|
||||||
"version": "3.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
|
||||||
"integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/lodash.isboolean": {
|
"node_modules/lodash.isboolean": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
||||||
|
@ -10481,6 +10423,7 @@
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz",
|
||||||
"integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==",
|
"integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minipass": "^7.1.2"
|
"minipass": "^7.1.2"
|
||||||
|
@ -10493,6 +10436,7 @@
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
|
||||||
"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
|
"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"mkdirp": "dist/cjs/src/bin.js"
|
"mkdirp": "dist/cjs/src/bin.js"
|
||||||
|
@ -14470,18 +14414,6 @@
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rate-limit-redis": {
|
|
||||||
"version": "4.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/rate-limit-redis/-/rate-limit-redis-4.2.1.tgz",
|
|
||||||
"integrity": "sha512-JsUsVmRVI6G/XrlYtfGV1NMCbGS/CVYayHkxD5Ism5FaL8qpFHCXbFkUeIi5WJ/onJOKWCgtB/xtCLa6qSXb4g==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 16"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"express-rate-limit": ">= 6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/raw-body": {
|
"node_modules/raw-body": {
|
||||||
"version": "2.5.2",
|
"version": "2.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
|
||||||
|
@ -14828,27 +14760,6 @@
|
||||||
"node": ">=0.8.8"
|
"node": ">=0.8.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/redis-errors": {
|
|
||||||
"version": "1.2.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
|
||||||
"integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/redis-parser": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"redis-errors": "^1.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/reflect.getprototypeof": {
|
"node_modules/reflect.getprototypeof": {
|
||||||
"version": "1.0.10",
|
"version": "1.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz",
|
||||||
|
@ -15628,12 +15539,6 @@
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/standard-as-callback": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
|
|
||||||
"integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/statuses": {
|
"node_modules/statuses": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||||
|
@ -16021,6 +15926,7 @@
|
||||||
"version": "7.4.3",
|
"version": "7.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
|
||||||
"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
|
"integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
|
||||||
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@isaacs/fs-minipass": "^4.0.0",
|
"@isaacs/fs-minipass": "^4.0.0",
|
||||||
|
@ -16667,6 +16573,7 @@
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz",
|
||||||
"integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==",
|
"integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==",
|
||||||
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"isexe": "^3.1.1"
|
"isexe": "^3.1.1"
|
||||||
|
@ -16972,6 +16879,7 @@
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
|
||||||
"integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
|
"integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
|
||||||
|
"dev": true,
|
||||||
"license": "BlueOak-1.0.0",
|
"license": "BlueOak-1.0.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
|
|
|
@ -22,7 +22,7 @@ export const domains = pgTable("domains", {
|
||||||
export const orgs = pgTable("orgs", {
|
export const orgs = pgTable("orgs", {
|
||||||
orgId: varchar("orgId").primaryKey(),
|
orgId: varchar("orgId").primaryKey(),
|
||||||
name: varchar("name").notNull(),
|
name: varchar("name").notNull(),
|
||||||
passwordResetTokenExpiryHours: integer("passwordResetTokenExpiryHours").notNull().default(1)
|
passwordResetTokenExpiryHours: integer("passwordResetTokenExpiryHours").notNull().default(1),
|
||||||
subnet: varchar("subnet")
|
subnet: varchar("subnet")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ export const domains = sqliteTable("domains", {
|
||||||
export const orgs = sqliteTable("orgs", {
|
export const orgs = sqliteTable("orgs", {
|
||||||
orgId: text("orgId").primaryKey(),
|
orgId: text("orgId").primaryKey(),
|
||||||
name: text("name").notNull(),
|
name: text("name").notNull(),
|
||||||
passwordResetTokenExpiryHours: integer("passwordResetTokenExpiryHours").notNull().default(1)
|
passwordResetTokenExpiryHours: integer("passwordResetTokenExpiryHours").notNull().default(1),
|
||||||
subnet: text("subnet")
|
subnet: text("subnet")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { db } from "@server/db/pg";
|
|
||||||
import { db } from "@server/db/pg/driver";
|
import { db } from "@server/db/pg/driver";
|
||||||
import { sql } from "drizzle-orm";
|
import { sql } from "drizzle-orm";
|
||||||
const version = "1.7.0";
|
const version = "1.7.0";
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { Layout } from "@app/components/Layout";
|
||||||
import { ListUserOrgsResponse } from "@server/routers/org";
|
import { ListUserOrgsResponse } from "@server/routers/org";
|
||||||
import { pullEnv } from "@app/lib/pullEnv";
|
import { pullEnv } from "@app/lib/pullEnv";
|
||||||
import EnvProvider from "@app/providers/EnvProvider";
|
import EnvProvider from "@app/providers/EnvProvider";
|
||||||
|
import { orgLangingNavItems } from "@app/app/navigation";
|
||||||
|
|
||||||
type OrgPageProps = {
|
type OrgPageProps = {
|
||||||
params: Promise<{ orgId: string }>;
|
params: Promise<{ orgId: string }>;
|
||||||
|
@ -38,48 +39,9 @@ export default async function OrgPage(props: OrgPageProps) {
|
||||||
overview = res.data.data;
|
overview = res.data.data;
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
// If user is admin or owner, show the admin landing card and potentially redirect
|
// If user is admin or owner, redirect to settings
|
||||||
if (overview?.isAdmin || overview?.isOwner) {
|
if (overview?.isAdmin || overview?.isOwner) {
|
||||||
let orgs: ListUserOrgsResponse["orgs"] = [];
|
redirect(`/${orgId}/settings`);
|
||||||
try {
|
|
||||||
const getOrgs = cache(async () =>
|
|
||||||
internal.get<AxiosResponse<ListUserOrgsResponse>>(
|
|
||||||
`/user/${user.userId}/orgs`,
|
|
||||||
await authCookieHeader()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
const res = await getOrgs();
|
|
||||||
if (res && res.data.data.orgs) {
|
|
||||||
orgs = res.data.data.orgs;
|
|
||||||
}
|
|
||||||
} catch (e) {}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<UserProvider user={user}>
|
|
||||||
<EnvProvider env={env}>
|
|
||||||
<Layout orgId={orgId} navItems={orgLangingNavItems} orgs={orgs}>
|
|
||||||
{overview && (
|
|
||||||
<div className="w-full max-w-4xl mx-auto md:mt-32 mt-4">
|
|
||||||
<OrganizationLandingCard
|
|
||||||
overview={{
|
|
||||||
orgId: overview.orgId,
|
|
||||||
orgName: overview.orgName,
|
|
||||||
stats: {
|
|
||||||
users: overview.numUsers,
|
|
||||||
sites: overview.numSites,
|
|
||||||
resources: overview.numResources
|
|
||||||
},
|
|
||||||
isAdmin: overview.isAdmin,
|
|
||||||
isOwner: overview.isOwner,
|
|
||||||
userRole: overview.userRoleName
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Layout>
|
|
||||||
</EnvProvider>
|
|
||||||
</UserProvider>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For non-admin users, show the member resources portal
|
// For non-admin users, show the member resources portal
|
||||||
|
@ -101,21 +63,8 @@ export default async function OrgPage(props: OrgPageProps) {
|
||||||
<UserProvider user={user}>
|
<UserProvider user={user}>
|
||||||
<Layout orgId={orgId} navItems={[]} orgs={orgs}>
|
<Layout orgId={orgId} navItems={[]} orgs={orgs}>
|
||||||
{overview && (
|
{overview && (
|
||||||
<div className="w-full max-w-4xl mx-auto md:mt-32 mt-4">
|
<div className="w-full px-4 py-6">
|
||||||
<OrganizationLandingCard
|
<MemberResourcesPortal orgId={orgId} />
|
||||||
overview={{
|
|
||||||
orgId: overview.orgId,
|
|
||||||
orgName: overview.orgName,
|
|
||||||
stats: {
|
|
||||||
users: overview.numUsers,
|
|
||||||
sites: overview.numSites,
|
|
||||||
resources: overview.numResources
|
|
||||||
},
|
|
||||||
isAdmin: overview.isAdmin,
|
|
||||||
isOwner: overview.isOwner,
|
|
||||||
userRole: overview.userRoleName
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
|
@ -676,9 +676,7 @@ export default function Page() {
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{t(
|
{t("nameOptional")}
|
||||||
"emailOptional"
|
|
||||||
)}
|
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
|
@ -698,8 +696,7 @@ export default function Page() {
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
"nameOptional"
|
{t("nameOptional")}
|
||||||
)}
|
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
|
|
|
@ -36,9 +36,6 @@ import {
|
||||||
} from "@app/components/Settings";
|
} from "@app/components/Settings";
|
||||||
import { useUserContext } from "@app/hooks/useUserContext";
|
import { useUserContext } from "@app/hooks/useUserContext";
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
import { AxiosResponse } from "axios";
|
|
||||||
import { DeleteOrgResponse, ListUserOrgsResponse } from "@server/routers/org";
|
|
||||||
import { useRouter } from "next/navigation";
|
|
||||||
import { build } from "@server/build";
|
import { build } from "@server/build";
|
||||||
|
|
||||||
// Updated schema to include subnet field
|
// Updated schema to include subnet field
|
||||||
|
|
|
@ -158,66 +158,74 @@ export default function ResetPasswordForm({
|
||||||
const { password, email, token } = form.getValues();
|
const { password, email, token } = form.getValues();
|
||||||
const { code } = mfaForm.getValues();
|
const { code } = mfaForm.getValues();
|
||||||
|
|
||||||
const res = await api
|
try {
|
||||||
.post<AxiosResponse<ResetPasswordResponse>>(
|
const res = await api
|
||||||
"/auth/reset-password",
|
.post<AxiosResponse<ResetPasswordResponse>>(
|
||||||
{
|
"/auth/reset-password",
|
||||||
email,
|
{
|
||||||
token,
|
email,
|
||||||
newPassword: password,
|
token,
|
||||||
code
|
newPassword: password,
|
||||||
} as ResetPasswordBody
|
code
|
||||||
)
|
} as ResetPasswordBody
|
||||||
.catch((e) => {
|
);
|
||||||
setError(formatAxiosError(e, t('errorOccurred')));
|
|
||||||
console.error(t('passwordErrorReset'), e);
|
|
||||||
setIsSubmitting(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(res);
|
if (res) {
|
||||||
|
setError(null);
|
||||||
|
|
||||||
if (res) {
|
if (res.data.data?.codeRequested) {
|
||||||
setError(null);
|
setState("mfa");
|
||||||
|
setIsSubmitting(false);
|
||||||
if (res.data.data?.codeRequested) {
|
mfaForm.reset();
|
||||||
setState("mfa");
|
|
||||||
setIsSubmitting(false);
|
|
||||||
mfaForm.reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setSuccessMessage(quickstart ? t('accountSetupSuccess') : t('passwordResetSuccess'));
|
|
||||||
|
|
||||||
// Auto-login after successful password reset
|
|
||||||
try {
|
|
||||||
const loginRes = await api.post("/auth/login", {
|
|
||||||
email: form.getValues("email"),
|
|
||||||
password: form.getValues("password")
|
|
||||||
});
|
|
||||||
|
|
||||||
if (loginRes.data.data?.codeRequested) {
|
|
||||||
if (redirect) {
|
|
||||||
router.push(`/auth/login?redirect=${redirect}`);
|
|
||||||
} else {
|
|
||||||
router.push("/auth/login");
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loginRes.data.data?.emailVerificationRequired) {
|
setSuccessMessage(quickstart ? t('accountSetupSuccess') : t('passwordResetSuccess'));
|
||||||
try {
|
|
||||||
await api.post("/auth/verify-email/request");
|
// Auto-login after successful password reset
|
||||||
} catch (verificationError) {
|
try {
|
||||||
console.error("Failed to send verification code:", verificationError);
|
const loginRes = await api.post("/auth/login", {
|
||||||
|
email: form.getValues("email"),
|
||||||
|
password: form.getValues("password")
|
||||||
|
});
|
||||||
|
|
||||||
|
if (loginRes.data.data?.codeRequested) {
|
||||||
|
if (redirect) {
|
||||||
|
router.push(`/auth/login?redirect=${redirect}`);
|
||||||
|
} else {
|
||||||
|
router.push("/auth/login");
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (redirect) {
|
if (loginRes.data.data?.emailVerificationRequired) {
|
||||||
router.push(`/auth/verify-email?redirect=${redirect}`);
|
try {
|
||||||
} else {
|
await api.post("/auth/verify-email/request");
|
||||||
router.push("/auth/verify-email");
|
} catch (verificationError) {
|
||||||
|
console.error("Failed to send verification code:", verificationError);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (redirect) {
|
||||||
|
router.push(`/auth/verify-email?redirect=${redirect}`);
|
||||||
|
} else {
|
||||||
|
router.push("/auth/verify-email");
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
} else {
|
// Login successful, redirect
|
||||||
|
setTimeout(() => {
|
||||||
|
if (redirect) {
|
||||||
|
const safe = cleanRedirect(redirect);
|
||||||
|
router.push(safe);
|
||||||
|
} else {
|
||||||
|
router.push("/");
|
||||||
|
}
|
||||||
|
setIsSubmitting(false);
|
||||||
|
}, 1500);
|
||||||
|
} catch (loginError) {
|
||||||
|
// Auto-login failed, but password reset was successful
|
||||||
|
console.error("Auto-login failed:", loginError);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
const safe = cleanRedirect(redirect);
|
const safe = cleanRedirect(redirect);
|
||||||
|
@ -225,34 +233,14 @@ if (loginRes.data.data?.emailVerificationRequired) {
|
||||||
} else {
|
} else {
|
||||||
router.push("/auth/login");
|
router.push("/auth/login");
|
||||||
}
|
}
|
||||||
}, 0);
|
setIsSubmitting(false);
|
||||||
|
}, 1500);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Login successful, redirect
|
|
||||||
setTimeout(() => {
|
|
||||||
if (redirect) {
|
|
||||||
const safe = cleanRedirect(redirect);
|
|
||||||
router.push(safe);
|
|
||||||
} else {
|
|
||||||
router.push("/");
|
|
||||||
}
|
|
||||||
setIsSubmitting(false);
|
|
||||||
}, 1500);
|
|
||||||
|
|
||||||
} catch (loginError) {
|
|
||||||
// Auto-login failed, but password reset was successful
|
|
||||||
console.error("Auto-login failed:", loginError);
|
|
||||||
setTimeout(() => {
|
|
||||||
if (redirect) {
|
|
||||||
const safe = cleanRedirect(redirect);
|
|
||||||
router.push(safe);
|
|
||||||
} else {
|
|
||||||
router.push("/login");
|
|
||||||
}
|
|
||||||
setIsSubmitting(false);
|
|
||||||
}, 1500);
|
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
setError(formatAxiosError(e, t('errorOccurred')));
|
||||||
|
console.error(t('passwordErrorReset'), e);
|
||||||
|
setIsSubmitting(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@ export type SidebarNavItem = {
|
||||||
title: string;
|
title: string;
|
||||||
icon?: React.ReactNode;
|
icon?: React.ReactNode;
|
||||||
showProfessional?: boolean;
|
showProfessional?: boolean;
|
||||||
|
autoExpand?: boolean;
|
||||||
|
children?: SidebarNavItem[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SidebarNavSection = {
|
export type SidebarNavSection = {
|
||||||
|
@ -76,44 +78,60 @@ export function SidebarNav({
|
||||||
: t(item.title);
|
: t(item.title);
|
||||||
|
|
||||||
const itemContent = (
|
const itemContent = (
|
||||||
<Link
|
<>
|
||||||
href={isDisabled ? "#" : hydratedHref}
|
<Link
|
||||||
className={cn(
|
href={isDisabled ? "#" : hydratedHref}
|
||||||
"flex items-center rounded transition-colors hover:bg-secondary/50 dark:hover:bg-secondary/20 rounded-md",
|
className={cn(
|
||||||
isCollapsed ? "px-2 py-2 justify-center" : "px-3 py-1.5",
|
"flex items-center rounded transition-colors hover:bg-secondary/50 dark:hover:bg-secondary/20 rounded-md",
|
||||||
isActive
|
isCollapsed ? "px-2 py-2 justify-center" : "px-3 py-1.5",
|
||||||
? "text-primary font-medium"
|
isActive
|
||||||
: "text-muted-foreground hover:text-foreground",
|
? "text-primary font-medium"
|
||||||
isDisabled && "cursor-not-allowed opacity-60"
|
: "text-muted-foreground hover:text-foreground",
|
||||||
|
isDisabled && "cursor-not-allowed opacity-60"
|
||||||
|
)}
|
||||||
|
onClick={(e) => {
|
||||||
|
if (isDisabled) {
|
||||||
|
e.preventDefault();
|
||||||
|
} else if (onItemClick) {
|
||||||
|
onItemClick();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
tabIndex={isDisabled ? -1 : undefined}
|
||||||
|
aria-disabled={isDisabled}
|
||||||
|
>
|
||||||
|
{item.icon && (
|
||||||
|
<span
|
||||||
|
className={cn("flex-shrink-0", !isCollapsed && "mr-2")}
|
||||||
|
>
|
||||||
|
{item.icon}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{!isCollapsed && (
|
||||||
|
<>
|
||||||
|
<span>{t(item.title)}</span>
|
||||||
|
{item.showProfessional && !isUnlocked() && (
|
||||||
|
<Badge variant="outlinePrimary" className="ml-2">
|
||||||
|
{t("licenseBadge")}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
|
{!isCollapsed && item.children && (item.autoExpand || isActive) && (
|
||||||
|
<div className="ml-4 mt-1 flex flex-col gap-1">
|
||||||
|
{item.children.map((child) => {
|
||||||
|
const childHref = hydrateHref(child.href);
|
||||||
|
const isChildActive = pathname.startsWith(childHref);
|
||||||
|
return renderNavItem(
|
||||||
|
child,
|
||||||
|
childHref,
|
||||||
|
isChildActive,
|
||||||
|
isDisabled
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
onClick={(e) => {
|
</>
|
||||||
if (isDisabled) {
|
|
||||||
e.preventDefault();
|
|
||||||
} else if (onItemClick) {
|
|
||||||
onItemClick();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
tabIndex={isDisabled ? -1 : undefined}
|
|
||||||
aria-disabled={isDisabled}
|
|
||||||
>
|
|
||||||
{item.icon && (
|
|
||||||
<span
|
|
||||||
className={cn("flex-shrink-0", !isCollapsed && "mr-2")}
|
|
||||||
>
|
|
||||||
{item.icon}
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
{!isCollapsed && (
|
|
||||||
<>
|
|
||||||
<span>{t(item.title)}</span>
|
|
||||||
{item.showProfessional && !isUnlocked() && (
|
|
||||||
<Badge variant="outlinePrimary" className="ml-2">
|
|
||||||
{t("licenseBadge")}
|
|
||||||
</Badge>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</Link>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isCollapsed) {
|
if (isCollapsed) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue