Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
65c2cf8
feat(backend): add management functionality
NarwhalChen Mar 28, 2025
04da78b
feat: add initial project structure with assets and configuration files
NarwhalChen Mar 28, 2025
50b7f2b
feat: add dashboard configuration to tmuxinator and pnpm workspace
NarwhalChen Mar 29, 2025
b3fa801
feat: update authentication guard and ESLint configuration, upgrade R…
NarwhalChen Mar 29, 2025
b99bed7
feat: downgrade React and ReactDOM to version 17, update tsconfig pat…
Sma1lboy Mar 29, 2025
90b2d5b
feat: update type definitions for CSS properties in theme and package…
Sma1lboy Mar 29, 2025
99a9a9e
feat: add Apollo Client setup and GraphQL code generation configuration
NarwhalChen Mar 29, 2025
8c95cbe
refactor: remove unnecessary JoinTable decorator from Role model
NarwhalChen Mar 30, 2025
b80b148
feat: enhance dashboard module with authentication and role management
NarwhalChen Mar 30, 2025
3610215
feat: add roleIds field to CreateUserInput for user role assignment
NarwhalChen Mar 30, 2025
d3a701d
feat: implement UserInitService for initializing admin role and user
NarwhalChen Mar 30, 2025
f7d6657
chore: update ESLint configuration and add new dependencies for impro…
NarwhalChen Mar 30, 2025
f6249b2
feat: implement authentication context and protected route for user s…
NarwhalChen Mar 30, 2025
13493e3
feat: implement admin login functionality with error handling and pro…
NarwhalChen Mar 30, 2025
64572f5
feat: add user management functionality with CreateUserInput, UpdateU…
NarwhalChen Mar 30, 2025
858c70c
feat: remove redundant overview route and sidebar menu item for clean…
NarwhalChen Mar 30, 2025
6b19a10
feat: add menu and role management functionality with create and upda…
NarwhalChen Apr 2, 2025
d1453a2
feat: enhance role and menu management with new properties, guards, a…
NarwhalChen Apr 6, 2025
1965589
feat: update user model to enhance role association and remove deprec…
NarwhalChen Apr 6, 2025
91dffa3
feat: add role and menu management functionality with queries, mutati…
NarwhalChen Apr 6, 2025
965adf7
Merge branch 'main' into feat-backend-dashboard-api
NarwhalChen Apr 6, 2025
2e326ba
feat: add wildcard permission for menu access and initialize catch-al…
NarwhalChen Apr 6, 2025
e3dd8d2
feat: add management components for users, chats, and projects with c…
NarwhalChen Apr 6, 2025
40c9083
feat: implement user initialization service and add chat/project inpu…
NarwhalChen Apr 6, 2025
9eb89d1
feat: add login functionality and remove unused role and menu GraphQL…
NarwhalChen Apr 6, 2025
89f314a
feat: add isActive field to user, menu, and role inputs; implement to…
NarwhalChen Apr 6, 2025
4ef848e
feat: add roleIds field to user input types; implement user, role, an…
NarwhalChen Apr 6, 2025
8ff52ca
fix: update role authorization to use 'Admin' instead of 'admin' for …
NarwhalChen Apr 6, 2025
b7a5a96
refactor: update import paths for consistency across management compo…
NarwhalChen Apr 6, 2025
1be89a6
feat: implement chat and project creation components; update GraphQL …
NarwhalChen Apr 7, 2025
edae0c9
feat: enhance chat creation by associating user and project; update G…
NarwhalChen Apr 7, 2025
4f312eb
feat: add DashboardStats model and query; implement dashboard statist…
NarwhalChen Apr 7, 2025
41feeb2
feat: add avatarUrl to User interface; update HeaderUserbox to displa…
NarwhalChen Apr 7, 2025
3c423d7
feat: refactor login component and update authentication flow; rename…
NarwhalChen Apr 7, 2025
e42fbfe
feat: enforce admin role requirement for dashboard queries and mutations
NarwhalChen Apr 7, 2025
e1a653b
feat: implement logging interceptor for telemetry data collection; ad…
NarwhalChen Apr 7, 2025
841b4bc
feat: add telemetry log management; implement filtering and counting …
NarwhalChen Apr 7, 2025
45814f5
feat: add API logs section to management; implement TelemetryLogDetai…
NarwhalChen Apr 7, 2025
967718e
feat: update telemetry log to use email instead of userId; modify rel…
NarwhalChen Apr 7, 2025
298bbf9
[autofix.ci] apply automated fixes
autofix-ci[bot] Apr 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .tmuxinator/dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,9 @@ windows:
- docker:
- echo "Docker Services (Ctrl+a 4 to focus)"
- docker compose up
- dashboard:
root: <%= ENV["PWD"] %>/dashboard
panes:
- dashboard:
- echo "Dashboard (Ctrl+a 5 to focus, Ctrl+a r to restart)"
- pnpm run start
4 changes: 4 additions & 0 deletions backend/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import { MailModule } from './mail/mail.module';
import { GitHubModule } from './github/github.module';
import { AppConfigService } from './config/config.service';
import { getDatabaseConfig } from './database.config';
import { DashboardModule } from './dashboard/dashboard.module';
import { InterceptorModule } from './interceptor/interceptor.module';

