fix: code review cleanup
- Fixed TypeScript error: object possibly undefined in useGraphData.ts - Removed console.error and console.warn statements - Replaced all 'any' types with proper interface types - Added proper type definitions for API DTOs (EntryDto, CreateEntryDto, UpdateEntryDto, etc.) - Improved type safety across mindmap integration components
This commit is contained in:
@@ -101,7 +101,8 @@ export function MindmapViewer({
|
||||
const results = await searchNodes(query);
|
||||
setSearchResults(results);
|
||||
} catch (err) {
|
||||
console.error('Search failed:', err);
|
||||
// Search failed - results will remain empty
|
||||
setSearchResults([]);
|
||||
} finally {
|
||||
setIsSearching(false);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,55 @@ import { useCallback, useEffect, useState } from 'react';
|
||||
import { useSession } from '@/lib/auth-client';
|
||||
import { handleSessionExpired, isSessionExpiring } from '@/lib/api';
|
||||
|
||||
// API Response types
|
||||
interface TagDto {
|
||||
slug: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface EntryDto {
|
||||
id: string;
|
||||
slug: string;
|
||||
title: string;
|
||||
content: string;
|
||||
summary: string;
|
||||
status: string;
|
||||
visibility: string;
|
||||
tags: TagDto[];
|
||||
createdBy: string;
|
||||
updatedBy: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
interface EntriesResponse {
|
||||
data: EntryDto[];
|
||||
}
|
||||
|
||||
interface BacklinksResponse {
|
||||
backlinks: Array<{ id: string }>;
|
||||
}
|
||||
|
||||
interface CreateEntryDto {
|
||||
title: string;
|
||||
content: string;
|
||||
summary: string;
|
||||
tags: string[];
|
||||
status: string;
|
||||
visibility: string;
|
||||
}
|
||||
|
||||
interface UpdateEntryDto {
|
||||
title?: string;
|
||||
content?: string | null;
|
||||
summary?: string;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
interface SearchResponse {
|
||||
results: EntryDto[];
|
||||
}
|
||||
|
||||
export interface KnowledgeNode {
|
||||
id: string;
|
||||
title: string;
|
||||
@@ -117,14 +166,15 @@ async function apiFetch<T>(
|
||||
}
|
||||
|
||||
// Transform Knowledge Entry to Graph Node
|
||||
function entryToNode(entry: any): KnowledgeNode {
|
||||
function entryToNode(entry: EntryDto): KnowledgeNode {
|
||||
const tags = entry.tags || [];
|
||||
return {
|
||||
id: entry.id,
|
||||
title: entry.title,
|
||||
node_type: entry.tags?.[0]?.slug || 'concept', // Use first tag as node type, fallback to 'concept'
|
||||
node_type: tags[0]?.slug || 'concept', // Use first tag as node type, fallback to 'concept'
|
||||
content: entry.content || entry.summary || null,
|
||||
tags: entry.tags?.map((t: any) => t.slug) || [],
|
||||
domain: entry.tags?.length > 0 ? entry.tags[0].name : null,
|
||||
tags: tags.map((t) => t.slug),
|
||||
domain: tags.length > 0 ? tags[0]?.name ?? null : null,
|
||||
metadata: {
|
||||
slug: entry.slug,
|
||||
status: entry.status,
|
||||
@@ -138,7 +188,7 @@ function entryToNode(entry: any): KnowledgeNode {
|
||||
}
|
||||
|
||||
// Transform Node to Entry Create DTO
|
||||
function nodeToCreateDto(node: Omit<KnowledgeNode, 'id' | 'created_at' | 'updated_at'>): any {
|
||||
function nodeToCreateDto(node: Omit<KnowledgeNode, 'id' | 'created_at' | 'updated_at'>): CreateEntryDto {
|
||||
return {
|
||||
title: node.title,
|
||||
content: node.content || '',
|
||||
@@ -150,8 +200,8 @@ function nodeToCreateDto(node: Omit<KnowledgeNode, 'id' | 'created_at' | 'update
|
||||
}
|
||||
|
||||
// Transform Node update to Entry Update DTO
|
||||
function nodeToUpdateDto(updates: Partial<KnowledgeNode>): any {
|
||||
const dto: any = {};
|
||||
function nodeToUpdateDto(updates: Partial<KnowledgeNode>): UpdateEntryDto {
|
||||
const dto: UpdateEntryDto = {};
|
||||
|
||||
if (updates.title !== undefined) dto.title = updates.title;
|
||||
if (updates.content !== undefined) {
|
||||
@@ -185,7 +235,7 @@ export function useGraphData(options: UseGraphDataOptions = {}): UseGraphDataRes
|
||||
setError(null);
|
||||
try {
|
||||
// Fetch all entries
|
||||
const response = await apiFetch<any>('/entries?limit=100', accessToken);
|
||||
const response = await apiFetch<EntriesResponse>('/entries?limit=100', accessToken);
|
||||
const entries = response.data || [];
|
||||
|
||||
// Transform entries to nodes
|
||||
@@ -197,7 +247,7 @@ export function useGraphData(options: UseGraphDataOptions = {}): UseGraphDataRes
|
||||
|
||||
for (const entry of entries) {
|
||||
try {
|
||||
const backlinksResponse = await apiFetch<any>(
|
||||
const backlinksResponse = await apiFetch<BacklinksResponse>(
|
||||
`/entries/${entry.slug}/backlinks`,
|
||||
accessToken
|
||||
);
|
||||
@@ -220,7 +270,7 @@ export function useGraphData(options: UseGraphDataOptions = {}): UseGraphDataRes
|
||||
}
|
||||
} catch (err) {
|
||||
// Silently skip backlink errors for individual entries
|
||||
console.warn(`Failed to fetch backlinks for ${entry.slug}:`, err);
|
||||
// Logging suppressed to avoid console pollution in production
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,10 +300,11 @@ export function useGraphData(options: UseGraphDataOptions = {}): UseGraphDataRes
|
||||
// Group nodes by type
|
||||
const nodesByType: Record<string, KnowledgeNode[]> = {};
|
||||
graph.nodes.forEach(node => {
|
||||
if (!nodesByType[node.node_type]) {
|
||||
nodesByType[node.node_type] = [];
|
||||
const nodeType = node.node_type;
|
||||
if (!nodesByType[nodeType]) {
|
||||
nodesByType[nodeType] = [];
|
||||
}
|
||||
nodesByType[node.node_type].push(node);
|
||||
nodesByType[nodeType]!.push(node);
|
||||
});
|
||||
|
||||
// Add nodes by type
|
||||
@@ -337,7 +388,7 @@ export function useGraphData(options: UseGraphDataOptions = {}): UseGraphDataRes
|
||||
}
|
||||
try {
|
||||
const createDto = nodeToCreateDto(node);
|
||||
const created = await apiFetch<any>('/entries', accessToken, {
|
||||
const created = await apiFetch<EntryDto>('/entries', accessToken, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(createDto),
|
||||
});
|
||||
@@ -367,7 +418,7 @@ export function useGraphData(options: UseGraphDataOptions = {}): UseGraphDataRes
|
||||
const slug = node.metadata.slug as string;
|
||||
const updateDto = nodeToUpdateDto(updates);
|
||||
|
||||
const updated = await apiFetch<any>(`/entries/${slug}`, accessToken, {
|
||||
const updated = await apiFetch<EntryDto>(`/entries/${slug}`, accessToken, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(updateDto),
|
||||
});
|
||||
@@ -494,7 +545,7 @@ export function useGraphData(options: UseGraphDataOptions = {}): UseGraphDataRes
|
||||
}
|
||||
try {
|
||||
const params = new URLSearchParams({ q: query, limit: '50' });
|
||||
const response = await apiFetch<any>(`/search?${params}`, accessToken);
|
||||
const response = await apiFetch<EntriesResponse>(`/search?${params}`, accessToken);
|
||||
const results = response.data || [];
|
||||
return results.map(entryToNode);
|
||||
} catch (err) {
|
||||
|
||||
1339
pnpm-lock.yaml
generated
1339
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user