create-bubbles 0.1.26 → 0.1.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/template-vp-monorepo-react-nestjs/.agents/rules//345/205/261/344/272/253/344/273/243/347/240/201.md +2 -2
- package/template-vp-monorepo-react-nestjs/.agents/rules//351/234/200/346/261/202/344/270/216/350/256/276/350/256/241/346/226/207/346/241/243.md +50 -0
- package/template-vp-monorepo-react-nestjs/.codegraph/.gitignore +5 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/PRD.md +121 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/cleanup-empty-preview.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/company-created.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/login-desktop.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/member-role-assigned.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/permission-revoked.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/platform-menu-recovery.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/project-created.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/project-member-home.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/replacement-administrator.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225/ui/workspace-empty.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//345/206/263/347/255/226/350/256/260/345/275/225.md +29 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//345/211/215/347/253/257/344/272/244/346/216/245.md +74 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//345/220/216/347/253/257/346/265/213/350/257/225/346/212/245/345/221/212.md +115 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//346/212/200/346/234/257/345/245/221/347/272/246.md +578 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//346/265/213/350/257/225/346/212/245/345/221/212.md +137 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//346/265/213/350/257/225/350/257/201/346/215/256/browser.json +84 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//346/265/213/350/257/225/350/257/201/346/215/256/http.json +108 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//346/265/213/350/257/225/350/257/201/346/215/256/legacy-http.json +18 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//346/265/213/350/257/225/350/257/201/346/215/256/legacy.json +24 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//350/201/224/350/260/203/350/256/260/345/275/225.md +76 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//350/277/220/350/241/214/350/257/264/346/230/216.md +117 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//346/235/203/351/231/220/344/270/216/350/217/234/345/215/225//351/234/200/346/261/202/346/226/207/346/241/243.md +275 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//347/273/204/347/273/207/346/236/266/346/236/204//345/206/263/347/255/226/350/256/260/345/275/225.md +35 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//347/273/204/347/273/207/346/236/266/346/236/204//346/212/200/346/234/257/345/245/221/347/272/246.md +744 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//347/273/204/347/273/207/346/236/266/346/236/204//346/265/213/350/257/225/346/212/245/345/221/212.md +174 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//347/273/204/347/273/207/346/236/266/346/236/204//350/201/224/350/260/203/350/256/260/345/275/225.md +137 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//347/273/204/347/273/207/346/236/266/346/236/204//350/256/276/350/256/241/346/226/271/346/241/210.md +215 -0
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//347/273/204/347/273/207/346/236/266/346/236/204//351/234/200/346/261/202/346/226/207/346/241/243.md +421 -0
- package/template-vp-monorepo-react-nestjs/.spaces/{server/05./344/270/212/344/274/240/346/224/271/351/200/240/346/226/271/346/241/210/README.md → 02./344/270/212/344/274/240/344/270/216/346/226/207/344/273/266//344/270/212/344/274/240/346/224/271/351/200/240//350/256/276/350/256/241/346/226/271/346/241/210.md} +13 -20
- package/template-vp-monorepo-react-nestjs/.spaces/{server/06./345/205/254/345/205/261/351/230/237/345/210/227/346/216/245/345/205/245/346/226/271/346/241/210//344/270/212/344/274/240/346/270/205/347/220/206.md → 02./344/270/212/344/274/240/344/270/216/346/226/207/344/273/266//344/270/212/344/274/240/346/270/205/347/220/206//350/256/276/350/256/241/346/226/271/346/241/210.md} +13 -8
- package/template-vp-monorepo-react-nestjs/.spaces/{server/04.upload.md → 02./344/270/212/344/274/240/344/270/216/346/226/207/344/273/266//345/210/206/347/211/207/344/270/212/344/274/240//345/256/236/346/226/275/346/225/231/347/250/213.md} +21 -18
- package/template-vp-monorepo-react-nestjs/.spaces/{server/06./345/205/254/345/205/261/351/230/237/345/210/227/346/216/245/345/205/245/346/226/271/346/241/210/README.md → 03./344/273/273/345/212/241/351/230/237/345/210/227//345/205/254/345/205/261/351/230/237/345/210/227//350/256/276/350/256/241/346/226/271/346/241/210.md} +13 -6
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/accounts-mobile-320.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/accounts-mobile-360.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/accounts-mobile-390.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/companies-desktop-data.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/companies-desktop-empty.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/companies-mobile-320.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/companies-mobile-360.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/companies-mobile-390.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/company-create-dialog.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/company-projects-1440.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/company-projects-390.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/login-1440.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/login-390.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/project-home-1440.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/project-home-390.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/register-1440.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/register-390.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/workspaces-1440.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/workspaces-390.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273/ui/workspaces-empty.png +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273//345/267/245/345/205/267/fixtures.mjs +132 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273//345/267/245/345/205/267/visual-check.mjs +274 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273//346/265/213/350/257/225/350/257/201/346/215/256/visual-report.json +104 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//344/270/207/347/211/251/346/242/246/345/271/273//351/252/214/350/257/201/350/257/264/346/230/216.md +25 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//344/272/244/344/273/230/350/256/260/345/275/225.md +12 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//346/265/213/350/257/225/346/212/245/345/221/212.md +19 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//350/256/276/350/256/241/346/226/271/346/241/210.md +18 -0
- package/template-vp-monorepo-react-nestjs/.spaces/04./347/225/214/351/235/242/344/270/216/344/270/273/351/242/230//345/233/275/351/231/205/345/214/226//351/234/200/346/261/202/346/226/207/346/241/243.md +24 -0
- package/template-vp-monorepo-react-nestjs/.spaces/05./350/277/220/350/241/214/347/273/264/346/212/244//345/271/263/345/217/260/346/223/215/344/275/234/346/211/213/345/206/214.md +397 -0
- package/template-vp-monorepo-react-nestjs/.spaces/05./350/277/220/350/241/214/347/273/264/346/212/244//346/225/260/346/215/256/345/272/223/350/277/201/347/247/273//345/244/207/344/273/275/backup.dump +0 -0
- package/template-vp-monorepo-react-nestjs/.spaces/05./350/277/220/350/241/214/347/273/264/346/212/244//346/225/260/346/215/256/345/272/223/350/277/201/347/247/273//345/244/207/344/273/275/export-dump.ps1 +34 -0
- package/template-vp-monorepo-react-nestjs/.spaces/05./350/277/220/350/241/214/347/273/264/346/212/244//346/225/260/346/215/256/345/272/223/350/277/201/347/247/273//345/244/207/344/273/275/restore-dump.ps1 +73 -0
- package/template-vp-monorepo-react-nestjs/.spaces/05./350/277/220/350/241/214/347/273/264/346/212/244//346/225/260/346/215/256/345/272/223/350/277/201/347/247/273//346/223/215/344/275/234/346/214/207/345/215/227.md +227 -0
- package/template-vp-monorepo-react-nestjs/.spaces/05./350/277/220/350/241/214/347/273/264/346/212/244//346/225/260/346/215/256/345/272/223/350/277/201/347/247/273//351/234/200/346/261/202/346/226/207/346/241/243.md +31 -0
- package/template-vp-monorepo-react-nestjs/.spaces/06./350/256/244/350/257/201/344/270/216/344/274/232/350/257/235//344/274/232/350/257/235/347/256/241/347/220/206//346/212/200/346/234/257/345/245/221/347/272/246.md +93 -0
- package/template-vp-monorepo-react-nestjs/.spaces/06./350/256/244/350/257/201/344/270/216/344/274/232/350/257/235//344/274/232/350/257/235/347/256/241/347/220/206//351/234/200/346/261/202/346/226/207/346/241/243.md +87 -0
- package/template-vp-monorepo-react-nestjs/.spaces/06./350/256/244/350/257/201/344/270/216/344/274/232/350/257/235//344/277/256/346/224/271/345/257/206/347/240/201/PRD.md +55 -0
- package/template-vp-monorepo-react-nestjs/.spaces/06./350/256/244/350/257/201/344/270/216/344/274/232/350/257/235//344/277/256/346/224/271/345/257/206/347/240/201//346/212/200/346/234/257/345/245/221/347/272/246.md +92 -0
- package/template-vp-monorepo-react-nestjs/.spaces/06./350/256/244/350/257/201/344/270/216/344/274/232/350/257/235//344/277/256/346/224/271/345/257/206/347/240/201//346/265/213/350/257/225/346/212/245/345/221/212.md +38 -0
- package/template-vp-monorepo-react-nestjs/.spaces/06./350/256/244/350/257/201/344/270/216/344/274/232/350/257/235//344/277/256/346/224/271/345/257/206/347/240/201//350/201/224/350/260/203/350/256/260/345/275/225.md +26 -0
- package/template-vp-monorepo-react-nestjs/.spaces/06./350/256/244/350/257/201/344/270/216/344/274/232/350/257/235//344/277/256/346/224/271/345/257/206/347/240/201//350/256/276/350/256/241/346/226/271/346/241/210.md +53 -0
- package/template-vp-monorepo-react-nestjs/.spaces/06./350/256/244/350/257/201/344/270/216/344/274/232/350/257/235//344/277/256/346/224/271/345/257/206/347/240/201//351/234/200/346/261/202/346/226/207/346/241/243.md +63 -0
- package/template-vp-monorepo-react-nestjs/.spaces/07.API/344/270/216/351/224/231/350/257/257//346/212/200/346/234/257/345/245/221/347/272/246.md +95 -0
- package/template-vp-monorepo-react-nestjs/.spaces/README.md +85 -0
- package/template-vp-monorepo-react-nestjs/.spaces//346/226/207/346/241/243/350/247/204/350/214/203.md +97 -0
- package/template-vp-monorepo-react-nestjs/AGENTS.md +12 -0
- package/template-vp-monorepo-react-nestjs/README.md +3 -27
- package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0002_enterprise_access.sql +182 -0
- package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0003_cute_killmonger.sql +357 -0
- package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0004_company-member-invitations.sql +25 -0
- package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0005_menu_svg_icons.sql +54 -0
- package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/0002_snapshot.json +1801 -0
- package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/0003_snapshot.json +3511 -0
- package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/0004_snapshot.json +3713 -0
- package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/_journal.json +29 -1
- package/template-vp-monorepo-react-nestjs/apps/server/drizzle/rollback/0003_organization_backfill.sql +32 -0
- package/template-vp-monorepo-react-nestjs/apps/server/package.json +6 -4
- package/template-vp-monorepo-react-nestjs/apps/server/src/access-init.ts +45 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/app.controller.ts +3 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/app.module.ts +28 -5
- package/template-vp-monorepo-react-nestjs/apps/server/src/app.service.ts +3 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/adapters/fastify.adapter.ts +11 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/constants/session.constants.ts +9 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/decorators/access-policy.decorator.ts +18 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/decorators/current-auth.decorator.ts +4 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/decorators/public.decorator.ts +3 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/exceptions/app.exception.ts +9 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/filters/global-exception.filter.ts +38 -5
- package/template-vp-monorepo-react-nestjs/apps/server/src/common/security/password-security-event.ts +98 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/config/app.config.ts +3 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/config/database.config.ts +3 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/config/llm.config.ts +3 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/config/queue.config.ts +14 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/config/redis.config.ts +3 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/config/session.config.ts +7 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/config/storage.config.ts +9 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/database/access.schema.ts +394 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/database/db.module.ts +3 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/database/organization.schema.ts +453 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/database/schema.ts +6 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/main.ts +4 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access-http.ts +29 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.errors.ts +130 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.guard.ts +63 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.module.ts +27 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.service.ts +441 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.store.ts +68 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/access.validation.ts +44 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/maintenance/permissions-cleanup.controller.ts +27 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/maintenance/permissions-cleanup.service.ts +260 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/maintenance/permissions-cleanup.validation.ts +7 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/roles/roles.controller.ts +80 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/roles/roles.service.ts +249 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/roles/roles.validation.ts +24 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/seed/access-seed.service.ts +183 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/workspaces/workspaces.controller.ts +28 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/workspaces/workspaces.service.ts +94 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/access/workspaces/workspaces.validation.ts +5 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/audit/audit.controller.ts +26 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/audit/audit.module.ts +11 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/audit/audit.service.ts +74 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/audit/audit.validation.ts +11 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.controller.ts +25 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.errors.ts +10 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.module.ts +1 -1
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.repository.ts +60 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.service.ts +69 -11
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/dto/register.dto.ts +1 -1
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/guards/session-auth.guard.ts +8 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/password/change-password.dto.ts +17 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/password.service.ts +6 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/session/session-store.service.ts +46 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/session/session-token.service.ts +12 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/session/session.script.ts +7 -1
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/companies/companies.controller.ts +105 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/companies/companies.module.ts +12 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/companies/companies.service.ts +523 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/accounts/accounts.controller.ts +72 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/accounts/accounts.service.ts +154 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/accounts/accounts.validation.ts +8 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/accounts/password-reset/password-reset.service.ts +81 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/accounts/password-reset/reset-password.validation.ts +13 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/administrators/administrators.service.ts +116 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/administrators/administrators.validation.ts +1 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/invitations/company-member-invitations.controller.ts +69 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/invitations/member-invitation-acceptance.controller.ts +23 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/invitations/member-invitations.service.ts +344 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/invitations/member-invitations.validation.ts +23 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/members.controller.ts +88 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/members.module.ts +31 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/members.service.ts +573 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/members/members.validation.ts +19 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/menus/menus.controller.ts +56 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/menus/menus.module.ts +11 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/menus/menus.service.ts +230 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/menus/menus.validation.ts +30 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/candidates/global-account/global-account-candidates.controller.ts +35 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/candidates/global-account/global-account-candidates.service.ts +109 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/candidates/member-candidates.controller.ts +60 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/candidates/member-candidates.service.ts +939 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/initialization/project-organization-initialization.service.ts +189 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/organization.module.ts +34 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/organization.store.ts +150 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/organization.validation.ts +23 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/positions/positions.controller.ts +160 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/positions/positions.service.ts +636 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/templates/organization-templates.controller.ts +77 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/templates/organization-templates.service.ts +501 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/templates/organization-templates.store.ts +163 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/units/organization-units.controller.ts +187 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/organization/units/organization-units.service.ts +947 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/projects/projects.controller.ts +94 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/projects/projects.module.ts +13 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/projects/projects.service.ts +369 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/queue-worker.bootstrap.ts +3 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.contracts.ts +4 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.module.ts +5 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.processor.ts +13 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.service.ts +9 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/db/db.controller.ts +9 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/db/db.service.ts +9 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/redis/redis.controller.ts +9 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/redis/redis.service.ts +18 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/dto/upload-params.dto.ts +1 -1
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/storage/exact-size.transform.ts +14 -3
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/storage/minio-storage.adapter.ts +37 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/storage/storage.port.ts +21 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.constants.ts +9 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.controller.ts +25 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.reponsitory.ts +27 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.service.ts +78 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/utils/object-key.ts +4 -0
- package/template-vp-monorepo-react-nestjs/apps/server/src/utils/server-address.ts +6 -0
- package/template-vp-monorepo-react-nestjs/apps/server/test/access/access-policy.spec.ts +95 -0
- package/template-vp-monorepo-react-nestjs/apps/server/test/access/access.integration.spec.ts +2250 -0
- package/template-vp-monorepo-react-nestjs/apps/server/test/access/member-onboarding.validation.spec.ts +78 -0
- package/template-vp-monorepo-react-nestjs/apps/server/test/auth/password-operations.spec.ts +433 -0
- package/template-vp-monorepo-react-nestjs/apps/server/test/auth/password.integration.spec.ts +300 -0
- package/template-vp-monorepo-react-nestjs/apps/server/test/error-catalog.spec.ts +6 -1
- package/template-vp-monorepo-react-nestjs/apps/server/test/menus.validation.spec.ts +28 -0
- package/template-vp-monorepo-react-nestjs/apps/server/test/organization/organization-domain.spec.ts +260 -0
- package/template-vp-monorepo-react-nestjs/apps/server/tsconfig.scripts.json +5 -0
- package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//347/273/204/344/273/266/345/244/215/347/224/250.md +7 -0
- package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//350/241/250/345/215/225/345/233/236/345/241/253.md +4 -0
- package/template-vp-monorepo-react-nestjs/apps/web/AGENTS.md +17 -8
- package/template-vp-monorepo-react-nestjs/apps/web/README.MD +36 -8
- package/template-vp-monorepo-react-nestjs/apps/web/index.html +2 -2
- package/template-vp-monorepo-react-nestjs/apps/web/package.json +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/App.tsx +19 -8
- package/template-vp-monorepo-react-nestjs/apps/web/src/api/auth.ts +14 -1
- package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/accounts.svg +4 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/audit-log.svg +4 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/companies.svg +5 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/dashboard.svg +6 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/home.svg +4 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/members.svg +4 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/menu-item.svg +4 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/menus.svg +6 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/organization-template.svg +4 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/organization.svg +6 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/positions.svg +4 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/profile.svg +5 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/projects.svg +4 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/roles.svg +4 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Brand/Brand.module.css +125 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Brand/Brand.tsx +56 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/DraftProTable/DraftProTable.tsx +11 -5
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/SvgAsset/IconSelector.tsx +38 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/SvgAsset/SvgAssetIcon.tsx +14 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/SvgAsset/SvgAssetRegistry.ts +32 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/SvgAsset/index.ts +10 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/svg-icon/SvgIcon.tsx +0 -2
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Loading/PageLoading.tsx +5 -1
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/LocaleSwitch/LocaleSwitch.tsx +52 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/PasswordActions/ChangePasswordDialog.tsx +90 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/PasswordActions/PasswordFields.module.css +12 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/PasswordActions/PasswordFields.tsx +54 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/PasswordActions/ResetAccountPasswordDialog.tsx +100 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/PasswordActions/change-password-session.ts +13 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/RouteTransition/RouteTransition.css +60 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/RouteTransition/RouteTransition.tsx +44 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/BasicTableSelector/BasicTableSelector.tsx +218 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/BasicTableSelector/BasicTableSelectorSelection.ts +91 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/BasicTableSelector/BasicTableSelectorTypes.ts +60 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/BasicTableSelector/README.md +110 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/BasicTableSelector/index.ts +7 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/GlobalAccountSelect/GlobalAccountSelect.tsx +211 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/GlobalAccountSelect/GlobalAccountSelectTypes.ts +75 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/GlobalAccountSelect/README.md +35 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/GlobalAccountSelect/index.ts +9 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/OrganizationMemberSelector/OrganizationMemberBrowser.tsx +146 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/OrganizationMemberSelector/OrganizationMemberCandidateColumns.tsx +137 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/OrganizationMemberSelector/OrganizationMemberFilterPanel.tsx +209 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/OrganizationMemberSelector/OrganizationMemberSelector.tsx +196 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/OrganizationMemberSelector/OrganizationMemberSelectorTypes.ts +103 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/OrganizationMemberSelector/README.md +8 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/OrganizationMemberSelector/index.ts +13 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/README.md +13 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/components/Selector/index.ts +30 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/config/theme.ts +41 -9
- package/template-vp-monorepo-react-nestjs/apps/web/src/hooks/useLatestDialogRequest.ts +71 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/i18n/config.ts +40 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/i18n/index.ts +10 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/i18n/instance.ts +36 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/i18n/ui-locale.ts +30 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/{BasicLayout.tsx → BasicLayout/index.tsx} +42 -35
- package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/WorkspaceLayout/components/WorkspaceNavigationBoundary.tsx +50 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/WorkspaceLayout/index.tsx +196 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/WorkspaceLayout/workspace-landing.css +119 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/WorkspaceLayout/workspace-surfaces.css +110 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/WorkspaceLayout/workspace.css +223 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/locales/en_US.json +639 -1
- package/template-vp-monorepo-react-nestjs/apps/web/src/locales/zh_CN.json +621 -1
- package/template-vp-monorepo-react-nestjs/apps/web/src/main.tsx +8 -2
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/api.ts +226 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/audit.tsx +169 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/AdministratorDialog.tsx +128 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/CleanupDialog.tsx +140 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/CompanyHierarchyDialog.tsx +244 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/EntityFormDialog.tsx +285 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/EntitySelectors/index.ts +6 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/EntitySelectors/selector-requests.ts +59 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberAffiliations/MemberOrganizationsDialog.tsx +188 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberAffiliations/MemberPositionsDialog.tsx +116 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberAffiliations/affiliation-loaders.ts +18 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberAffiliations/index.ts +5 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberOnboarding/AddProjectMemberDialog.tsx +75 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberOnboarding/CompanyMemberInvitation/CompanyMemberInvitationDialog.tsx +246 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberOnboarding/CompanyMemberInvitation/InvitationRecordsTable.tsx +152 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberOnboarding/CompanyMemberInvitation/invitation-link.ts +9 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberOnboarding/MemberOnboardingActions.tsx +79 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberOnboarding/RegisterCompanyMember/RegisterCompanyMemberDialog.module.css +12 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberOnboarding/RegisterCompanyMember/RegisterCompanyMemberDialog.tsx +122 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberRolesDialog.tsx +80 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberTable/MemberTableColumns.tsx +234 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberTable/index.ts +2 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MemberTable/member-candidate-cache.ts +12 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/MenuFormDialog.tsx +251 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/RoleFormDialog.tsx +73 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/components/RolePermissionsDialog.tsx +185 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/entities.tsx +268 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/home.tsx +67 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/members.tsx +310 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/menus/api.ts +74 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/menus/index.tsx +325 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/profile.tsx +160 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/roles.tsx +173 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/access/use-access.ts +35 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/error/404.tsx +20 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/error/error.tsx +42 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/i18n/index.tsx +20 -38
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/components/ProjectFormDialog.tsx +46 -41
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/config/columns.tsx +20 -15
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/config/index.ts +32 -22
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/components/DraftProjectFormDialog.tsx +41 -34
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/config/columns.tsx +27 -20
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/config/projects.ts +21 -13
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/index.tsx +47 -27
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/index.tsx +51 -36
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/home/index.tsx +9 -6
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/api.ts +3 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/index.tsx +62 -82
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/login-form.css +199 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/login.css +146 -124
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/member-invitations/accept.css +47 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/member-invitations/accept.tsx +143 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/member-invitations/api.ts +20 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/api.ts +91 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/MoveOrganizationUnitDialog.tsx +82 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/OrganizationMemberColumns.tsx +87 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/OrganizationMemberHeader.tsx +102 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/OrganizationTreeModel.tsx +59 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/OrganizationTreePanel.tsx +88 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/index.ts +11 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/organization-loaders.ts +47 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationBrowser/organization-member-filter-loaders.ts +187 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationMembersDialog.tsx +207 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/components/OrganizationUnitDialog.tsx +110 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization/index.tsx +258 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization-templates/api.ts +53 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization-templates/components/OrganizationTemplateDialog/TemplateDefinitionTabs.tsx +189 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization-templates/components/OrganizationTemplateDialog/index.tsx +135 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization-templates/components/OrganizationTemplateDialog/types.ts +25 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/organization-templates/index.tsx +201 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/positions/api.ts +81 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/positions/components/PositionFormDialog.tsx +86 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/positions/components/PositionMembersDialog.tsx +102 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/positions/index.tsx +198 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/positions/loaders.ts +35 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/register/api.ts +14 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/register/index.tsx +157 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/workspaces/api.ts +32 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/workspaces/index.tsx +146 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/pages/workspaces/state.ts +24 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/AGENTS.MD +6 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/index.tsx +2 -46
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/lazy-load/index.tsx +26 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/README.md +23 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/auth.ts +6 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/index.ts +4 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/workspace/access.ts +23 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/workspace/data.ts +55 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/middleware/workspace/entry.ts +52 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/access/page.tsx +20 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/auth.tsx +17 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/company.tsx +30 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/entry.tsx +20 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/examples.tsx +23 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/fallback.tsx +13 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/index.tsx +32 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/platform.tsx +27 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/project.tsx +28 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/page-registry.tsx +94 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/styles/dream.css +34 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/styles/index.css +6 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/types/auto-imports.d.ts +26 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/utils/organization-assignment.ts +66 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/core/index.ts +48 -13
- package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/core/utils.ts +5 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/index.ts +7 -2
- package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/workspace.ts +82 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/utils/safe-next.ts +36 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/utils/storage/cookie.ts +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web/src/utils/storage/session.ts +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/i18n-locale.spec.ts +22 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/icon-selector.spec.tsx +23 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/latest-dialog-request.spec.ts +89 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/member-invitation-navigation.spec.ts +34 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/organization-assignment.spec.ts +137 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/password-actions.spec.ts +40 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/password-reset-action.spec.ts +64 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/request.spec.ts +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/router/access.spec.ts +136 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/router/config.ts +140 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/router/entry.spec.ts +179 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/router/workspace-data.spec.ts +112 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/selector/global-account-select.spec.ts +311 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/selector/organization-member-selector.spec.ts +454 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/selector/selector-selection.spec.ts +132 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/storage.spec.ts +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/tsconfig.json +2 -2
- package/template-vp-monorepo-react-nestjs/apps/web/test/workspace-navigation-boundary.spec.tsx +169 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/workspace-navigation.spec.ts +105 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/workspace-requests.spec.ts +174 -0
- package/template-vp-monorepo-react-nestjs/apps/web/test/workspaces-password-entry.spec.tsx +71 -0
- package/template-vp-monorepo-react-nestjs/apps/web/vite.config.ts +84 -35
- package/template-vp-monorepo-react-nestjs/apps/web-vue/package.json +2 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/api/index.ts +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/hooks/chart/useEcharts.ts +13 -1
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/layout/default/header/index.vue +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/layout/default/index.vue +6 -2
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/router/guard/index.ts +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/router/guard/permissionGuard.ts +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/router/index.ts +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/store/index.ts +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/store/modules/user.ts +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/types/auto-import.d.ts +2 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/utils/request/core/index.ts +30 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/utils/request/core/utils.ts +5 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/utils/request/index.ts +2 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/src/views/example/echart/config.ts +1 -0
- package/template-vp-monorepo-react-nestjs/apps/web-vue/tsconfig.tsbuildinfo +1 -1
- package/template-vp-monorepo-react-nestjs/package.json +1 -8
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/command.ts +22 -2
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/config.ts +1 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/files.ts +1 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/load-config.ts +8 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/report.ts +2 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/scanner.ts +11 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/src/sync.ts +12 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/test/command.test.ts +1 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/cli/test/temporary-directory.ts +5 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/format.ts +1 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/i18n.ts +14 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/storage.ts +8 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/core/src/store.ts +9 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/react/src/index.tsx +5 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/react/src/use-store.ts +3 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/vue/src/index.ts +6 -0
- package/template-vp-monorepo-react-nestjs/packages/i18n/vue/src/use-store.ts +3 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/package.json +5 -1
- package/template-vp-monorepo-react-nestjs/packages/shared/src/index.ts +2 -13
- package/template-vp-monorepo-react-nestjs/packages/shared/src/types/access-maintenance.ts +68 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/types/access-menus.ts +94 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/types/access-resources.ts +168 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/types/access.ts +71 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/types/auth.ts +23 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/types/index.ts +9 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/types/organization/models.ts +361 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/access-catalog.ts +304 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/access-scope.ts +97 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/account.ts +1 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/index.ts +65 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/organization/contracts.ts +237 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/record.ts +10 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/src/utils/session-terminal.ts +1 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/test/access.spec.ts +194 -0
- package/template-vp-monorepo-react-nestjs/packages/shared/test/organization.spec.ts +168 -0
- package/template-vp-monorepo-react-nestjs/pnpm-workspace.yaml +103 -69
- package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/browser.mjs +696 -0
- package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/http-support.mjs +105 -0
- package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/http.mjs +1091 -0
- package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/legacy-http.mjs +140 -0
- package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/legacy.mjs +196 -0
- package/template-vp-monorepo-react-nestjs/scripts/enterprise-qa/runtime.mjs +110 -0
- package/template-vp-monorepo-react-nestjs/scripts/with-enterprise-test-env.mjs +80 -0
- package/template-vp-monorepo-react-nestjs/src/types/auto-imports.d.ts +60 -0
- package/template-vp-react/.vscode/settings.json +8 -1
- package/template-vp-react/package.json +10 -10
- package/template-vp-react/src/types/auto-imports.d.ts +2 -0
- package/template-vp-vue-eslint-vapor/package.json +20 -20
- package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//351/234/200/346/261/202/346/226/207/346/241/243.md +0 -177
- package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/BasicLayout.module.css +0 -17
- package/template-vp-monorepo-react-nestjs/apps/web/src/router/modules/.gitkeep +0 -0
- package/template-vp-react/.agents/rules/SVG/344/275/277/347/224/250.md +0 -8
- package/template-vp-react/AGENTS.md +0 -11
- /package/template-vp-monorepo-react-nestjs/apps/web/src/assets/{hero.png → image/hero.png} +0 -0
- /package/template-vp-monorepo-react-nestjs/apps/web/src/assets/{react.svg → svg/react.svg} +0 -0
- /package/template-vp-monorepo-react-nestjs/apps/web/src/assets/{vite.svg → svg/vite.svg} +0 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { AccessContext, AccessScope, MenuNode } from 'shared/types'
|
|
2
|
+
import { accessRoutePath, filterSupportedAccessMenus } from 'shared/utils'
|
|
3
|
+
import { SvgAssetIcon } from '@/components/Icon/SvgAsset'
|
|
4
|
+
import { tr } from '@/i18n'
|
|
5
|
+
|
|
6
|
+
/** 此表随 Web 发布;服务端下发的 routeKey 不能动态 import 任意组件。 */
|
|
7
|
+
export const pageRegistry = {
|
|
8
|
+
'platform.home': { path: '', title: () => tr('平台工作台') },
|
|
9
|
+
'platform.companies': { path: 'companies', title: () => tr('企业管理') },
|
|
10
|
+
'platform.accounts': { path: 'accounts', title: () => tr('全局账号') },
|
|
11
|
+
'platform.roles': { path: 'roles', title: () => tr('平台角色') },
|
|
12
|
+
'platform.menus': { path: 'menus', title: () => tr('菜单管理') },
|
|
13
|
+
'platform.audit': { path: 'audit', title: () => tr('平台操作日志') },
|
|
14
|
+
'company.home': { path: '', title: () => tr('企业工作台') },
|
|
15
|
+
'company.profile': { path: 'profile', title: () => tr('企业资料') },
|
|
16
|
+
'company.members': { path: 'members', title: () => tr('企业成员') },
|
|
17
|
+
'company.roles': { path: 'roles', title: () => tr('企业角色') },
|
|
18
|
+
'company.organization': { path: 'organization', title: () => tr('企业组织架构') },
|
|
19
|
+
'company.positions': { path: 'positions', title: () => tr('企业岗位') },
|
|
20
|
+
'company.organization.templates': {
|
|
21
|
+
path: 'organization/templates',
|
|
22
|
+
title: () => tr('项目组织模板'),
|
|
23
|
+
},
|
|
24
|
+
'company.projects': { path: 'projects', title: () => tr('项目管理') },
|
|
25
|
+
'company.audit': { path: 'audit', title: () => tr('企业操作日志') },
|
|
26
|
+
'project.home': { path: '', title: () => tr('项目工作台') },
|
|
27
|
+
'project.profile': { path: 'profile', title: () => tr('项目资料') },
|
|
28
|
+
'project.members': { path: 'members', title: () => tr('项目成员') },
|
|
29
|
+
'project.roles': { path: 'roles', title: () => tr('项目角色') },
|
|
30
|
+
'project.organization': { path: 'organization', title: () => tr('项目组织架构') },
|
|
31
|
+
'project.positions': { path: 'positions', title: () => tr('项目岗位') },
|
|
32
|
+
'project.audit': { path: 'audit', title: () => tr('项目操作日志') },
|
|
33
|
+
} as const
|
|
34
|
+
|
|
35
|
+
export type RegisteredPage = keyof typeof pageRegistry
|
|
36
|
+
export const registeredRouteKeys = Object.keys(pageRegistry)
|
|
37
|
+
|
|
38
|
+
/** 仅为前端已注册的页面生成指定作用域路径,未知页面返回 null。 */
|
|
39
|
+
export function pagePath(scope: AccessScope, routeKey: string) {
|
|
40
|
+
const page = pageRegistry[routeKey as RegisteredPage]
|
|
41
|
+
return page ? accessRoutePath({ scope, routeKey }) : null
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** 优先按可见菜单顺序寻找授权页面,再从已注册页面中兜底选择。 */
|
|
45
|
+
export function firstAccessiblePagePath(context: AccessContext): string | null {
|
|
46
|
+
/** 仅为拥有读取权限的页面生成当前工作空间路径。 */
|
|
47
|
+
const allowedPath = (key: string) =>
|
|
48
|
+
context.permissionKeys.includes(`${key}.read`) ? pagePath(context.scope, key) : null
|
|
49
|
+
/** 深度优先遍历可见且启用的菜单,返回首个已授权页面路径。 */
|
|
50
|
+
const visit = (nodes: MenuNode[]): string | null => {
|
|
51
|
+
for (const node of nodes) {
|
|
52
|
+
if (node.hidden || node.status !== 'active' || node.type === 'operation') continue
|
|
53
|
+
const destination =
|
|
54
|
+
node.type === 'page' ? allowedPath(node.routeKey ?? '') : visit(node.children)
|
|
55
|
+
if (destination) return destination
|
|
56
|
+
}
|
|
57
|
+
return null
|
|
58
|
+
}
|
|
59
|
+
return (
|
|
60
|
+
visit(context.menus) ??
|
|
61
|
+
registeredRouteKeys.map(allowedPath).find((destination) => destination !== null) ??
|
|
62
|
+
null
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface NavigationItem {
|
|
67
|
+
key: string
|
|
68
|
+
name: string
|
|
69
|
+
path?: string
|
|
70
|
+
icon: ReactNode
|
|
71
|
+
routes?: NavigationItem[]
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** 过滤未发布和不可见功能,将有效菜单递归转换为布局导航数据。 */
|
|
75
|
+
export function navigationTree(nodes: MenuNode[], scope: AccessScope): NavigationItem[] {
|
|
76
|
+
return filterSupportedAccessMenus({
|
|
77
|
+
menus: nodes,
|
|
78
|
+
supportedRouteKeys: registeredRouteKeys,
|
|
79
|
+
}).flatMap(
|
|
80
|
+
/** 丢弃不可导航节点,解析页面路径或递归生成目录下的有效导航项。 */ (
|
|
81
|
+
node,
|
|
82
|
+
): NavigationItem[] => {
|
|
83
|
+
if (node.hidden || node.status !== 'active' || node.type === 'operation') return []
|
|
84
|
+
const icon = <SvgAssetIcon name={node.icon} />
|
|
85
|
+
if (node.type === 'page') {
|
|
86
|
+
const path = pagePath(scope, node.routeKey ?? '')
|
|
87
|
+
const page = pageRegistry[node.routeKey as RegisteredPage]
|
|
88
|
+
return path ? [{ key: path, path, name: page?.title() ?? node.name, icon }] : []
|
|
89
|
+
}
|
|
90
|
+
const routes = navigationTree(node.children, scope)
|
|
91
|
+
return routes.length ? [{ key: node.id, name: tr(node.name), icon, routes }] : []
|
|
92
|
+
},
|
|
93
|
+
)
|
|
94
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
@layer components {
|
|
2
|
+
:root {
|
|
3
|
+
--wanwu-ink: #302b49;
|
|
4
|
+
--wanwu-muted: #78718e;
|
|
5
|
+
--wanwu-accent: #7864c4;
|
|
6
|
+
--wanwu-lilac: #8270db;
|
|
7
|
+
--wanwu-fog: #f5f3fc;
|
|
8
|
+
--wanwu-ice: #dceefa;
|
|
9
|
+
--wanwu-rose: #f2dfef;
|
|
10
|
+
--wanwu-border: rgba(255, 255, 255, 0.85);
|
|
11
|
+
--wanwu-glass: rgba(255, 255, 255, 0.76);
|
|
12
|
+
--wanwu-shadow: 0 12px 40px rgba(91, 70, 144, 0.06);
|
|
13
|
+
--wanwu-atmosphere:
|
|
14
|
+
radial-gradient(ellipse at 84% 7%, #e6ddf6 0, transparent 44%),
|
|
15
|
+
radial-gradient(ellipse at 38% 95%, var(--wanwu-ice) 0, transparent 48%),
|
|
16
|
+
radial-gradient(ellipse at 2% 26%, var(--wanwu-rose) 0, transparent 44%), var(--wanwu-fog);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
a:focus-visible,
|
|
20
|
+
button:focus-visible {
|
|
21
|
+
outline: 2px solid var(--wanwu-accent);
|
|
22
|
+
outline-offset: 4px;
|
|
23
|
+
}
|
|
24
|
+
@media (prefers-reduced-motion: reduce) {
|
|
25
|
+
*,
|
|
26
|
+
*::before,
|
|
27
|
+
*::after {
|
|
28
|
+
animation-duration: 0.01ms !important;
|
|
29
|
+
animation-iteration-count: 1 !important;
|
|
30
|
+
transition-duration: 0.01ms !important;
|
|
31
|
+
scroll-behavior: auto !important;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/* eslint-disable */
|
|
2
2
|
/* prettier-ignore */
|
|
3
|
+
/* oxlint-disable */
|
|
4
|
+
/* oxfmt-ignore */
|
|
3
5
|
// @ts-nocheck
|
|
4
6
|
// noinspection JSUnusedGlobalSymbols
|
|
5
7
|
// Generated by unplugin-auto-import
|
|
@@ -8,14 +10,23 @@ export {}
|
|
|
8
10
|
declare global {
|
|
9
11
|
const Activity: typeof import('react').Activity
|
|
10
12
|
const Fragment: typeof import('react').Fragment
|
|
13
|
+
const Link: typeof import('react-router').Link
|
|
14
|
+
const Outlet: typeof import('react-router').Outlet
|
|
15
|
+
const ReactViewTransition: typeof import('react').ViewTransition
|
|
16
|
+
const RouterProvider: typeof import('react-router').RouterProvider
|
|
11
17
|
const Suspense: typeof import('react').Suspense
|
|
12
18
|
const cache: typeof import('react').cache
|
|
13
19
|
const cacheSignal: typeof import('react').cacheSignal
|
|
20
|
+
const createBrowserRouter: typeof import('react-router').createBrowserRouter
|
|
14
21
|
const createContext: typeof import('react').createContext
|
|
22
|
+
const createMemoryRouter: typeof import('react-router').createMemoryRouter
|
|
15
23
|
const createPortal: typeof import('react-dom').createPortal
|
|
16
24
|
const createRef: typeof import('react').createRef
|
|
25
|
+
const createRoot: typeof import('react-dom/client').createRoot
|
|
26
|
+
const createRouterContext: typeof import('react-router').createContext
|
|
17
27
|
const flushSync: typeof import('react-dom').flushSync
|
|
18
28
|
const forwardRef: typeof import('react').forwardRef
|
|
29
|
+
const isRouteErrorResponse: typeof import('react-router').isRouteErrorResponse
|
|
19
30
|
const lazy: typeof import('react').lazy
|
|
20
31
|
const memo: typeof import('react').memo
|
|
21
32
|
const preconnect: typeof import('react-dom').preconnect
|
|
@@ -24,6 +35,7 @@ declare global {
|
|
|
24
35
|
const preinitModule: typeof import('react-dom').preinitModule
|
|
25
36
|
const preload: typeof import('react-dom').preload
|
|
26
37
|
const preloadModule: typeof import('react-dom').preloadModule
|
|
38
|
+
const redirect: typeof import('react-router').redirect
|
|
27
39
|
const startTransition: typeof import('react').startTransition
|
|
28
40
|
const use: typeof import('react').use
|
|
29
41
|
const useActionState: typeof import('react').useActionState
|
|
@@ -41,8 +53,10 @@ declare global {
|
|
|
41
53
|
const useInsertionEffect: typeof import('react').useInsertionEffect
|
|
42
54
|
const useLayoutEffect: typeof import('react').useLayoutEffect
|
|
43
55
|
const useLocation: typeof import('react-router').useLocation
|
|
56
|
+
const useMatches: typeof import('react-router').useMatches
|
|
44
57
|
const useMemo: typeof import('react').useMemo
|
|
45
58
|
const useNavigate: typeof import('react-router').useNavigate
|
|
59
|
+
const useNavigation: typeof import('react-router').useNavigation
|
|
46
60
|
const useNavigationType: typeof import('react-router').useNavigationType
|
|
47
61
|
const useOptimistic: typeof import('react').useOptimistic
|
|
48
62
|
const useOutlet: typeof import('react-router').useOutlet
|
|
@@ -51,8 +65,20 @@ declare global {
|
|
|
51
65
|
const useReducer: typeof import('react').useReducer
|
|
52
66
|
const useRef: typeof import('react').useRef
|
|
53
67
|
const useResolvedPath: typeof import('react-router').useResolvedPath
|
|
68
|
+
const useRevalidator: typeof import('react-router').useRevalidator
|
|
69
|
+
const useRouteError: typeof import('react-router').useRouteError
|
|
54
70
|
const useRoutes: typeof import('react-router').useRoutes
|
|
71
|
+
const useSearchParams: typeof import('react-router').useSearchParams
|
|
55
72
|
const useState: typeof import('react').useState
|
|
56
73
|
const useSyncExternalStore: typeof import('react').useSyncExternalStore
|
|
57
74
|
const useTransition: typeof import('react').useTransition
|
|
58
75
|
}
|
|
76
|
+
// for type re-export
|
|
77
|
+
declare global {
|
|
78
|
+
// @ts-ignore
|
|
79
|
+
export type { ReactNode, ComponentType, SVGProps, PropsWithChildren, Key, Ref, LazyExoticComponent, ReactElement } from 'react'
|
|
80
|
+
import('react')
|
|
81
|
+
// @ts-ignore
|
|
82
|
+
export type { MiddlewareFunction, DataRouter, RouterState, RouteObject } from 'react-router'
|
|
83
|
+
import('react-router')
|
|
84
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { OrganizationDuty, OrganizationMemberCandidate, OrganizationScope } from 'shared/types'
|
|
2
|
+
import { accessScopeKey } from 'shared/utils'
|
|
3
|
+
|
|
4
|
+
const dutyOrder: Record<OrganizationDuty, number> = {
|
|
5
|
+
member: 0,
|
|
6
|
+
deputy: 1,
|
|
7
|
+
leader: 2,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface CandidateAssignmentInput {
|
|
11
|
+
candidate: OrganizationMemberCandidate
|
|
12
|
+
scope: OrganizationScope
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface OrganizationAssignmentInput extends CandidateAssignmentInput {
|
|
16
|
+
unitEffective: boolean
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface OrganizationDutyChangeInput extends OrganizationAssignmentInput {
|
|
20
|
+
initialDuty?: OrganizationDuty
|
|
21
|
+
nextDuty: OrganizationDuty
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface PositionAssignmentInput extends CandidateAssignmentInput {
|
|
25
|
+
positionActive: boolean
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** 判断账号及其当前 URL 作用域成员身份是否都处于有效状态。 */
|
|
29
|
+
export function isCandidateActiveInScope({ candidate, scope }: CandidateAssignmentInput): boolean {
|
|
30
|
+
if (candidate.accountStatus !== 'active') return false
|
|
31
|
+
const scopeKey = accessScopeKey(scope)
|
|
32
|
+
const identity = candidate.identities.find((item) => accessScopeKey(item.scope) === scopeKey)
|
|
33
|
+
return identity?.scopeStatus === 'active' && identity.memberStatus === 'active'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** 仅允许有效成员向有效组织单元新增关系。 */
|
|
37
|
+
export function canAddOrganizationAssignment({
|
|
38
|
+
candidate,
|
|
39
|
+
scope,
|
|
40
|
+
unitEffective,
|
|
41
|
+
}: OrganizationAssignmentInput): boolean {
|
|
42
|
+
return unitEffective && isCandidateActiveInScope({ candidate, scope })
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 有效关系可任意调整职责;失效关系只能原样保留或降级,不能新增或升级职责。
|
|
47
|
+
*/
|
|
48
|
+
export function canChangeOrganizationDuty({
|
|
49
|
+
candidate,
|
|
50
|
+
scope,
|
|
51
|
+
unitEffective,
|
|
52
|
+
initialDuty,
|
|
53
|
+
nextDuty,
|
|
54
|
+
}: OrganizationDutyChangeInput): boolean {
|
|
55
|
+
if (canAddOrganizationAssignment({ candidate, scope, unitEffective })) return true
|
|
56
|
+
return initialDuty !== undefined && dutyOrder[nextDuty] <= dutyOrder[initialDuty]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** 仅允许可选且当前作用域有效的成员新增到启用岗位。 */
|
|
60
|
+
export function canAddPositionAssignment({
|
|
61
|
+
candidate,
|
|
62
|
+
scope,
|
|
63
|
+
positionActive,
|
|
64
|
+
}: PositionAssignmentInput): boolean {
|
|
65
|
+
return positionActive && !candidate.disabled && isCandidateActiveInScope({ candidate, scope })
|
|
66
|
+
}
|
|
@@ -9,9 +9,11 @@ import type {
|
|
|
9
9
|
} from 'alova'
|
|
10
10
|
import { createAlova } from 'alova'
|
|
11
11
|
import type { AxiosResponse, AxiosResponseHeaders } from 'axios'
|
|
12
|
+
import { tr } from '@/i18n'
|
|
12
13
|
import { deepMergeObject, isPlainObject, isReadableStream, tryParseJsonString } from './utils.ts'
|
|
13
14
|
|
|
14
15
|
type MaybePromise<T> = T | Promise<T>
|
|
16
|
+
type MessageResolver = string | (() => string)
|
|
15
17
|
type HeaderValue =
|
|
16
18
|
| string
|
|
17
19
|
| number
|
|
@@ -55,8 +57,8 @@ export interface BaseRequestOption<
|
|
|
55
57
|
cacheFor?: GlobalCacheConfig<any> | null
|
|
56
58
|
cacheLogger?: boolean
|
|
57
59
|
statesHook?: StatesHook<SE>
|
|
58
|
-
successDefaultMessage?:
|
|
59
|
-
errorDefaultMessage?:
|
|
60
|
+
successDefaultMessage?: MessageResolver
|
|
61
|
+
errorDefaultMessage?: MessageResolver
|
|
60
62
|
successMessageFunc?: (message: string) => void
|
|
61
63
|
errorMessageFunc?: (message: string) => void
|
|
62
64
|
unAuthorizedResponseFunc?: (response: RE) => void
|
|
@@ -112,9 +114,6 @@ type ResolvedRequestOption<RC extends object, RE, RH, SE extends StatesExport<an
|
|
|
112
114
|
> &
|
|
113
115
|
BaseRequestOption<RC, RE, RH, SE>
|
|
114
116
|
|
|
115
|
-
const DEFAULT_SUCCESS_MESSAGE = '操作成功'
|
|
116
|
-
const DEFAULT_ERROR_MESSAGE = '服务异常'
|
|
117
|
-
|
|
118
117
|
const defaultRequestOption: BaseRequestOption<any, any, any, any> = {
|
|
119
118
|
baseUrl: '/',
|
|
120
119
|
timeout: undefined,
|
|
@@ -131,24 +130,27 @@ const defaultRequestOption: BaseRequestOption<any, any, any, any> = {
|
|
|
131
130
|
isWrapped: true,
|
|
132
131
|
isTransformResponse: true,
|
|
133
132
|
isShowSuccessMessage: false,
|
|
134
|
-
successDefaultMessage:
|
|
133
|
+
successDefaultMessage: () => tr('操作成功'),
|
|
135
134
|
isShowErrorMessage: true,
|
|
136
|
-
errorDefaultMessage:
|
|
135
|
+
errorDefaultMessage: () => tr('服务异常'),
|
|
137
136
|
cacheFor: null,
|
|
138
137
|
cacheLogger: true,
|
|
139
138
|
requestAdapter: axiosRequestAdapter(),
|
|
140
139
|
}
|
|
141
140
|
|
|
141
|
+
/** 兼容不同 Method 元数据位置,优先读取请求配置内的选项。 */
|
|
142
142
|
function getMethodMeta(method: unknown): RequestMeta {
|
|
143
143
|
const methodRecord = method as { meta?: RequestMeta; config?: { meta?: RequestMeta } } | undefined
|
|
144
144
|
return methodRecord?.config?.meta ?? methodRecord?.meta ?? {}
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
/** 读取请求级布尔开关,未显式指定时使用实例默认值。 */
|
|
147
148
|
function getMetaFlag(meta: RequestMeta, key: keyof RequestMeta, fallback: boolean): boolean {
|
|
148
149
|
const value = meta[key]
|
|
149
150
|
return typeof value === 'boolean' ? value : fallback
|
|
150
151
|
}
|
|
151
152
|
|
|
153
|
+
/** 以单值、集合或自定义函数判断 HTTP 状态是否命中规则。 */
|
|
152
154
|
function isMatchedStatus<RE>(
|
|
153
155
|
status: number,
|
|
154
156
|
matcher: StatusMatcher<RE> | undefined,
|
|
@@ -161,18 +163,21 @@ function isMatchedStatus<RE>(
|
|
|
161
163
|
return Array.isArray(matcher) ? matcher.includes(status) : matcher === status
|
|
162
164
|
}
|
|
163
165
|
|
|
166
|
+
/** 将业务码转为字符串匹配;未配置匹配集合时视为命中。 */
|
|
164
167
|
function isMatchedCode(code: unknown, matcher: CodeMatcher | undefined): boolean {
|
|
165
168
|
if (!matcher?.length) return true
|
|
166
169
|
|
|
167
170
|
return matcher.some((item) => String(item) === String(code))
|
|
168
171
|
}
|
|
169
172
|
|
|
173
|
+
/** 兼容 statusCode 和 status 字段,将响应状态转换为数字。 */
|
|
170
174
|
function getResponseStatus(response: unknown): number {
|
|
171
175
|
const responseRecord = response as { status?: unknown; statusCode?: unknown }
|
|
172
176
|
const status = responseRecord.statusCode ?? responseRecord.status
|
|
173
177
|
return typeof status === 'number' ? status : Number(status)
|
|
174
178
|
}
|
|
175
179
|
|
|
180
|
+
/** 按配置字段及常见消息字段读取提示,内容不可用时返回默认文案。 */
|
|
176
181
|
function getResponseMessage(data: unknown, messageKey: string, defaultMessage: string): string {
|
|
177
182
|
if (!isPlainObject(data)) return defaultMessage
|
|
178
183
|
|
|
@@ -183,10 +188,17 @@ function getResponseMessage(data: unknown, messageKey: string, defaultMessage: s
|
|
|
183
188
|
return defaultMessage
|
|
184
189
|
}
|
|
185
190
|
|
|
191
|
+
/** 在请求实际完成时解析默认提示,使语言切换后无需重建请求实例。 */
|
|
192
|
+
function resolveMessage(message: MessageResolver): string {
|
|
193
|
+
return typeof message === 'function' ? message() : message
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** 仅从普通对象读取指定响应字段,其他响应形态返回 undefined。 */
|
|
186
197
|
function getResponseField(data: unknown, key: string): unknown {
|
|
187
198
|
return isPlainObject(data) ? data[key] : undefined
|
|
188
199
|
}
|
|
189
200
|
|
|
201
|
+
/** 根据内容类型解析 Fetch 响应,204 返回空值并为 JSON 失败提供文本回退。 */
|
|
190
202
|
async function parseFetchResponse(response: {
|
|
191
203
|
status?: number
|
|
192
204
|
body?: unknown
|
|
@@ -219,6 +231,7 @@ async function parseFetchResponse(response: {
|
|
|
219
231
|
return undefined
|
|
220
232
|
}
|
|
221
233
|
|
|
234
|
+
/** 兼容 Headers 和普通对象读取响应头,缺失或非字符串值返回空串。 */
|
|
222
235
|
function getHeaderValue(
|
|
223
236
|
headers: Headers | Record<string, unknown> | undefined,
|
|
224
237
|
key: string,
|
|
@@ -233,6 +246,7 @@ function getHeaderValue(
|
|
|
233
246
|
return typeof value === 'string' ? value : ''
|
|
234
247
|
}
|
|
235
248
|
|
|
249
|
+
/** 统一提取 Axios 或 Fetch 响应内容,并尝试解析对象、数组形式的 JSON 文本。 */
|
|
236
250
|
async function getResponseData(response: unknown): Promise<unknown> {
|
|
237
251
|
const responseRecord = response as {
|
|
238
252
|
body?: unknown
|
|
@@ -255,12 +269,14 @@ async function getResponseData(response: unknown): Promise<unknown> {
|
|
|
255
269
|
return response
|
|
256
270
|
}
|
|
257
271
|
|
|
272
|
+
/** 求值静态或异步请求头配置,忽略空值并将有效结果转为字符串。 */
|
|
258
273
|
async function resolveHeaderValue(value: HeaderValue): Promise<string | undefined> {
|
|
259
274
|
const resolved = typeof value === 'function' ? await value() : value
|
|
260
275
|
if (resolved === null || resolved === undefined) return undefined
|
|
261
276
|
return String(resolved)
|
|
262
277
|
}
|
|
263
278
|
|
|
279
|
+
/** 兼容 Headers、键值对数组及普通对象写入请求头。 */
|
|
264
280
|
function setHeader(target: unknown, key: string, value: string): void {
|
|
265
281
|
if (typeof Headers !== 'undefined' && target instanceof Headers) {
|
|
266
282
|
target.set(key, value)
|
|
@@ -275,12 +291,14 @@ function setHeader(target: unknown, key: string, value: string): void {
|
|
|
275
291
|
;(target as Record<string, string>)[key] = value
|
|
276
292
|
}
|
|
277
293
|
|
|
294
|
+
/** 将实例配置递归合并到请求默认项,保留未覆盖的默认设置。 */
|
|
278
295
|
function resolveConfig<RC extends object, RE, RH, SE extends StatesExport<any>>(
|
|
279
296
|
option: BaseRequestOption<RC, RE, RH, SE>,
|
|
280
297
|
): ResolvedRequestOption<RC, RE, RH, SE> {
|
|
281
298
|
return deepMergeObject(defaultRequestOption, option) as ResolvedRequestOption<RC, RE, RH, SE>
|
|
282
299
|
}
|
|
283
300
|
|
|
301
|
+
/** 创建统一处理公共请求头、响应解析、业务错误与未授权回调的 alova 实例。 */
|
|
284
302
|
export function createInstance<
|
|
285
303
|
RC extends object = AlovaAxiosRequestConfig,
|
|
286
304
|
RE = AxiosResponse,
|
|
@@ -289,10 +307,17 @@ export function createInstance<
|
|
|
289
307
|
>(option: RequestOption<RC, RE, RH, SE> = {}) {
|
|
290
308
|
const config = resolveConfig(option)
|
|
291
309
|
|
|
310
|
+
/** 从响应内容构造包含 HTTP 状态及业务码的可识别错误。 */
|
|
292
311
|
function responseError(data: unknown, status: number) {
|
|
293
312
|
const code = getResponseField(data, config.responseCodeKey)
|
|
294
313
|
return Object.assign(
|
|
295
|
-
new Error(
|
|
314
|
+
new Error(
|
|
315
|
+
getResponseMessage(
|
|
316
|
+
data,
|
|
317
|
+
config.responseMessageKey,
|
|
318
|
+
resolveMessage(config.errorDefaultMessage),
|
|
319
|
+
),
|
|
320
|
+
),
|
|
296
321
|
{ status, code: typeof code === 'string' || typeof code === 'number' ? code : undefined },
|
|
297
322
|
)
|
|
298
323
|
}
|
|
@@ -306,6 +331,7 @@ export function createInstance<
|
|
|
306
331
|
requestAdapter: config.requestAdapter!,
|
|
307
332
|
l1Cache: config.l1Cache,
|
|
308
333
|
l2Cache: config.l2Cache ?? config.storageAdapter,
|
|
334
|
+
/** 逐项求值公共请求头,并写入本次请求配置。 */
|
|
309
335
|
beforeRequest: async (method) => {
|
|
310
336
|
const methodConfig = method.config as { headers?: unknown }
|
|
311
337
|
const headers = methodConfig.headers ?? {}
|
|
@@ -318,6 +344,7 @@ export function createInstance<
|
|
|
318
344
|
},
|
|
319
345
|
responded: {
|
|
320
346
|
// HTTP 成败由适配器判断;这里只解析成功响应并检查业务 code。
|
|
347
|
+
/** 按请求元数据解析成功响应,检查业务码并按配置提示或返回业务数据。 */
|
|
321
348
|
onSuccess: async (response, method) => {
|
|
322
349
|
const meta = getMethodMeta(method)
|
|
323
350
|
const shouldTransform = getMetaFlag(meta, 'isTransformResponse', config.isTransformResponse)
|
|
@@ -331,7 +358,7 @@ export function createInstance<
|
|
|
331
358
|
const data = await getResponseData(response)
|
|
332
359
|
|
|
333
360
|
if (!isWrapped) {
|
|
334
|
-
if (showSuccess) config.successMessageFunc?.(config.successDefaultMessage)
|
|
361
|
+
if (showSuccess) config.successMessageFunc?.(resolveMessage(config.successDefaultMessage))
|
|
335
362
|
return data
|
|
336
363
|
}
|
|
337
364
|
|
|
@@ -340,7 +367,7 @@ export function createInstance<
|
|
|
340
367
|
const responseMessage = getResponseMessage(
|
|
341
368
|
data,
|
|
342
369
|
config.responseMessageKey,
|
|
343
|
-
config.successDefaultMessage,
|
|
370
|
+
resolveMessage(config.successDefaultMessage),
|
|
344
371
|
)
|
|
345
372
|
|
|
346
373
|
if (!isMatchedCode(code, config.codeMap.success)) {
|
|
@@ -349,7 +376,11 @@ export function createInstance<
|
|
|
349
376
|
|
|
350
377
|
if (showError) {
|
|
351
378
|
config.errorMessageFunc?.(
|
|
352
|
-
getResponseMessage(
|
|
379
|
+
getResponseMessage(
|
|
380
|
+
data,
|
|
381
|
+
config.responseMessageKey,
|
|
382
|
+
resolveMessage(config.errorDefaultMessage),
|
|
383
|
+
),
|
|
353
384
|
)
|
|
354
385
|
}
|
|
355
386
|
throw responseError(data, status)
|
|
@@ -360,6 +391,7 @@ export function createInstance<
|
|
|
360
391
|
return responseData
|
|
361
392
|
},
|
|
362
393
|
// 统一处理 HTTP 错误、网络故障和超时;onSuccess 抛出的业务错误直接传给调用方。
|
|
394
|
+
/** 统一处理 HTTP 和网络错误,触发未授权回调并抛出标准错误。 */
|
|
363
395
|
onError: async (error, method) => {
|
|
364
396
|
const meta = getMethodMeta(method)
|
|
365
397
|
const showError = getMetaFlag(meta, 'isShowErrorMessage', config.isShowErrorMessage)
|
|
@@ -373,7 +405,7 @@ export function createInstance<
|
|
|
373
405
|
}
|
|
374
406
|
failure = responseError(await getResponseData(response), status)
|
|
375
407
|
} else {
|
|
376
|
-
failure = new Error('无法连接服务,请检查网络后重试')
|
|
408
|
+
failure = new Error(tr('无法连接服务,请检查网络后重试'))
|
|
377
409
|
}
|
|
378
410
|
|
|
379
411
|
if (showError) {
|
|
@@ -402,6 +434,7 @@ export type DualCallInstance<
|
|
|
402
434
|
> = RequestInstance<RC, RE, RH, SE> &
|
|
403
435
|
((option?: RequestOption<RC, RE, RH, SE>) => RequestInstance<RC, RE, RH, SE>)
|
|
404
436
|
|
|
437
|
+
/** 提供默认请求实例的方法,同时支持通过函数调用创建覆盖配置的新实例。 */
|
|
405
438
|
export function createDualCallInstance<
|
|
406
439
|
RC extends object = AlovaAxiosRequestConfig,
|
|
407
440
|
RE = AxiosResponse,
|
|
@@ -409,7 +442,9 @@ export function createDualCallInstance<
|
|
|
409
442
|
SE extends StatesExport<any> = StatesExport<any>,
|
|
410
443
|
>(baseConfig: BaseRequestOption<RC, RE, RH, SE>): DualCallInstance<RC, RE, RH, SE> {
|
|
411
444
|
const defaultInstance = createInstance(baseConfig)
|
|
412
|
-
const dualInstance =
|
|
445
|
+
const dualInstance = /** 未传配置时复用默认请求实例,传入配置时合并基础设置创建独立实例。 */ ((
|
|
446
|
+
option?: RequestOption<RC, RE, RH, SE>,
|
|
447
|
+
) => {
|
|
413
448
|
if (!option) return defaultInstance
|
|
414
449
|
return createInstance(deepMergeObject(baseConfig, option))
|
|
415
450
|
}) as DualCallInstance<RC, RE, RH, SE>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
/** 递归合并普通对象,数组等非普通对象由目标值整体替换。 */
|
|
1
2
|
export function deepMergeObject<T = any>(source: T, target: Partial<T>): T {
|
|
3
|
+
/** 递归复制并合并目标对象属性,目标值未定义时沿用源值。 */
|
|
2
4
|
const merge = (src: any, tgt: any): any => {
|
|
3
5
|
if (!isPlainObject(src) || !isPlainObject(tgt)) return tgt === undefined ? src : tgt
|
|
4
6
|
|
|
@@ -14,15 +16,18 @@ export function deepMergeObject<T = any>(source: T, target: Partial<T>): T {
|
|
|
14
16
|
return merge(source, target)
|
|
15
17
|
}
|
|
16
18
|
|
|
19
|
+
/** 通过对象标签判断值是否为普通对象形态。 */
|
|
17
20
|
export function isPlainObject(data: unknown): data is Record<string, any> {
|
|
18
21
|
return Object.prototype.toString.call(data) === '[object Object]'
|
|
19
22
|
}
|
|
20
23
|
|
|
24
|
+
/** 在运行环境支持 ReadableStream 时判断响应体是否为流。 */
|
|
21
25
|
export function isReadableStream(data: unknown): boolean {
|
|
22
26
|
if (typeof ReadableStream === 'undefined') return false
|
|
23
27
|
return data instanceof ReadableStream
|
|
24
28
|
}
|
|
25
29
|
|
|
30
|
+
/** 仅尝试解析对象或数组形式的 JSON 字符串,解析失败时保留原值。 */
|
|
26
31
|
export function tryParseJsonString(data: unknown): unknown {
|
|
27
32
|
if (typeof data !== 'string') return data
|
|
28
33
|
|
|
@@ -2,6 +2,7 @@ import { axiosRequestAdapter, type AlovaAxiosRequestConfig } from '@alova/adapte
|
|
|
2
2
|
import reactHook, { type ReactHookExportType } from 'alova/react'
|
|
3
3
|
import { message } from 'antd'
|
|
4
4
|
import type { AxiosResponse, AxiosResponseHeaders } from 'axios'
|
|
5
|
+
import { tr } from '@/i18n'
|
|
5
6
|
import { envVariables } from '@/utils/env'
|
|
6
7
|
import { cookie } from '@/utils/storage/cookie'
|
|
7
8
|
import { createDualCallInstance, type BaseRequestOption } from './core/index.ts'
|
|
@@ -13,6 +14,7 @@ type WebRequestOption = BaseRequestOption<
|
|
|
13
14
|
ReactHookExportType<unknown>
|
|
14
15
|
>
|
|
15
16
|
|
|
17
|
+
/** 保留完整 URL 和绝对路径,为相对接口前缀补齐开头斜杠。 */
|
|
16
18
|
function normalizeBaseUrl(apiAffix?: string) {
|
|
17
19
|
if (!apiAffix) return '/'
|
|
18
20
|
if (/^https?:\/\//.test(apiAffix) || apiAffix.startsWith('/')) {
|
|
@@ -22,6 +24,7 @@ function normalizeBaseUrl(apiAffix?: string) {
|
|
|
22
24
|
return `/${apiAffix}`
|
|
23
25
|
}
|
|
24
26
|
|
|
27
|
+
/** 组装 Web 请求配置,绑定登录凭据、提示方式及未授权跳转。 */
|
|
25
28
|
function getBaseConfig(): WebRequestOption {
|
|
26
29
|
return {
|
|
27
30
|
baseUrl: normalizeBaseUrl(envVariables.API_AFFIX),
|
|
@@ -35,7 +38,8 @@ function getBaseConfig(): WebRequestOption {
|
|
|
35
38
|
},
|
|
36
39
|
responseDataKey: 'data',
|
|
37
40
|
responseMessageKey: 'message',
|
|
38
|
-
errorDefaultMessage: '请求失败,请稍后重试',
|
|
41
|
+
errorDefaultMessage: () => tr('请求失败,请稍后重试'),
|
|
42
|
+
/** 在发送请求时读取最新登录令牌,存在时附加 Bearer 鉴权头。 */
|
|
39
43
|
commonHeaders: () => {
|
|
40
44
|
const token = cookie.get('token')
|
|
41
45
|
return token ? { Authorization: `Bearer ${token}` } : {}
|
|
@@ -46,9 +50,10 @@ function getBaseConfig(): WebRequestOption {
|
|
|
46
50
|
errorMessageFunc: (msg) => {
|
|
47
51
|
message.error(msg)
|
|
48
52
|
},
|
|
53
|
+
/** 清除失效登录令牌,提示登录过期并跳转到登录页。 */
|
|
49
54
|
unAuthorizedResponseFunc: () => {
|
|
50
55
|
cookie.remove('token')
|
|
51
|
-
message.error('登录过期或未登录')
|
|
56
|
+
message.error(tr('登录过期或未登录'))
|
|
52
57
|
window.location.assign('/login')
|
|
53
58
|
},
|
|
54
59
|
statesHook: reactHook,
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import request from './index'
|
|
2
|
+
import { cookie } from '@/utils/storage/cookie'
|
|
3
|
+
|
|
4
|
+
/** 权限和管理数据不进入 alova 缓存;每个工作空间代次都有独立的在途请求集合。 */
|
|
5
|
+
export const workspaceRequest = request({
|
|
6
|
+
cacheFor: { GET: 0, POST: 0, PUT: 0, PATCH: 0, DELETE: 0, HEAD: 0, OPTIONS: 0 },
|
|
7
|
+
cacheLogger: false,
|
|
8
|
+
isShowErrorMessage: false,
|
|
9
|
+
/** 延后到请求代次校验后再处理 401,防止旧会话的迟到失败退出新会话。 */
|
|
10
|
+
unAuthorizedResponseFunc: () => {},
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
let currentKey = ''
|
|
14
|
+
let generation = 0
|
|
15
|
+
const pending = new Set<() => void>()
|
|
16
|
+
|
|
17
|
+
/** 推进工作空间代次并中止所有在途请求,使迟到结果立即失效。 */
|
|
18
|
+
export function clearWorkspaceRequests() {
|
|
19
|
+
generation += 1
|
|
20
|
+
for (const abort of pending) abort()
|
|
21
|
+
pending.clear()
|
|
22
|
+
currentKey = ''
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** 按会话令牌和工作空间键识别切换,切换时清理旧空间请求。 */
|
|
26
|
+
export function enterWorkspace(key: string) {
|
|
27
|
+
const identityKey = `${cookie.get('token') ?? ''}:${key}`
|
|
28
|
+
if (identityKey !== currentKey) {
|
|
29
|
+
clearWorkspaceRequests()
|
|
30
|
+
currentKey = identityKey
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** 通知工作空间布局重新校验权限及导航数据。 */
|
|
35
|
+
export function refreshAccess() {
|
|
36
|
+
window.dispatchEvent(new Event('workspace-access-refresh'))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const freshRequest = { cacheFor: 0, shareRequest: false } as const
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 在指定工作空间代次内发送请求,丢弃跨账号、跨空间或已取消的结果。
|
|
43
|
+
* `workspaceKey` 必须由 API 创建时绑定,不能在实际发送时读取当前空间后补写。
|
|
44
|
+
*/
|
|
45
|
+
export async function runWorkspaceRequest<T>(options: {
|
|
46
|
+
method: { send: (force?: boolean) => Promise<T>; abort: () => void }
|
|
47
|
+
workspaceKey: string
|
|
48
|
+
signal?: AbortSignal
|
|
49
|
+
accessRequest?: boolean
|
|
50
|
+
}): Promise<T> {
|
|
51
|
+
const { method, workspaceKey, signal, accessRequest } = options
|
|
52
|
+
const startedAt = generation
|
|
53
|
+
const token = cookie.get('token')
|
|
54
|
+
const identityKey = `${token ?? ''}:${workspaceKey}`
|
|
55
|
+
const abort = () => method.abort()
|
|
56
|
+
/** 检查取消信号、调用方空间、工作空间代次及登录令牌,判断请求是否已经过期。 */
|
|
57
|
+
const stale = () =>
|
|
58
|
+
signal?.aborted ||
|
|
59
|
+
currentKey !== identityKey ||
|
|
60
|
+
generation !== startedAt ||
|
|
61
|
+
token !== cookie.get('token')
|
|
62
|
+
if (stale()) throw new DOMException('请求已取消', 'AbortError')
|
|
63
|
+
pending.add(abort)
|
|
64
|
+
signal?.addEventListener('abort', abort, { once: true })
|
|
65
|
+
try {
|
|
66
|
+
const result = await method.send(true)
|
|
67
|
+
if (stale()) throw new DOMException('工作空间已切换', 'AbortError')
|
|
68
|
+
return result
|
|
69
|
+
} catch (error) {
|
|
70
|
+
if (stale()) throw new DOMException('工作空间已切换', 'AbortError')
|
|
71
|
+
if ((error as { status?: number }).status === 401) {
|
|
72
|
+
clearWorkspaceRequests()
|
|
73
|
+
cookie.remove('token')
|
|
74
|
+
window.location.assign('/login')
|
|
75
|
+
}
|
|
76
|
+
if (!accessRequest && (error as { status?: number }).status === 403) refreshAccess()
|
|
77
|
+
throw error
|
|
78
|
+
} finally {
|
|
79
|
+
pending.delete(abort)
|
|
80
|
+
signal?.removeEventListener('abort', abort)
|
|
81
|
+
}
|
|
82
|
+
}
|