@Module({
imports: [
Expand Down Expand Up @@ -56,6 +58,8 @@ import { getDatabaseConfig } from './database.config';
MailModule,
TypeOrmModule.forFeature([User]),
GitHubModule,
DashboardModule,
InterceptorModule,
],
providers: [
AppResolver,
Expand Down
16 changes: 14 additions & 2 deletions backend/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import { MailModule } from 'src/mail/mail.module';
import { GoogleStrategy } from './oauth/GoogleStrategy';
import { GoogleController } from './google.controller';
import { AppConfigModule } from 'src/config/config.module';
import { RoleResolver } from './role/role.resolver';
import { MenuResolver } from './menu/menu.resolver';
import { RoleService } from './role/role.service';
import { MenuService } from './menu/menu.service';

@Module({
imports: [
Expand All @@ -29,8 +33,16 @@ import { AppConfigModule } from 'src/config/config.module';
JwtCacheModule,
MailModule,
],
providers: [
AuthService,
AuthResolver,
RoleResolver,
MenuResolver,
RoleService,
MenuService,
GoogleStrategy,
],
exports: [AuthService, RoleService, MenuService, JwtModule],
controllers: [GoogleController],
providers: [AuthService, AuthResolver, GoogleStrategy],
exports: [AuthService, JwtModule],
})
export class AuthModule {}
25 changes: 25 additions & 0 deletions backend/src/auth/menu/dto/create-menu.input.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Field, InputType } from '@nestjs/graphql';
import { IsString, IsNotEmpty, IsOptional, IsArray } from 'class-validator';

@InputType()
export class CreateMenuInput {
@Field()
@IsString()
@IsNotEmpty()
name: string;

@Field()
@IsString()
@IsNotEmpty()
path: string;

@Field()
@IsString()
@IsNotEmpty()
permission: string;

@Field(() => [String], { nullable: true })
@IsArray()
@IsOptional()
roleIds?: string[];
}
32 changes: 32 additions & 0 deletions backend/src/auth/menu/dto/update-menu.input.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Field, ID, InputType } from '@nestjs/graphql';
import { IsString, IsOptional, IsArray } from 'class-validator';

@InputType()
export class UpdateMenuInput {
@Field(() => ID)
id: string;

@Field({ nullable: true })
@IsString()
@IsOptional()
name?: string;

@Field({ nullable: true })
@IsString()
@IsOptional()
path?: string;

@Field({ nullable: true })
@IsString()
@IsOptional()
permission?: string;

@Field({ nullable: true })
@IsOptional()
isActive?: boolean;

@Field(() => [String], { nullable: true })
@IsArray()
@IsOptional()
roleIds?: string[];
}
35 changes: 31 additions & 4 deletions backend/src/auth/menu/menu.model.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import { ObjectType, Field, ID } from '@nestjs/graphql';
import { SystemBaseModel } from 'src/system-base-model/system-base.model';
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany } from 'typeorm';
import {
Entity,
PrimaryGeneratedColumn,
Column,
ManyToMany,
CreateDateColumn,
UpdateDateColumn,
} from 'typeorm';
import { Role } from '../role/role.model';

