fix & enhance workspace

This commit is contained in:
2026-06-30 10:44:50 +03:30
parent d24abe7ee4
commit 9d8ff3603e
6 changed files with 123 additions and 68 deletions
@@ -0,0 +1,53 @@
import { Controller, Get, Post, Patch, Delete, Param, Body } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
import { WorkspaceService } from '../providers/workspace.service';
import { CreateWorkspaceDto } from '../dto/workspace/create-workspace.dto';
import { UpdateWorkspaceDto } from '../dto/workspace/update-workspace.dto';
import { TMWorkspace } from '../entities/workspace.entity';
@ApiTags('Task Manager - Workspaces')
@Controller('task-manager/workspaces')
export class WorkspaceController {
constructor(private readonly workspaceService: WorkspaceService) {}
@Get()
@ApiOperation({ summary: 'Get all workspaces' })
@ApiResponse({ status: 200, description: 'List of workspaces', type: [TMWorkspace] })
findAll(): Promise<TMWorkspace[]> {
return this.workspaceService.findAll();
}
@Get(':id')
@ApiOperation({ summary: 'Get a workspace by ID' })
@ApiParam({ name: 'id', description: 'Workspace ID' })
@ApiResponse({ status: 200, description: 'Workspace found', type: TMWorkspace })
@ApiResponse({ status: 404, description: 'Workspace not found' })
findOne(@Param('id') id: string): Promise<TMWorkspace> {
return this.workspaceService.findOneOrFail(id);
}
@Post()
@ApiOperation({ summary: 'Create a new workspace' })
@ApiResponse({ status: 201, description: 'Workspace created', type: TMWorkspace })
create(@Body() body: CreateWorkspaceDto): Promise<TMWorkspace> {
return this.workspaceService.create(body);
}
@Patch(':id')
@ApiOperation({ summary: 'Update a workspace' })
@ApiParam({ name: 'id', description: 'Workspace ID' })
@ApiResponse({ status: 200, description: 'Workspace updated', type: TMWorkspace })
@ApiResponse({ status: 404, description: 'Workspace not found' })
update(@Param('id') id: string, @Body() body: UpdateWorkspaceDto): Promise<TMWorkspace> {
return this.workspaceService.update(id, body);
}
@Delete(':id')
@ApiOperation({ summary: 'Delete a workspace' })
@ApiParam({ name: 'id', description: 'Workspace ID' })
@ApiResponse({ status: 200, description: 'Workspace deleted' })
@ApiResponse({ status: 404, description: 'Workspace not found' })
remove(@Param('id') id: string): Promise<void> {
return this.workspaceService.remove(id);
}
}
@@ -1,25 +1,40 @@
import { ApiProperty } from "@nestjs/swagger";
import { IsString, IsOptional, IsBoolean, IsNotEmpty, IsUUID, MaxLength } from "class-validator"; import { IsString, IsOptional, IsBoolean, IsNotEmpty, IsUUID, MaxLength } from "class-validator";
export class CreateWorkspaceDto { export class CreateWorkspaceDto {
@ApiProperty({ description: "Name of the workspace", example: "Engineering" })
@IsString() @IsString()
@IsNotEmpty() @IsNotEmpty()
@MaxLength(100) @MaxLength(100)
name: string; name: string;
@ApiProperty({ description: "ID of the workspace type", example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" })
@IsUUID()
@IsNotEmpty()
workspaceTypeId: string;
@ApiProperty({ description: "Description of the workspace", required: false, example: "Workspace for the engineering team" })
@IsString() @IsString()
@IsOptional() @IsOptional()
description?: string; description?: string;
@ApiProperty({ description: "Color code for the workspace (hex or named)", example: "#4F46E5" })
@IsString() @IsString()
@IsNotEmpty() @IsNotEmpty()
@MaxLength(20) @MaxLength(20)
color: string; color: string;
@ApiProperty({ description: "Whether the workspace is active", required: false, default: true, example: true })
@IsBoolean() @IsBoolean()
@IsOptional() isActive: boolean;
isActive?: boolean;
@IsUUID() @ApiProperty({
@IsNotEmpty() description: "IDs of users to assign to the workspace",
workspaceTypeId: string; required: false,
type: [String],
example: ["b2c3d4e5-f6a7-8901-bcde-f12345678901"],
})
@IsUUID("4", { each: true })
@IsOptional()
userIds?: string[];
} }
@@ -1,4 +1,4 @@
import { PartialType } from "@nestjs/mapped-types"; import { PartialType } from "@nestjs/swagger";
import { CreateWorkspaceDto } from "./create-workspace.dto"; import { CreateWorkspaceDto } from "./create-workspace.dto";
export class UpdateWorkspaceDto extends PartialType(CreateWorkspaceDto) {} export class UpdateWorkspaceDto extends PartialType(CreateWorkspaceDto) {}
@@ -1,41 +1,64 @@
import { Injectable, NotFoundException } from "@nestjs/common"; import { Injectable, NotFoundException } from '@nestjs/common';
import { CreateWorkspaceDto } from "../dto/workspace/create-workspace.dto"; import { InjectRepository } from '@nestjs/typeorm';
import { WorkspaceRepository } from "../repositories/workspace.repository"; import { In, Repository } from 'typeorm';
import { UpdateWorkspaceDto } from "../dto/workspace/update-workspace.dto"; import { TMWorkspace } from '../entities/workspace.entity';
import { CreateWorkspaceDto } from '../dto/workspace/create-workspace.dto';
import { UpdateWorkspaceDto } from '../dto/workspace/update-workspace.dto';
import { User } from '../../users/entities/user.entity';
@Injectable() @Injectable()
export class WorkspaceService { export class WorkspaceService {
constructor( constructor(
private readonly workspaceRepository: WorkspaceRepository, @InjectRepository(TMWorkspace)
private readonly workspaceRepository: Repository<TMWorkspace>,
@InjectRepository(User)
private readonly userRepository: Repository<User>,
) {} ) {}
findAll() { findAll(): Promise<TMWorkspace[]> {
return this.workspaceRepository.findAll(); return this.workspaceRepository.find({
} relations: ['workspaceType', 'projects', 'users'],
});
async findOne(id: string) {
const workspace = await this.workspaceRepository.findOneById(id);
if (!workspace) {
throw new NotFoundException(`Workspace #${id} not found`);
} }
async findOneOrFail(id: string): Promise<TMWorkspace> {
const workspace = await this.workspaceRepository.findOne({
where: { id },
relations: ['workspaceType', 'projects', 'users'],
});
if (!workspace) throw new NotFoundException(`Workspace #${id} not found`);
return workspace; return workspace;
} }
async create(dto: CreateWorkspaceDto) { async create(dto: CreateWorkspaceDto): Promise<TMWorkspace> {
const workspace = this.workspaceRepository.create(dto); const { userIds, ...rest } = dto;
const workspace = this.workspaceRepository.create(rest);
if (userIds?.length) {
workspace.users = await this.userRepository.findBy({ id: In(userIds) });
}
return this.workspaceRepository.save(workspace); return this.workspaceRepository.save(workspace);
} }
async update(id: string, dto: UpdateWorkspaceDto) { async update(id: string, dto: UpdateWorkspaceDto): Promise<TMWorkspace> {
await this.findOne(id); const workspace = await this.findOneOrFail(id);
await this.workspaceRepository.update(id, dto); const { userIds, ...rest } = dto;
return this.findOne(id);
Object.assign(workspace, rest);
if (userIds) {
workspace.users = userIds.length
? await this.userRepository.findBy({ id: In(userIds) })
: [];
} }
async remove(id: string) { return this.workspaceRepository.save(workspace);
await this.findOne(id); }
async remove(id: string): Promise<void> {
await this.findOneOrFail(id);
await this.workspaceRepository.delete(id); await this.workspaceRepository.delete(id);
} }
} }
@@ -1,38 +0,0 @@
import { Controller, Get, Post, Patch, Delete, Param, Body } from '@nestjs/common';
import { TMWorkspace } from './entities/workspace.entity';
import { WorkspaceService } from './providers/workspace.service';
import { CreateWorkspaceDto } from './dto/workspace/create-workspace.dto';
import { UpdateWorkspaceDto } from './dto/workspace/update-workspace.dto';
@Controller('task-manager')
export class TaskManagerController {
constructor(
private readonly workspaceService: WorkspaceService,
) {}
// --- Workspace ---
@Get('workspaces')
findAllWorkspaces(): Promise<TMWorkspace[]> {
return this.workspaceService.findAll();
}
@Get('workspaces/:id')
findOneWorkspace(@Param('id') id: string): Promise<TMWorkspace> {
return this.workspaceService.findOne(id);
}
@Post('workspaces')
createWorkspace(@Body() body: CreateWorkspaceDto): Promise<TMWorkspace> {
return this.workspaceService.create(body);
}
@Patch('workspaces/:id')
updateWorkspace(@Param('id') id: string, @Body() body: UpdateWorkspaceDto): Promise<TMWorkspace> {
return this.workspaceService.update(id, body);
}
@Delete('workspaces/:id')
removeWorkspace(@Param('id') id: string): Promise<void> {
return this.workspaceService.remove(id);
}
}
@@ -10,8 +10,9 @@ import { TMRemark } from './entities/remark.entity';
import { TMAttachment } from './entities/attachment.entity'; import { TMAttachment } from './entities/attachment.entity';
import { TMCheckListItem } from './entities/check-list-item.entity'; import { TMCheckListItem } from './entities/check-list-item.entity';
import { WorkspaceRepository } from './repositories/workspace.repository'; import { WorkspaceRepository } from './repositories/workspace.repository';
import { TaskManagerController } from './task-manager.controller'; import { WorkspaceController } from './controllers/workspace.controller';
import { WorkspaceService } from './providers/workspace.service'; import { WorkspaceService } from './providers/workspace.service';
import { User } from '../users/entities/user.entity';
// import { WorkspaceTypeService } from './providers/workspace-type.service'; // import { WorkspaceTypeService } from './providers/workspace-type.service';
// import { WorkspaceService } from './providers/workspace.service'; // import { WorkspaceService } from './providers/workspace.service';
@@ -32,9 +33,10 @@ import { WorkspaceService } from './providers/workspace.service';
TMRemark, TMRemark,
TMAttachment, TMAttachment,
TMCheckListItem, TMCheckListItem,
User
]), ]),
], ],
controllers: [TaskManagerController], controllers: [WorkspaceController],
providers: [ providers: [
WorkspaceRepository, WorkspaceRepository,
WorkspaceService, WorkspaceService,