Add roles and users admin UI with role management API
Backend: - GET /v1/users (list company users) - GET/POST/PATCH/DELETE /v1/roles (role CRUD with permissions) - GET/POST/DELETE /v1/users/:userId/roles (role assignment) - GET /v1/me/permissions (current user's effective permissions) Frontend: - Roles list page with kebab menu (edit permissions, delete custom) - Role detail page with grouped permission checkboxes and inheritance note - New role page with auto-generated slug - Users list page showing assigned roles per user - Manage Roles dialog for adding/removing roles per user - Sidebar: Admin section with Users, Roles, Help links
This commit is contained in:
@@ -12,9 +12,13 @@ import { Route as rootRouteImport } from './routes/__root'
|
||||
import { Route as LoginRouteImport } from './routes/login'
|
||||
import { Route as AuthenticatedRouteImport } from './routes/_authenticated'
|
||||
import { Route as AuthenticatedIndexRouteImport } from './routes/_authenticated/index'
|
||||
import { Route as AuthenticatedUsersRouteImport } from './routes/_authenticated/users'
|
||||
import { Route as AuthenticatedHelpRouteImport } from './routes/_authenticated/help'
|
||||
import { Route as AuthenticatedRolesIndexRouteImport } from './routes/_authenticated/roles/index'
|
||||
import { Route as AuthenticatedMembersIndexRouteImport } from './routes/_authenticated/members/index'
|
||||
import { Route as AuthenticatedAccountsIndexRouteImport } from './routes/_authenticated/accounts/index'
|
||||
import { Route as AuthenticatedRolesNewRouteImport } from './routes/_authenticated/roles/new'
|
||||
import { Route as AuthenticatedRolesRoleIdRouteImport } from './routes/_authenticated/roles/$roleId'
|
||||
import { Route as AuthenticatedMembersMemberIdRouteImport } from './routes/_authenticated/members/$memberId'
|
||||
import { Route as AuthenticatedAccountsNewRouteImport } from './routes/_authenticated/accounts/new'
|
||||
import { Route as AuthenticatedAccountsAccountIdRouteImport } from './routes/_authenticated/accounts/$accountId'
|
||||
@@ -38,11 +42,21 @@ const AuthenticatedIndexRoute = AuthenticatedIndexRouteImport.update({
|
||||
path: '/',
|
||||
getParentRoute: () => AuthenticatedRoute,
|
||||
} as any)
|
||||
const AuthenticatedUsersRoute = AuthenticatedUsersRouteImport.update({
|
||||
id: '/users',
|
||||
path: '/users',
|
||||
getParentRoute: () => AuthenticatedRoute,
|
||||
} as any)
|
||||
const AuthenticatedHelpRoute = AuthenticatedHelpRouteImport.update({
|
||||
id: '/help',
|
||||
path: '/help',
|
||||
getParentRoute: () => AuthenticatedRoute,
|
||||
} as any)
|
||||
const AuthenticatedRolesIndexRoute = AuthenticatedRolesIndexRouteImport.update({
|
||||
id: '/roles/',
|
||||
path: '/roles/',
|
||||
getParentRoute: () => AuthenticatedRoute,
|
||||
} as any)
|
||||
const AuthenticatedMembersIndexRoute =
|
||||
AuthenticatedMembersIndexRouteImport.update({
|
||||
id: '/members/',
|
||||
@@ -55,6 +69,17 @@ const AuthenticatedAccountsIndexRoute =
|
||||
path: '/accounts/',
|
||||
getParentRoute: () => AuthenticatedRoute,
|
||||
} as any)
|
||||
const AuthenticatedRolesNewRoute = AuthenticatedRolesNewRouteImport.update({
|
||||
id: '/roles/new',
|
||||
path: '/roles/new',
|
||||
getParentRoute: () => AuthenticatedRoute,
|
||||
} as any)
|
||||
const AuthenticatedRolesRoleIdRoute =
|
||||
AuthenticatedRolesRoleIdRouteImport.update({
|
||||
id: '/roles/$roleId',
|
||||
path: '/roles/$roleId',
|
||||
getParentRoute: () => AuthenticatedRoute,
|
||||
} as any)
|
||||
const AuthenticatedMembersMemberIdRoute =
|
||||
AuthenticatedMembersMemberIdRouteImport.update({
|
||||
id: '/members/$memberId',
|
||||
@@ -108,11 +133,15 @@ export interface FileRoutesByFullPath {
|
||||
'/': typeof AuthenticatedIndexRoute
|
||||
'/login': typeof LoginRoute
|
||||
'/help': typeof AuthenticatedHelpRoute
|
||||
'/users': typeof AuthenticatedUsersRoute
|
||||
'/accounts/$accountId': typeof AuthenticatedAccountsAccountIdRouteWithChildren
|
||||
'/accounts/new': typeof AuthenticatedAccountsNewRoute
|
||||
'/members/$memberId': typeof AuthenticatedMembersMemberIdRoute
|
||||
'/roles/$roleId': typeof AuthenticatedRolesRoleIdRoute
|
||||
'/roles/new': typeof AuthenticatedRolesNewRoute
|
||||
'/accounts/': typeof AuthenticatedAccountsIndexRoute
|
||||
'/members/': typeof AuthenticatedMembersIndexRoute
|
||||
'/roles/': typeof AuthenticatedRolesIndexRoute
|
||||
'/accounts/$accountId/members': typeof AuthenticatedAccountsAccountIdMembersRoute
|
||||
'/accounts/$accountId/payment-methods': typeof AuthenticatedAccountsAccountIdPaymentMethodsRoute
|
||||
'/accounts/$accountId/processor-links': typeof AuthenticatedAccountsAccountIdProcessorLinksRoute
|
||||
@@ -122,11 +151,15 @@ export interface FileRoutesByFullPath {
|
||||
export interface FileRoutesByTo {
|
||||
'/login': typeof LoginRoute
|
||||
'/help': typeof AuthenticatedHelpRoute
|
||||
'/users': typeof AuthenticatedUsersRoute
|
||||
'/': typeof AuthenticatedIndexRoute
|
||||
'/accounts/new': typeof AuthenticatedAccountsNewRoute
|
||||
'/members/$memberId': typeof AuthenticatedMembersMemberIdRoute
|
||||
'/roles/$roleId': typeof AuthenticatedRolesRoleIdRoute
|
||||
'/roles/new': typeof AuthenticatedRolesNewRoute
|
||||
'/accounts': typeof AuthenticatedAccountsIndexRoute
|
||||
'/members': typeof AuthenticatedMembersIndexRoute
|
||||
'/roles': typeof AuthenticatedRolesIndexRoute
|
||||
'/accounts/$accountId/members': typeof AuthenticatedAccountsAccountIdMembersRoute
|
||||
'/accounts/$accountId/payment-methods': typeof AuthenticatedAccountsAccountIdPaymentMethodsRoute
|
||||
'/accounts/$accountId/processor-links': typeof AuthenticatedAccountsAccountIdProcessorLinksRoute
|
||||
@@ -138,12 +171,16 @@ export interface FileRoutesById {
|
||||
'/_authenticated': typeof AuthenticatedRouteWithChildren
|
||||
'/login': typeof LoginRoute
|
||||
'/_authenticated/help': typeof AuthenticatedHelpRoute
|
||||
'/_authenticated/users': typeof AuthenticatedUsersRoute
|
||||
'/_authenticated/': typeof AuthenticatedIndexRoute
|
||||
'/_authenticated/accounts/$accountId': typeof AuthenticatedAccountsAccountIdRouteWithChildren
|
||||
'/_authenticated/accounts/new': typeof AuthenticatedAccountsNewRoute
|
||||
'/_authenticated/members/$memberId': typeof AuthenticatedMembersMemberIdRoute
|
||||
'/_authenticated/roles/$roleId': typeof AuthenticatedRolesRoleIdRoute
|
||||
'/_authenticated/roles/new': typeof AuthenticatedRolesNewRoute
|
||||
'/_authenticated/accounts/': typeof AuthenticatedAccountsIndexRoute
|
||||
'/_authenticated/members/': typeof AuthenticatedMembersIndexRoute
|
||||
'/_authenticated/roles/': typeof AuthenticatedRolesIndexRoute
|
||||
'/_authenticated/accounts/$accountId/members': typeof AuthenticatedAccountsAccountIdMembersRoute
|
||||
'/_authenticated/accounts/$accountId/payment-methods': typeof AuthenticatedAccountsAccountIdPaymentMethodsRoute
|
||||
'/_authenticated/accounts/$accountId/processor-links': typeof AuthenticatedAccountsAccountIdProcessorLinksRoute
|
||||
@@ -156,11 +193,15 @@ export interface FileRouteTypes {
|
||||
| '/'
|
||||
| '/login'
|
||||
| '/help'
|
||||
| '/users'
|
||||
| '/accounts/$accountId'
|
||||
| '/accounts/new'
|
||||
| '/members/$memberId'
|
||||
| '/roles/$roleId'
|
||||
| '/roles/new'
|
||||
| '/accounts/'
|
||||
| '/members/'
|
||||
| '/roles/'
|
||||
| '/accounts/$accountId/members'
|
||||
| '/accounts/$accountId/payment-methods'
|
||||
| '/accounts/$accountId/processor-links'
|
||||
@@ -170,11 +211,15 @@ export interface FileRouteTypes {
|
||||
to:
|
||||
| '/login'
|
||||
| '/help'
|
||||
| '/users'
|
||||
| '/'
|
||||
| '/accounts/new'
|
||||
| '/members/$memberId'
|
||||
| '/roles/$roleId'
|
||||
| '/roles/new'
|
||||
| '/accounts'
|
||||
| '/members'
|
||||
| '/roles'
|
||||
| '/accounts/$accountId/members'
|
||||
| '/accounts/$accountId/payment-methods'
|
||||
| '/accounts/$accountId/processor-links'
|
||||
@@ -185,12 +230,16 @@ export interface FileRouteTypes {
|
||||
| '/_authenticated'
|
||||
| '/login'
|
||||
| '/_authenticated/help'
|
||||
| '/_authenticated/users'
|
||||
| '/_authenticated/'
|
||||
| '/_authenticated/accounts/$accountId'
|
||||
| '/_authenticated/accounts/new'
|
||||
| '/_authenticated/members/$memberId'
|
||||
| '/_authenticated/roles/$roleId'
|
||||
| '/_authenticated/roles/new'
|
||||
| '/_authenticated/accounts/'
|
||||
| '/_authenticated/members/'
|
||||
| '/_authenticated/roles/'
|
||||
| '/_authenticated/accounts/$accountId/members'
|
||||
| '/_authenticated/accounts/$accountId/payment-methods'
|
||||
| '/_authenticated/accounts/$accountId/processor-links'
|
||||
@@ -226,6 +275,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof AuthenticatedIndexRouteImport
|
||||
parentRoute: typeof AuthenticatedRoute
|
||||
}
|
||||
'/_authenticated/users': {
|
||||
id: '/_authenticated/users'
|
||||
path: '/users'
|
||||
fullPath: '/users'
|
||||
preLoaderRoute: typeof AuthenticatedUsersRouteImport
|
||||
parentRoute: typeof AuthenticatedRoute
|
||||
}
|
||||
'/_authenticated/help': {
|
||||
id: '/_authenticated/help'
|
||||
path: '/help'
|
||||
@@ -233,6 +289,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof AuthenticatedHelpRouteImport
|
||||
parentRoute: typeof AuthenticatedRoute
|
||||
}
|
||||
'/_authenticated/roles/': {
|
||||
id: '/_authenticated/roles/'
|
||||
path: '/roles'
|
||||
fullPath: '/roles/'
|
||||
preLoaderRoute: typeof AuthenticatedRolesIndexRouteImport
|
||||
parentRoute: typeof AuthenticatedRoute
|
||||
}
|
||||
'/_authenticated/members/': {
|
||||
id: '/_authenticated/members/'
|
||||
path: '/members'
|
||||
@@ -247,6 +310,20 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof AuthenticatedAccountsIndexRouteImport
|
||||
parentRoute: typeof AuthenticatedRoute
|
||||
}
|
||||
'/_authenticated/roles/new': {
|
||||
id: '/_authenticated/roles/new'
|
||||
path: '/roles/new'
|
||||
fullPath: '/roles/new'
|
||||
preLoaderRoute: typeof AuthenticatedRolesNewRouteImport
|
||||
parentRoute: typeof AuthenticatedRoute
|
||||
}
|
||||
'/_authenticated/roles/$roleId': {
|
||||
id: '/_authenticated/roles/$roleId'
|
||||
path: '/roles/$roleId'
|
||||
fullPath: '/roles/$roleId'
|
||||
preLoaderRoute: typeof AuthenticatedRolesRoleIdRouteImport
|
||||
parentRoute: typeof AuthenticatedRoute
|
||||
}
|
||||
'/_authenticated/members/$memberId': {
|
||||
id: '/_authenticated/members/$memberId'
|
||||
path: '/members/$memberId'
|
||||
@@ -335,23 +412,31 @@ const AuthenticatedAccountsAccountIdRouteWithChildren =
|
||||
|
||||
interface AuthenticatedRouteChildren {
|
||||
AuthenticatedHelpRoute: typeof AuthenticatedHelpRoute
|
||||
AuthenticatedUsersRoute: typeof AuthenticatedUsersRoute
|
||||
AuthenticatedIndexRoute: typeof AuthenticatedIndexRoute
|
||||
AuthenticatedAccountsAccountIdRoute: typeof AuthenticatedAccountsAccountIdRouteWithChildren
|
||||
AuthenticatedAccountsNewRoute: typeof AuthenticatedAccountsNewRoute
|
||||
AuthenticatedMembersMemberIdRoute: typeof AuthenticatedMembersMemberIdRoute
|
||||
AuthenticatedRolesRoleIdRoute: typeof AuthenticatedRolesRoleIdRoute
|
||||
AuthenticatedRolesNewRoute: typeof AuthenticatedRolesNewRoute
|
||||
AuthenticatedAccountsIndexRoute: typeof AuthenticatedAccountsIndexRoute
|
||||
AuthenticatedMembersIndexRoute: typeof AuthenticatedMembersIndexRoute
|
||||
AuthenticatedRolesIndexRoute: typeof AuthenticatedRolesIndexRoute
|
||||
}
|
||||
|
||||
const AuthenticatedRouteChildren: AuthenticatedRouteChildren = {
|
||||
AuthenticatedHelpRoute: AuthenticatedHelpRoute,
|
||||
AuthenticatedUsersRoute: AuthenticatedUsersRoute,
|
||||
AuthenticatedIndexRoute: AuthenticatedIndexRoute,
|
||||
AuthenticatedAccountsAccountIdRoute:
|
||||
AuthenticatedAccountsAccountIdRouteWithChildren,
|
||||
AuthenticatedAccountsNewRoute: AuthenticatedAccountsNewRoute,
|
||||
AuthenticatedMembersMemberIdRoute: AuthenticatedMembersMemberIdRoute,
|
||||
AuthenticatedRolesRoleIdRoute: AuthenticatedRolesRoleIdRoute,
|
||||
AuthenticatedRolesNewRoute: AuthenticatedRolesNewRoute,
|
||||
AuthenticatedAccountsIndexRoute: AuthenticatedAccountsIndexRoute,
|
||||
AuthenticatedMembersIndexRoute: AuthenticatedMembersIndexRoute,
|
||||
AuthenticatedRolesIndexRoute: AuthenticatedRolesIndexRoute,
|
||||
}
|
||||
|
||||
const AuthenticatedRouteWithChildren = AuthenticatedRoute._addFileChildren(
|
||||
Reference in New Issue
Block a user