@Entity()
@ObjectType()
export class Menu extends SystemBaseModel {
export class Menu {
@Field(() => ID)
@PrimaryGeneratedColumn()
@PrimaryGeneratedColumn('uuid')
id: string;

@Field()
Expand All @@ -22,6 +28,27 @@ export class Menu extends SystemBaseModel {
@Column()
permission: string;

@Field(() => String, { nullable: true })
@Column({ nullable: true })
description?: string;

@Field()
@Column({ default: true })
isActive: boolean;

@Field()
@Column({ default: false })
isDeleted: boolean;

@Field()
@CreateDateColumn()
createdAt: Date;

@Field()
@UpdateDateColumn()
updatedAt: Date;

@Field(() => [Role], { nullable: true })
@ManyToMany(() => Role, (role) => role.menus)
roles: Role[];
}
65 changes: 65 additions & 0 deletions backend/src/auth/menu/menu.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Resolver, Query, Mutation, Args, ID } from '@nestjs/graphql';
import { UseGuards } from '@nestjs/common';
import { MenuService } from './menu.service';
import { Menu } from './menu.model';
import { CreateMenuInput } from './dto/create-menu.input';
import { UpdateMenuInput } from './dto/update-menu.input';
import { RequireAuth } from '../../decorator/auth.decorator';
import { JWTAuthGuard } from 'src/guard/jwt-auth.guard';

@UseGuards(JWTAuthGuard)
@Resolver(() => Menu)
export class MenuResolver {
constructor(private readonly menuService: MenuService) {}

@Query(() => [Menu])
@RequireAuth({
roles: ['Admin'],
menuPath: '/menu/list',
})
async menus(): Promise<Menu[]> {
return this.menuService.findAll();
}

@Query(() => Menu)
@RequireAuth({
roles: ['Admin'],
menuPath: '/menu/detail',
})
async menu(@Args('id', { type: () => ID }) id: string): Promise<Menu> {
return this.menuService.findOne(id);
}

@Mutation(() => Menu)
@RequireAuth({
roles: ['Admin'],
menuPath: '/menu/create',
})
async createMenu(
@Args('createMenuInput') createMenuInput: CreateMenuInput,
): Promise<Menu> {
return this.menuService.create(createMenuInput);
}

@Mutation(() => Menu)
@RequireAuth({
roles: ['Admin'],
menuPath: '/menu/update',
})
async updateMenu(
@Args('updateMenuInput') updateMenuInput: UpdateMenuInput,
): Promise<Menu> {
return this.menuService.update(updateMenuInput.id, updateMenuInput);
}

@Mutation(() => Boolean)
@RequireAuth({
roles: ['Admin'],
menuPath: '/menu/delete',
})
async removeMenu(
@Args('id', { type: () => ID }) id: string,
): Promise<boolean> {
return this.menuService.remove(id);
}
}
69 changes: 69 additions & 0 deletions backend/src/auth/menu/menu.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Menu } from './menu.model';
import { CreateMenuInput } from './dto/create-menu.input';
import { UpdateMenuInput } from './dto/update-menu.input';

@Injectable()
export class MenuService {
constructor(
@InjectRepository(Menu)
private readonly menuRepository: Repository<Menu>,
) {}

async create(createMenuInput: CreateMenuInput): Promise<Menu> {
const menu = this.menuRepository.create(createMenuInput);
return this.menuRepository.save(menu);
}

async findAll(): Promise<Menu[]> {
return this.menuRepository.find({
relations: ['roles'],
});
}

async findOne(id: string): Promise<Menu> {
const menu = await this.menuRepository.findOne({
where: { id },
relations: ['roles'],
});

if (!menu) {
throw new NotFoundException(`Menu with ID "${id}" not found`);
}

return menu;
}

async update(id: string, updateMenuInput: UpdateMenuInput): Promise<Menu> {
const menu = await this.findOne(id);
Object.assign(menu, updateMenuInput);
return this.menuRepository.save(menu);
}

async remove(id: string): Promise<boolean> {
const result = await this.menuRepository.delete(id);
return result.affected > 0;
}

async findByPermission(permission: string): Promise<Menu[]> {
return this.menuRepository.find({
where: { permission },
relations: ['roles'],
});
}

async findByPath(path: string): Promise<Menu> {
const menu = await this.menuRepository.findOne({
where: { path },
relations: ['roles'],
});

if (!menu) {
throw new NotFoundException(`Menu with path "${path}" not found`);
}

return menu;
}
}
19 changes: 19 additions & 0 deletions backend/src/auth/role/dto/create-role.input.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Field, InputType } from '@nestjs/graphql';
import { IsString, IsArray, IsOptional } from 'class-validator';

@InputType()
export class CreateRoleInput {
@Field()
@IsString()
name: string;

@Field({ nullable: true })
@IsString()
@IsOptional()
description?: string;

@Field(() => [String], { nullable: true })
@IsArray()
@IsOptional()
menuIds?: string[];
}
27 changes: 27 additions & 0 deletions backend/src/auth/role/dto/update-role.input.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Field, ID, InputType } from '@nestjs/graphql';
import { IsString, IsArray, IsOptional } from 'class-validator';

@InputType()
export class UpdateRoleInput {
@Field(() => ID)
id: string;

@Field({ nullable: true })
@IsString()
@IsOptional()
name?: string;

@Field({ nullable: true })
@IsString()
@IsOptional()
description?: string;

@Field({ nullable: true })
@IsOptional()
isActive?: boolean;

@Field(() => [String], { nullable: true })
@IsArray()
@IsOptional()
menuIds?: string[];
}
Loading
Loading