fix: logs page shows activity_logs, interceptor accepts missing workspaceId, autoRefresh on
Some checks failed
ci/woodpecker/push/ci Pipeline failed

This commit is contained in:
2026-03-01 16:07:02 -06:00
parent 78ff8f8e70
commit 22cb68c5b0
7 changed files with 357 additions and 436 deletions

View File

@@ -396,7 +396,7 @@ model Task {
subtasks Task[] @relation("TaskSubtasks")
domain Domain? @relation(fields: [domainId], references: [id], onDelete: SetNull)
@@unique([id, workspaceId])
@@unique([id])
@@index([workspaceId])
@@index([workspaceId, status])
@@index([workspaceId, dueDate])
@@ -430,7 +430,7 @@ model Event {
project Project? @relation(fields: [projectId], references: [id], onDelete: SetNull)
domain Domain? @relation(fields: [domainId], references: [id], onDelete: SetNull)
@@unique([id, workspaceId])
@@unique([id])
@@index([workspaceId])
@@index([workspaceId, startTime])
@@index([creatorId])
@@ -462,7 +462,7 @@ model Project {
domain Domain? @relation(fields: [domainId], references: [id], onDelete: SetNull)
ideas Idea[]
@@unique([id, workspaceId])
@@unique([id])
@@index([workspaceId])
@@index([workspaceId, status])
@@index([creatorId])
@@ -472,7 +472,7 @@ model Project {
model ActivityLog {
id String @id @default(uuid()) @db.Uuid
workspaceId String @map("workspace_id") @db.Uuid
workspaceId String? @map("workspace_id") @db.Uuid
userId String @map("user_id") @db.Uuid
action ActivityAction
entityType EntityType @map("entity_type")
@@ -483,10 +483,10 @@ model ActivityLog {
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz
// Relations
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
workspace Workspace? @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([id, workspaceId])
@@unique([id])
@@index([workspaceId])
@@index([workspaceId, createdAt])
@@index([entityType, entityId])
@@ -541,7 +541,7 @@ model Domain {
projects Project[]
ideas Idea[]
@@unique([id, workspaceId])
@@unique([id])
@@unique([workspaceId, slug])
@@index([workspaceId])
@@map("domains")
@@ -581,7 +581,7 @@ model Idea {
project Project? @relation(fields: [projectId], references: [id], onDelete: SetNull)
creator User @relation("IdeaCreator", fields: [creatorId], references: [id], onDelete: Cascade)
@@unique([id, workspaceId])
@@unique([id])
@@index([workspaceId])
@@index([workspaceId, status])
@@index([domainId])
@@ -695,7 +695,7 @@ model AgentTask {
runnerJobs RunnerJob[]
findings Finding[]
@@unique([id, workspaceId])
@@unique([id])
@@index([workspaceId])
@@index([workspaceId, status])
@@index([createdById])
@@ -722,7 +722,7 @@ model Finding {
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
task AgentTask? @relation(fields: [taskId], references: [id], onDelete: SetNull)
@@unique([id, workspaceId])
@@unique([id])
@@index([workspaceId])
@@index([agentId])
@@index([type])
@@ -830,7 +830,7 @@ model UserLayout {
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([id, workspaceId])
@@unique([id])
@@unique([workspaceId, userId, name])
@@index([userId])
@@map("user_layouts")
@@ -1149,7 +1149,7 @@ model Personality {
llmProviderInstance LlmProviderInstance? @relation("PersonalityLlmProvider", fields: [llmProviderInstanceId], references: [id], onDelete: SetNull)
workspaceLlmSettings WorkspaceLlmSettings[] @relation("WorkspacePersonality")
@@unique([id, workspaceId])
@@unique([id])
@@unique([workspaceId, name])
@@index([workspaceId])
@@index([workspaceId, isDefault])
@@ -1322,7 +1322,7 @@ model RunnerJob {
steps JobStep[]
events JobEvent[]
@@unique([id, workspaceId])
@@unique([id])
@@index([workspaceId])
@@index([workspaceId, status])
@@index([agentTaskId])

View File

@@ -117,12 +117,13 @@ export class ActivityService {
/**
* Get a single activity log by ID
*/
async findOne(id: string, workspaceId: string): Promise<ActivityLogResult | null> {
async findOne(id: string, workspaceId?: string): Promise<ActivityLogResult | null> {
const where: Prisma.ActivityLogWhereUniqueInput = { id };
if (workspaceId) {
where.workspaceId = workspaceId;
}
return await this.prisma.activityLog.findUnique({
where: {
id,
workspaceId,
},
where,
include: {
user: {
select: {

View File

@@ -4,6 +4,7 @@ import { tap } from "rxjs/operators";
import { ActivityService } from "../activity.service";
import { ActivityAction, EntityType } from "@prisma/client";
import type { Prisma } from "@prisma/client";
import type { CreateActivityLogInput } from "../interfaces/activity.interface";
import type { AuthenticatedRequest } from "../../common/types/user.types";
/**
@@ -61,10 +62,13 @@ export class ActivityLoggingInterceptor implements NestInterceptor {
// Extract entity information
const resultObj = result as Record<string, unknown> | undefined;
const entityId = params.id ?? (resultObj?.id as string | undefined);
// workspaceId is now optional - log events even when missing
const workspaceId = user.workspaceId ?? (body.workspaceId as string | undefined);
if (!entityId || !workspaceId) {
this.logger.warn("Cannot log activity: missing entityId or workspaceId");
// Log with warning if entityId is missing, but still proceed with logging if workspaceId exists
if (!entityId) {
this.logger.warn("Cannot log activity: missing entityId");
return;
}
@@ -92,9 +96,8 @@ export class ActivityLoggingInterceptor implements NestInterceptor {
const userAgent =
typeof userAgentHeader === "string" ? userAgentHeader : userAgentHeader?.[0];
// Log the activity
await this.activityService.logActivity({
workspaceId,
// Log the activity — workspaceId is optional
const activityInput: CreateActivityLogInput = {
userId: user.id,
action,
entityType,
@@ -102,7 +105,11 @@ export class ActivityLoggingInterceptor implements NestInterceptor {
details,
ipAddress: ip ?? undefined,
userAgent: userAgent ?? undefined,
});
};
if (workspaceId) {
activityInput.workspaceId = workspaceId;
}
await this.activityService.logActivity(activityInput);
} catch (error) {
// Don't fail the request if activity logging fails
this.logger.error(

View File

@@ -2,9 +2,10 @@ import type { ActivityAction, EntityType, Prisma } from "@prisma/client";
/**
* Interface for creating a new activity log entry
* workspaceId is optional - allows logging events without workspace context
*/
export interface CreateActivityLogInput {
workspaceId: string;
workspaceId?: string | null;
userId: string;
action: ActivityAction;
entityType: EntityType;