Add saved report views with personal/org filters and in-org share links.

This commit is contained in:
2026-09-27 11:11:33 +03:30
parent 6a9e864b07
commit a16c2f0a9b
7 changed files with 550 additions and 34 deletions
+106 -2
View File
@@ -1,14 +1,63 @@
import { Controller, Get, Query, UseGuards } from '@nestjs/common';
import {
Body,
Controller,
Delete,
Get,
Param,
Patch,
Post,
Query,
UseGuards,
} from '@nestjs/common';
import {
IsBoolean,
IsObject,
IsOptional,
IsString,
MaxLength,
} from 'class-validator';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { CurrentUser } from '../auth/current-user.decorator';
import type { Actor } from '../common/record-scope';
import { SavedViewsService } from '../saved-views/saved-views.service';
import { ReportsDrilldownQueryDto, ReportsQueryDto } from './dto';
import { ReportsService } from './reports.service';
class CreateReportViewDto {
@IsString()
@MaxLength(120)
name!: string;
@IsObject()
filters!: Record<string, unknown>;
@IsOptional()
@IsBoolean()
isShared?: boolean;
}
class UpdateReportViewDto {
@IsOptional()
@IsString()
@MaxLength(120)
name?: string;
@IsOptional()
@IsObject()
filters?: Record<string, unknown>;
@IsOptional()
@IsBoolean()
isShared?: boolean;
}
@Controller('reports')
@UseGuards(JwtAuthGuard)
export class ReportsController {
constructor(private readonly reportsService: ReportsService) {}
constructor(
private readonly reportsService: ReportsService,
private readonly savedViews: SavedViewsService,
) {}
@Get('dashboard')
dashboard(@CurrentUser() user: Actor, @Query() query: ReportsQueryDto) {
@@ -35,4 +84,59 @@ export class ReportsController {
home(@CurrentUser() user: Actor) {
return this.reportsService.home(user);
}
@Get('views')
listViews(@CurrentUser() user: Actor) {
return this.savedViews.list(user.organizationId, user.userId, 'reports');
}
@Get('views/:id')
getView(@CurrentUser() user: Actor, @Param('id') id: string) {
return this.savedViews.get(user.organizationId, user.userId, id, 'reports');
}
@Post('views')
createView(@CurrentUser() user: Actor, @Body() dto: CreateReportViewDto) {
return this.savedViews.create(user.organizationId, user.userId, {
name: dto.name,
scope: 'reports',
filters: dto.filters,
isShared: dto.isShared,
});
}
@Patch('views/:id')
updateView(
@CurrentUser() user: Actor,
@Param('id') id: string,
@Body() dto: UpdateReportViewDto,
) {
const isAdmin = user.role === 'owner' || user.role === 'admin';
return this.savedViews.update(
user.organizationId,
user.userId,
id,
{
name: dto.name,
filters: dto.filters,
isShared: dto.isShared,
scope: 'reports',
},
isAdmin,
'reports',
);
}
@Delete('views/:id')
async removeView(@CurrentUser() user: Actor, @Param('id') id: string) {
const isAdmin = user.role === 'owner' || user.role === 'admin';
await this.savedViews.remove(
user.organizationId,
user.userId,
id,
isAdmin,
'reports',
);
return { ok: true };
}
}
+2 -1
View File
@@ -1,10 +1,11 @@
import { Module } from '@nestjs/common';
import { AuthModule } from '../auth/auth.module';
import { SavedViewsModule } from '../saved-views/saved-views.module';
import { ReportsController } from './reports.controller';
import { ReportsService } from './reports.service';
@Module({
imports: [AuthModule],
imports: [AuthModule, SavedViewsModule],
controllers: [ReportsController],
providers: [ReportsService],
})