From 7f68c1948148b2d52095a5e157e9ba040dbcf8e8 Mon Sep 17 00:00:00 2001 From: Hyungi Ahn Date: Thu, 28 Aug 2025 13:21:03 +0900 Subject: [PATCH] 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) --- .../static/js/viewer/features/link-manager.js | 66 ++++++++++++++++--- frontend/static/js/viewer/utils/cached-api.js | 14 +++- frontend/static/js/viewer/viewer-core.js | 32 ++++++++- 3 files changed, 99 insertions(+), 13 deletions(-) diff --git a/frontend/static/js/viewer/features/link-manager.js b/frontend/static/js/viewer/features/link-manager.js index fbe204f..3ae3651 100644 --- a/frontend/static/js/viewer/features/link-manager.js +++ b/frontend/static/js/viewer/features/link-manager.js @@ -27,13 +27,37 @@ class LinkManager { async loadDocumentLinks(documentId) { try { console.log('๐Ÿ“ก ๋งํฌ API ํ˜ธ์ถœ:', `/documents/${documentId}/links`); - const response = await this.cachedApi.get(`/documents/${documentId}/links`, {}, { category: 'links' }).catch(() => []); - this.documentLinks = Array.isArray(response) ? response : []; - console.log('๐Ÿ“ก API ์‘๋‹ต ๋งํฌ ๊ฐœ์ˆ˜:', this.documentLinks.length); - console.log('๐Ÿ“ก API ์‘๋‹ต ํƒ€์ž…:', typeof response, response); + console.log('๐Ÿ“ก ์‚ฌ์šฉ ์ค‘์ธ documentId:', documentId); + console.log('๐Ÿ“ก cachedApi ๊ฐ์ฒด:', this.cachedApi); + const response = await this.cachedApi.get(`/documents/${documentId}/links`, {}, { category: 'links' }); + 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; } catch (error) { - console.error('๋ฌธ์„œ ๋งํฌ ๋กœ๋“œ ์‹คํŒจ:', error); + console.error('โŒ ๋ฌธ์„œ ๋งํฌ ๋กœ๋“œ ์‹คํŒจ:', error); this.documentLinks = []; return []; } @@ -45,13 +69,35 @@ class LinkManager { async loadBacklinks(documentId) { try { console.log('๐Ÿ“ก ๋ฐฑ๋งํฌ API ํ˜ธ์ถœ:', `/documents/${documentId}/backlinks`); - const response = await this.cachedApi.get(`/documents/${documentId}/backlinks`, {}, { category: 'links' }).catch(() => []); - this.backlinks = Array.isArray(response) ? response : []; - console.log('๐Ÿ“ก API ์‘๋‹ต ๋ฐฑ๋งํฌ ๊ฐœ์ˆ˜:', this.backlinks.length); - console.log('๐Ÿ“ก API ์‘๋‹ต ํƒ€์ž…:', typeof response, response); + const response = await this.cachedApi.get(`/documents/${documentId}/backlinks`, {}, { category: 'links' }); + console.log('๐Ÿ“ก ์›๋ณธ ๋ฐฑ๋งํฌ ์‘๋‹ต:', 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.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; } catch (error) { - console.error('๋ฐฑ๋งํฌ ๋กœ๋“œ ์‹คํŒจ:', error); + console.error('โŒ ๋ฐฑ๋งํฌ ๋กœ๋“œ ์‹คํŒจ:', error); this.backlinks = []; return []; } diff --git a/frontend/static/js/viewer/utils/cached-api.js b/frontend/static/js/viewer/utils/cached-api.js index 062ac53..8c2ba1c 100644 --- a/frontend/static/js/viewer/utils/cached-api.js +++ b/frontend/static/js/viewer/utils/cached-api.js @@ -53,8 +53,20 @@ class CachedAPI { } else if (endpoint === '/document-links/backlinks' && params.target_document_id) { // ์‹ค์ œ: /documents/{documentId}/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]; + 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); } else { // ๊ธฐ๋ณธ API ํ˜ธ์ถœ (๊ธฐ์กด ๋ฐฉ์‹) diff --git a/frontend/static/js/viewer/viewer-core.js b/frontend/static/js/viewer/viewer-core.js index 7e4d99f..ed076a9 100644 --- a/frontend/static/js/viewer/viewer-core.js +++ b/frontend/static/js/viewer/viewer-core.js @@ -148,9 +148,12 @@ window.documentViewer = () => ({ throw new Error('ํ•„์ˆ˜ ๋ชจ๋“ˆ์„ ๋กœ๋“œํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.'); } - // UI ์ƒํƒœ๋ฅผ UIManager์™€ ๋™๊ธฐํ™” + // UI ์ƒํƒœ๋ฅผ UIManager์™€ ๋™๊ธฐํ™” (๋ชจ๋‹ฌ์€ ์ดˆ๊ธฐํ™” ์‹œ ๋‹ซํžŒ ์ƒํƒœ๋กœ) this.syncUIState(); + // ์ดˆ๊ธฐํ™” ์‹œ ๋ชจ๋“  ๋ชจ๋‹ฌ์„ ๋ช…์‹œ์ ์œผ๋กœ ๋‹ซ๊ธฐ + this.closeAllModals(); + // ๋‚˜๋จธ์ง€ ๋ชจ๋“ˆ๋“ค์€ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ํ”„๋ฆฌ๋กœ๋”ฉ (์ง€์—ฐ ๋กœ๋”ฉ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ๋งŒ) if (window.moduleLoader) { 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 ํŒŒ๋ผ๋ฏธํ„ฐ ์ฒ˜๋ฆฌ ==================== parseUrlParameters() { const urlParams = new URLSearchParams(window.location.search); @@ -289,13 +308,17 @@ window.documentViewer = () => ({ this.linkManager.loadBacklinks(this.documentId) ]); - // ๋ฐ์ดํ„ฐ ์ €์žฅ + // ๋ฐ์ดํ„ฐ ์ €์žฅ ๋ฐ ๋ชจ๋“ˆ ๋™๊ธฐํ™” this.highlights = highlights; this.notes = notes; this.bookmarks = bookmarks; this.documentLinks = documentLinks; this.backlinks = backlinks; + // ๋ชจ๋“ˆ์— ๋ฐ์ดํ„ฐ ๋™๊ธฐํ™” (์ค‘์š”!) + this.linkManager.documentLinks = documentLinks; + this.linkManager.backlinks = backlinks; + console.log('๐Ÿ“Š ๋กœ๋“œ๋œ ๋ฐ์ดํ„ฐ:', { highlights: highlights.length, notes: notes.length, @@ -303,6 +326,11 @@ window.documentViewer = () => ({ documentLinks: documentLinks.length, backlinks: backlinks.length }); + + console.log('๐Ÿ”„ ๋ชจ๋“ˆ ๋ฐ์ดํ„ฐ ๋™๊ธฐํ™” ์™„๋ฃŒ:', { + 'linkManager.documentLinks': this.linkManager.documentLinks?.length || 0, + 'linkManager.backlinks': this.linkManager.backlinks?.length || 0 + }); }, // ==================== ๋ชจ๋“ˆ ์ง€์—ฐ ๋กœ๋”ฉ ๋ณด์žฅ (ํด๋ฐฑ ํฌํ•จ) ====================