feat(web): add workspace management UI (M2 #12)
- Create workspace listing page at /settings/workspaces - List all user workspaces with role badges - Create new workspace functionality - Display member count per workspace - Create workspace detail page at /settings/workspaces/[id] - Workspace settings (name, ID, created date) - Member management with role editing - Invite member functionality - Delete workspace (owner only) - Add workspace components: - WorkspaceCard: Display workspace info with role badge - WorkspaceSettings: Edit workspace settings and delete - MemberList: Display and manage workspace members - InviteMember: Send invitations with role selection - Add WorkspaceMemberWithUser type to shared package - Follow existing app patterns for styling and structure - Use mock data (ready for API integration)
This commit is contained in:
2
apps/api/src/common/decorators/index.ts
Normal file
2
apps/api/src/common/decorators/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./permissions.decorator";
|
||||
export * from "./workspace.decorator";
|
||||
48
apps/api/src/common/decorators/permissions.decorator.ts
Normal file
48
apps/api/src/common/decorators/permissions.decorator.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { SetMetadata } from "@nestjs/common";
|
||||
|
||||
/**
|
||||
* Permission levels for workspace access control.
|
||||
* These map to WorkspaceMemberRole from the database schema.
|
||||
*/
|
||||
export enum Permission {
|
||||
/** Requires OWNER role - full control over workspace */
|
||||
WORKSPACE_OWNER = "workspace:owner",
|
||||
|
||||
/** Requires ADMIN or OWNER role - administrative functions */
|
||||
WORKSPACE_ADMIN = "workspace:admin",
|
||||
|
||||
/** Requires MEMBER, ADMIN, or OWNER role - standard access */
|
||||
WORKSPACE_MEMBER = "workspace:member",
|
||||
|
||||
/** Any authenticated workspace member including GUEST */
|
||||
WORKSPACE_ANY = "workspace:any",
|
||||
}
|
||||
|
||||
export const PERMISSION_KEY = "permission";
|
||||
|
||||
/**
|
||||
* Decorator to specify required permission level for a route.
|
||||
* Use with PermissionGuard to enforce role-based access control.
|
||||
*
|
||||
* @param permission - The minimum permission level required
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* @RequirePermission(Permission.WORKSPACE_ADMIN)
|
||||
* @Delete(':id')
|
||||
* async deleteWorkspace(@Param('id') id: string) {
|
||||
* // Only ADMIN or OWNER can execute this
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* @RequirePermission(Permission.WORKSPACE_MEMBER)
|
||||
* @Get()
|
||||
* async getTasks() {
|
||||
* // Any workspace member can execute this
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export const RequirePermission = (permission: Permission) =>
|
||||
SetMetadata(PERMISSION_KEY, permission);
|
||||
40
apps/api/src/common/decorators/workspace.decorator.ts
Normal file
40
apps/api/src/common/decorators/workspace.decorator.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { createParamDecorator, ExecutionContext } from "@nestjs/common";
|
||||
|
||||
/**
|
||||
* Decorator to extract workspace ID from the request.
|
||||
* Must be used with WorkspaceGuard which validates and attaches the workspace.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* @Get()
|
||||
* @UseGuards(AuthGuard, WorkspaceGuard)
|
||||
* async getTasks(@Workspace() workspaceId: string) {
|
||||
* // workspaceId is validated and ready to use
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export const Workspace = createParamDecorator(
|
||||
(_data: unknown, ctx: ExecutionContext): string => {
|
||||
const request = ctx.switchToHttp().getRequest();
|
||||
return request.workspace?.id;
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Decorator to extract full workspace context from the request.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* @Get()
|
||||
* @UseGuards(AuthGuard, WorkspaceGuard)
|
||||
* async getTasks(@WorkspaceContext() workspace: { id: string }) {
|
||||
* console.log(workspace.id);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export const WorkspaceContext = createParamDecorator(
|
||||
(_data: unknown, ctx: ExecutionContext) => {
|
||||
const request = ctx.switchToHttp().getRequest();
|
||||
return request.workspace;
|
||||
}
|
||||
);
|
||||
Reference in New Issue
Block a user