Fix: 노트 링크 관련 모든 기능 완전 수정
주요 수정사항:
- 노트 간 링크 네비게이션 수정 (target_note_id 우선 사용)
- 노트 백링크 네비게이션 수정 (source_note_id 우선 사용)
- 노트 링크 삭제 API 분기 처리 (/note-links vs /document-links)
- 하이라이트 삭제 시 메모 캐시 무효화 추가
- 하이라이트 메모 삭제 API 엔드포인트 추가 (DELETE /highlight-notes/{note_id})
- URL 파싱 개선 (null/undefined ID 감지 및 오류 처리)
- 노트 링크 생성 응답에 source_content_type, target_content_type 추가
- 통합 툴팁에서 노트 링크 제목 표시 수정 (target_note_title 사용)
- 링크 삭제 버튼에서 null 참조 오류 수정
수정된 파일:
- frontend: viewer-core.js, link-manager.js, highlight-manager.js, api.js, cached-api.js
- backend: note_links.py, notes.py
- 브라우저 캐시 무효화: 버전 v=2025012623
This commit is contained in:
@@ -730,7 +730,21 @@ class HighlightManager {
|
||||
async deleteHighlight(highlightId) {
|
||||
try {
|
||||
await this.api.delete(`/highlights/${highlightId}`);
|
||||
|
||||
// 하이라이트 배열에서 제거
|
||||
this.highlights = this.highlights.filter(h => h.id !== highlightId);
|
||||
|
||||
// 메모 배열에서도 해당 하이라이트의 메모들 제거
|
||||
this.notes = this.notes.filter(note => note.highlight_id !== highlightId);
|
||||
|
||||
// 캐시 무효화 (하이라이트와 메모 모두)
|
||||
if (window.documentViewerInstance && window.documentViewerInstance.cacheManager) {
|
||||
window.documentViewerInstance.cacheManager.invalidateCategory('highlights');
|
||||
window.documentViewerInstance.cacheManager.invalidateCategory('notes');
|
||||
console.log('🗑️ 하이라이트 삭제 후 캐시 무효화 완료');
|
||||
}
|
||||
|
||||
// 화면 다시 렌더링
|
||||
this.renderHighlights();
|
||||
console.log('하이라이트 삭제 완료:', highlightId);
|
||||
} catch (error) {
|
||||
@@ -1071,7 +1085,7 @@ class HighlightManager {
|
||||
</svg>
|
||||
복사
|
||||
</button>
|
||||
<button onclick="window.documentViewerInstance.highlightManager.deleteHighlightWithConfirm('${clickedHighlight.id}')"
|
||||
<button onclick="window.documentViewerInstance.deleteHighlightWithConfirm('${clickedHighlight.id}')"
|
||||
class="text-xs bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600 transition-colors flex items-center"
|
||||
title="하이라이트 삭제">
|
||||
<svg class="w-3 h-3 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
|
||||
@@ -781,7 +781,7 @@ class LinkManager {
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col sm:flex-row gap-3 mb-4">
|
||||
<button onclick="window.documentViewerInstance.linkManager.navigateToLinkedDocument('${link.target_document_id}', ${JSON.stringify(link).replace(/"/g, '"')})"
|
||||
<button onclick="window.documentViewerInstance.linkManager.navigateToLinkedDocument('${link.target_note_id || link.target_document_id}', ${JSON.stringify(link).replace(/"/g, '"')})"
|
||||
class="flex-1 bg-purple-500 text-white px-4 py-2 rounded-lg hover:bg-purple-600 transition-colors flex items-center justify-center">
|
||||
<svg class="w-4 h-4 mr-2" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M10.293 3.293a1 1 0 011.414 0l6 6a1 1 0 010 1.414l-6 6a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-4.293-4.293a1 1 0 010-1.414z" clip-rule="evenodd"></path>
|
||||
@@ -1033,10 +1033,22 @@ class LinkManager {
|
||||
linkInfo: linkInfo
|
||||
});
|
||||
|
||||
if (!targetDocumentId) {
|
||||
console.error('❌ targetDocumentId가 없습니다!');
|
||||
alert('대상 문서 ID가 없습니다.');
|
||||
return;
|
||||
// targetDocumentId가 null이거나 'null' 문자열인 경우 처리
|
||||
if (!targetDocumentId || targetDocumentId === 'null' || targetDocumentId === null) {
|
||||
console.error('❌ targetDocumentId가 유효하지 않습니다:', targetDocumentId);
|
||||
console.log('🔍 linkInfo에서 대체 ID 찾기:', linkInfo);
|
||||
|
||||
// linkInfo에서 대체 ID 찾기 (노트 링크의 경우 target_note_id 우선)
|
||||
if (linkInfo && linkInfo.target_note_id && linkInfo.target_note_id !== 'null') {
|
||||
targetDocumentId = linkInfo.target_note_id;
|
||||
console.log('✅ linkInfo에서 target_note_id 발견:', targetDocumentId);
|
||||
} else if (linkInfo && linkInfo.target_document_id && linkInfo.target_document_id !== 'null') {
|
||||
targetDocumentId = linkInfo.target_document_id;
|
||||
console.log('✅ linkInfo에서 target_document_id 발견:', targetDocumentId);
|
||||
} else {
|
||||
alert('대상 문서 ID가 유효하지 않습니다.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// contentType에 따라 적절한 URL 생성
|
||||
@@ -1083,7 +1095,18 @@ class LinkManager {
|
||||
// source_content_type에 따라 적절한 URL 생성
|
||||
let targetUrl;
|
||||
|
||||
if (backlinkInfo.source_content_type === 'note') {
|
||||
// source_content_type이 없으면 ID로 추론
|
||||
let sourceContentType = backlinkInfo.source_content_type;
|
||||
if (!sourceContentType) {
|
||||
if (backlinkInfo.source_note_id) {
|
||||
sourceContentType = 'note';
|
||||
} else if (backlinkInfo.source_document_id) {
|
||||
sourceContentType = 'document';
|
||||
}
|
||||
console.log('🔍 백링크에서 source_content_type 추론됨:', sourceContentType);
|
||||
}
|
||||
|
||||
if (sourceContentType === 'note') {
|
||||
// 노트 문서로 이동
|
||||
targetUrl = `/viewer.html?id=${sourceDocumentId}&contentType=note`;
|
||||
console.log('📝 노트 문서로 이동 (백링크):', sourceDocumentId);
|
||||
@@ -1114,7 +1137,19 @@ class LinkManager {
|
||||
}
|
||||
|
||||
try {
|
||||
await this.api.delete(`/document-links/${linkId}`);
|
||||
// 링크 타입 확인 (노트 링크인지 문서 링크인지)
|
||||
const link = this.documentLinks.find(l => l.id === linkId);
|
||||
|
||||
if (link && link.source_note_id) {
|
||||
// 노트 링크 삭제
|
||||
console.log('📝 노트 링크 삭제 API 호출');
|
||||
await this.api.delete(`/note-links/${linkId}`);
|
||||
} else {
|
||||
// 문서 링크 삭제
|
||||
console.log('📄 문서 링크 삭제 API 호출');
|
||||
await this.api.delete(`/document-links/${linkId}`);
|
||||
}
|
||||
|
||||
this.documentLinks = this.documentLinks.filter(l => l.id !== linkId);
|
||||
|
||||
this.hideTooltip();
|
||||
|
||||
Reference in New Issue
Block a user