Fix document links and backlinks rendering issue
- Fixed CachedAPI endpoint routing: /documents/{id}/links was incorrectly routed to getDocument()
- Added proper pattern matching for document API calls using regex
- Fixed link and backlink API calls to use correct getDocumentLinks() and getDocumentBacklinks() methods
- Added comprehensive debugging logs for API response tracking
- Resolved issue where links were not rendering in document viewer
Changes:
- cached-api.js: Fixed endpoint routing with proper regex pattern matching
- link-manager.js: Enhanced debugging and API response handling
- viewer-core.js: Added closeAllModals() to prevent modal auto-opening
Result: Document links and backlinks now render correctly (8 links restored)
This commit is contained in:
@@ -27,13 +27,37 @@ class LinkManager {
|
|||||||
async loadDocumentLinks(documentId) {
|
async loadDocumentLinks(documentId) {
|
||||||
try {
|
try {
|
||||||
console.log('📡 링크 API 호출:', `/documents/${documentId}/links`);
|
console.log('📡 링크 API 호출:', `/documents/${documentId}/links`);
|
||||||
const response = await this.cachedApi.get(`/documents/${documentId}/links`, {}, { category: 'links' }).catch(() => []);
|
console.log('📡 사용 중인 documentId:', documentId);
|
||||||
this.documentLinks = Array.isArray(response) ? response : [];
|
console.log('📡 cachedApi 객체:', this.cachedApi);
|
||||||
console.log('📡 API 응답 링크 개수:', this.documentLinks.length);
|
const response = await this.cachedApi.get(`/documents/${documentId}/links`, {}, { category: 'links' });
|
||||||
console.log('📡 API 응답 타입:', typeof response, response);
|
console.log('📡 원본 API 응답:', response);
|
||||||
|
console.log('📡 응답 타입:', typeof response);
|
||||||
|
console.log('📡 응답이 배열인가?', Array.isArray(response));
|
||||||
|
console.log('📡 응답 JSON 문자열:', JSON.stringify(response, null, 2));
|
||||||
|
console.log('📡 응답 키들:', Object.keys(response || {}));
|
||||||
|
|
||||||
|
// API 응답이 객체일 경우 처리
|
||||||
|
if (Array.isArray(response)) {
|
||||||
|
this.documentLinks = response;
|
||||||
|
} else if (response && typeof response === 'object') {
|
||||||
|
// 객체에서 배열 추출 시도
|
||||||
|
if (response.data && Array.isArray(response.data)) {
|
||||||
|
this.documentLinks = response.data;
|
||||||
|
} else if (response.links && Array.isArray(response.links)) {
|
||||||
|
this.documentLinks = response.links;
|
||||||
|
} else {
|
||||||
|
console.warn('⚠️ 예상치 못한 API 응답 구조:', response);
|
||||||
|
this.documentLinks = [];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.documentLinks = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('📡 최종 링크 데이터:', this.documentLinks);
|
||||||
|
console.log('📡 최종 링크 개수:', this.documentLinks.length);
|
||||||
return this.documentLinks;
|
return this.documentLinks;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('문서 링크 로드 실패:', error);
|
console.error('❌ 문서 링크 로드 실패:', error);
|
||||||
this.documentLinks = [];
|
this.documentLinks = [];
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -45,13 +69,35 @@ class LinkManager {
|
|||||||
async loadBacklinks(documentId) {
|
async loadBacklinks(documentId) {
|
||||||
try {
|
try {
|
||||||
console.log('📡 백링크 API 호출:', `/documents/${documentId}/backlinks`);
|
console.log('📡 백링크 API 호출:', `/documents/${documentId}/backlinks`);
|
||||||
const response = await this.cachedApi.get(`/documents/${documentId}/backlinks`, {}, { category: 'links' }).catch(() => []);
|
const response = await this.cachedApi.get(`/documents/${documentId}/backlinks`, {}, { category: 'links' });
|
||||||
this.backlinks = Array.isArray(response) ? response : [];
|
console.log('📡 원본 백링크 응답:', response);
|
||||||
console.log('📡 API 응답 백링크 개수:', this.backlinks.length);
|
console.log('📡 백링크 응답 타입:', typeof response);
|
||||||
console.log('📡 API 응답 타입:', typeof response, response);
|
console.log('📡 백링크 응답이 배열인가?', Array.isArray(response));
|
||||||
|
console.log('📡 백링크 응답 JSON 문자열:', JSON.stringify(response, null, 2));
|
||||||
|
console.log('📡 백링크 응답 키들:', Object.keys(response || {}));
|
||||||
|
|
||||||
|
// API 응답이 객체일 경우 처리
|
||||||
|
if (Array.isArray(response)) {
|
||||||
|
this.backlinks = response;
|
||||||
|
} else if (response && typeof response === 'object') {
|
||||||
|
// 객체에서 배열 추출 시도
|
||||||
|
if (response.data && Array.isArray(response.data)) {
|
||||||
|
this.backlinks = response.data;
|
||||||
|
} else if (response.backlinks && Array.isArray(response.backlinks)) {
|
||||||
|
this.backlinks = response.backlinks;
|
||||||
|
} else {
|
||||||
|
console.warn('⚠️ 예상치 못한 백링크 API 응답 구조:', response);
|
||||||
|
this.backlinks = [];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.backlinks = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('📡 최종 백링크 데이터:', this.backlinks);
|
||||||
|
console.log('📡 최종 백링크 개수:', this.backlinks.length);
|
||||||
return this.backlinks;
|
return this.backlinks;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('백링크 로드 실패:', error);
|
console.error('❌ 백링크 로드 실패:', error);
|
||||||
this.backlinks = [];
|
this.backlinks = [];
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,8 +53,20 @@ class CachedAPI {
|
|||||||
} else if (endpoint === '/document-links/backlinks' && params.target_document_id) {
|
} else if (endpoint === '/document-links/backlinks' && params.target_document_id) {
|
||||||
// 실제: /documents/{documentId}/backlinks
|
// 실제: /documents/{documentId}/backlinks
|
||||||
response = await this.api.get(`/documents/${params.target_document_id}/backlinks`);
|
response = await this.api.get(`/documents/${params.target_document_id}/backlinks`);
|
||||||
} else if (endpoint.startsWith('/documents/') && endpoint.includes('/')) {
|
} else if (endpoint.startsWith('/documents/') && endpoint.endsWith('/links')) {
|
||||||
|
// /documents/{documentId}/links 패턴
|
||||||
const documentId = endpoint.split('/')[2];
|
const documentId = endpoint.split('/')[2];
|
||||||
|
console.log('🔗 CachedAPI: 링크 API 직접 호출:', documentId);
|
||||||
|
response = await this.api.getDocumentLinks(documentId);
|
||||||
|
} else if (endpoint.startsWith('/documents/') && endpoint.endsWith('/backlinks')) {
|
||||||
|
// /documents/{documentId}/backlinks 패턴
|
||||||
|
const documentId = endpoint.split('/')[2];
|
||||||
|
console.log('🔗 CachedAPI: 백링크 API 직접 호출:', documentId);
|
||||||
|
response = await this.api.getDocumentBacklinks(documentId);
|
||||||
|
} else if (endpoint.startsWith('/documents/') && endpoint.match(/^\/documents\/[^\/]+$/)) {
|
||||||
|
// /documents/{documentId} 패턴만 (추가 경로 없음)
|
||||||
|
const documentId = endpoint.split('/')[2];
|
||||||
|
console.log('📄 CachedAPI: 문서 API 호출:', documentId);
|
||||||
response = await this.api.getDocument(documentId);
|
response = await this.api.getDocument(documentId);
|
||||||
} else {
|
} else {
|
||||||
// 기본 API 호출 (기존 방식)
|
// 기본 API 호출 (기존 방식)
|
||||||
|
|||||||
@@ -148,9 +148,12 @@ window.documentViewer = () => ({
|
|||||||
throw new Error('필수 모듈을 로드할 수 없습니다.');
|
throw new Error('필수 모듈을 로드할 수 없습니다.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// UI 상태를 UIManager와 동기화
|
// UI 상태를 UIManager와 동기화 (모달은 초기화 시 닫힌 상태로)
|
||||||
this.syncUIState();
|
this.syncUIState();
|
||||||
|
|
||||||
|
// 초기화 시 모든 모달을 명시적으로 닫기
|
||||||
|
this.closeAllModals();
|
||||||
|
|
||||||
// 나머지 모듈들은 백그라운드에서 프리로딩 (지연 로딩 가능한 경우만)
|
// 나머지 모듈들은 백그라운드에서 프리로딩 (지연 로딩 가능한 경우만)
|
||||||
if (window.moduleLoader) {
|
if (window.moduleLoader) {
|
||||||
window.moduleLoader.preloadModules(['HighlightManager', 'BookmarkManager', 'LinkManager']);
|
window.moduleLoader.preloadModules(['HighlightManager', 'BookmarkManager', 'LinkManager']);
|
||||||
@@ -223,6 +226,22 @@ window.documentViewer = () => ({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ==================== 모든 모달 닫기 ====================
|
||||||
|
closeAllModals() {
|
||||||
|
console.log('🔒 초기화 시 모든 모달 닫기');
|
||||||
|
this.showLinksModal = false;
|
||||||
|
this.showLinkModal = false;
|
||||||
|
this.showNotesModal = false;
|
||||||
|
this.showBookmarksModal = false;
|
||||||
|
this.showBacklinksModal = false;
|
||||||
|
this.showNoteInputModal = false;
|
||||||
|
|
||||||
|
// UIManager에도 반영
|
||||||
|
if (this.uiManager) {
|
||||||
|
this.uiManager.closeAllModals();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// ==================== URL 파라미터 처리 ====================
|
// ==================== URL 파라미터 처리 ====================
|
||||||
parseUrlParameters() {
|
parseUrlParameters() {
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
@@ -289,13 +308,17 @@ window.documentViewer = () => ({
|
|||||||
this.linkManager.loadBacklinks(this.documentId)
|
this.linkManager.loadBacklinks(this.documentId)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 데이터 저장
|
// 데이터 저장 및 모듈 동기화
|
||||||
this.highlights = highlights;
|
this.highlights = highlights;
|
||||||
this.notes = notes;
|
this.notes = notes;
|
||||||
this.bookmarks = bookmarks;
|
this.bookmarks = bookmarks;
|
||||||
this.documentLinks = documentLinks;
|
this.documentLinks = documentLinks;
|
||||||
this.backlinks = backlinks;
|
this.backlinks = backlinks;
|
||||||
|
|
||||||
|
// 모듈에 데이터 동기화 (중요!)
|
||||||
|
this.linkManager.documentLinks = documentLinks;
|
||||||
|
this.linkManager.backlinks = backlinks;
|
||||||
|
|
||||||
console.log('📊 로드된 데이터:', {
|
console.log('📊 로드된 데이터:', {
|
||||||
highlights: highlights.length,
|
highlights: highlights.length,
|
||||||
notes: notes.length,
|
notes: notes.length,
|
||||||
@@ -303,6 +326,11 @@ window.documentViewer = () => ({
|
|||||||
documentLinks: documentLinks.length,
|
documentLinks: documentLinks.length,
|
||||||
backlinks: backlinks.length
|
backlinks: backlinks.length
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('🔄 모듈 데이터 동기화 완료:', {
|
||||||
|
'linkManager.documentLinks': this.linkManager.documentLinks?.length || 0,
|
||||||
|
'linkManager.backlinks': this.linkManager.backlinks?.length || 0
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
// ==================== 모듈 지연 로딩 보장 (폴백 포함) ====================
|
// ==================== 모듈 지연 로딩 보장 (폴백 포함) ====================
|
||||||
|
|||||||
Reference in New Issue
Block a user