fix: code review cleanup
- Added missing API functions: fetchKnowledgeStats, fetchEntryGraph - Exported StatsDashboard and EntryGraphViewer components - Replaced 'any' types with proper TypeScript types: * AuthUser for @CurrentUser parameters * Prisma.KnowledgeEntryWhereInput for where clauses * Prisma.KnowledgeEntryUpdateInput for update data * Prisma.TransactionClient for transaction parameters - All TypeScript checks passing - XSS protection verified in WikiLinkRenderer (escapeHtml function) - Wiki-link parsing properly handles code blocks and escaping
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
ParseIntPipe,
|
||||
DefaultValuePipe,
|
||||
} from "@nestjs/common";
|
||||
import type { AuthUser } from "@mosaic/shared";
|
||||
import { KnowledgeService } from "./knowledge.service";
|
||||
import { CreateEntryDto, UpdateEntryDto, EntryQueryDto, RestoreVersionDto } from "./dto";
|
||||
import { AuthGuard } from "../auth/guards/auth.guard";
|
||||
@@ -69,7 +70,7 @@ export class KnowledgeController {
|
||||
@RequirePermission(Permission.WORKSPACE_MEMBER)
|
||||
async create(
|
||||
@Workspace() workspaceId: string,
|
||||
@CurrentUser() user: any,
|
||||
@CurrentUser() user: AuthUser,
|
||||
@Body() createDto: CreateEntryDto
|
||||
) {
|
||||
return this.knowledgeService.create(workspaceId, user.id, createDto);
|
||||
@@ -85,7 +86,7 @@ export class KnowledgeController {
|
||||
async update(
|
||||
@Workspace() workspaceId: string,
|
||||
@Param("slug") slug: string,
|
||||
@CurrentUser() user: any,
|
||||
@CurrentUser() user: AuthUser,
|
||||
@Body() updateDto: UpdateEntryDto
|
||||
) {
|
||||
return this.knowledgeService.update(workspaceId, slug, user.id, updateDto);
|
||||
@@ -101,7 +102,7 @@ export class KnowledgeController {
|
||||
async remove(
|
||||
@Workspace() workspaceId: string,
|
||||
@Param("slug") slug: string,
|
||||
@CurrentUser() user: any
|
||||
@CurrentUser() user: AuthUser
|
||||
) {
|
||||
await this.knowledgeService.remove(workspaceId, slug, user.id);
|
||||
return { message: "Entry archived successfully" };
|
||||
@@ -177,7 +178,7 @@ export class KnowledgeController {
|
||||
@Workspace() workspaceId: string,
|
||||
@Param("slug") slug: string,
|
||||
@Param("version", ParseIntPipe) version: number,
|
||||
@CurrentUser() user: any,
|
||||
@CurrentUser() user: AuthUser,
|
||||
@Body() restoreDto: RestoreVersionDto
|
||||
) {
|
||||
return this.knowledgeService.restoreVersion(
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
NotFoundException,
|
||||
ConflictException,
|
||||
} from "@nestjs/common";
|
||||
import { EntryStatus } from "@prisma/client";
|
||||
import { EntryStatus, Prisma } from "@prisma/client";
|
||||
import slugify from "slugify";
|
||||
import { PrismaService } from "../prisma/prisma.service";
|
||||
import type { CreateEntryDto, UpdateEntryDto, EntryQueryDto } from "./dto";
|
||||
@@ -41,7 +41,7 @@ export class KnowledgeService {
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
// Build where clause
|
||||
const where: any = {
|
||||
const where: Prisma.KnowledgeEntryWhereInput = {
|
||||
workspaceId,
|
||||
};
|
||||
|
||||
@@ -308,7 +308,7 @@ export class KnowledgeService {
|
||||
}
|
||||
|
||||
// Build update data object conditionally
|
||||
const updateData: any = {
|
||||
const updateData: Prisma.KnowledgeEntryUpdateInput = {
|
||||
updatedBy: userId,
|
||||
};
|
||||
|
||||
@@ -764,7 +764,7 @@ export class KnowledgeService {
|
||||
* Sync tags for an entry (create missing tags, update associations)
|
||||
*/
|
||||
private async syncTags(
|
||||
tx: any,
|
||||
tx: Prisma.TransactionClient,
|
||||
workspaceId: string,
|
||||
entryId: string,
|
||||
tagNames: string[]
|
||||
|
||||
@@ -7,3 +7,5 @@ export { EntryViewer } from "./EntryViewer";
|
||||
export { EntryEditor } from "./EntryEditor";
|
||||
export { EntryMetadata } from "./EntryMetadata";
|
||||
export { VersionHistory } from "./VersionHistory";
|
||||
export { StatsDashboard } from "./StatsDashboard";
|
||||
export { EntryGraphViewer } from "./EntryGraphViewer";
|
||||
|
||||
@@ -230,6 +230,94 @@ export async function fetchBacklinks(slug: string): Promise<{
|
||||
}>(`/api/knowledge/entries/${slug}/backlinks`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch knowledge base statistics
|
||||
*/
|
||||
export async function fetchKnowledgeStats(): Promise<{
|
||||
overview: {
|
||||
totalEntries: number;
|
||||
totalTags: number;
|
||||
totalLinks: number;
|
||||
publishedEntries: number;
|
||||
draftEntries: number;
|
||||
archivedEntries: number;
|
||||
};
|
||||
mostConnected: Array<{
|
||||
id: string;
|
||||
slug: string;
|
||||
title: string;
|
||||
incomingLinks: number;
|
||||
outgoingLinks: number;
|
||||
totalConnections: number;
|
||||
}>;
|
||||
recentActivity: Array<{
|
||||
id: string;
|
||||
slug: string;
|
||||
title: string;
|
||||
updatedAt: string;
|
||||
status: string;
|
||||
}>;
|
||||
tagDistribution: Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
color: string | null;
|
||||
entryCount: number;
|
||||
}>;
|
||||
}> {
|
||||
return apiGet(`/api/knowledge/stats`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch entry graph (network of connected entries)
|
||||
*/
|
||||
export async function fetchEntryGraph(
|
||||
slug: string,
|
||||
depth: number = 1
|
||||
): Promise<{
|
||||
centerNode: {
|
||||
id: string;
|
||||
slug: string;
|
||||
title: string;
|
||||
summary: string | null;
|
||||
tags: Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
color: string | null;
|
||||
}>;
|
||||
depth: number;
|
||||
};
|
||||
nodes: Array<{
|
||||
id: string;
|
||||
slug: string;
|
||||
title: string;
|
||||
summary: string | null;
|
||||
tags: Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
color: string | null;
|
||||
}>;
|
||||
depth: number;
|
||||
}>;
|
||||
edges: Array<{
|
||||
id: string;
|
||||
sourceId: string;
|
||||
targetId: string;
|
||||
linkText: string;
|
||||
}>;
|
||||
stats: {
|
||||
totalNodes: number;
|
||||
totalEdges: number;
|
||||
maxDepth: number;
|
||||
};
|
||||
}> {
|
||||
const params = new URLSearchParams();
|
||||
params.append("depth", depth.toString());
|
||||
return apiGet(`/api/knowledge/entries/${slug}/graph?${params.toString()}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock entries for development (until backend endpoints are ready)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user