Files
2026-04-22 21:11:57 +09:00

100 lines
3.5 KiB
JavaScript

import { state } from '../state.js';
/**
* initGlobalSearch - Initializes the canvas-wide search and highlight functionality
*/
export function initGlobalSearch() {
const searchInput = document.getElementById('global-search');
if (!searchInput) return;
searchInput.addEventListener('input', (e) => {
const query = e.target.value.toLowerCase().trim();
if (!state.graph) return;
const allNodes = state.graph.getNodes();
if (query === '') {
allNodes.forEach(node => {
node.attr('body/opacity', 1);
node.attr('image/opacity', 1);
node.attr('label/opacity', 1);
node.removeTools();
});
return;
}
allNodes.forEach(node => {
const data = node.getData() || {};
const label = (node.attr('label/text') || '').toLowerCase();
const id = node.id.toLowerCase();
// PM 전용 표준 속성 검색 대상 포함
const searchFields = [
id, label,
(data.type || '').toLowerCase(),
(data.ip || '').toLowerCase(),
(data.model || '').toLowerCase(),
(data.vendor || '').toLowerCase(),
(data.asset_tag || '').toLowerCase(),
(data.serial || '').toLowerCase(),
(data.project || '').toLowerCase(),
(data.tags || []).join(' ').toLowerCase()
];
const isMatch = searchFields.some(field => field.includes(query));
if (isMatch) {
node.attr('body/opacity', 1);
node.attr('image/opacity', 1);
node.attr('label/opacity', 1);
// 검색 강조 툴 추가
node.addTools({
name: 'boundary',
args: {
padding: 5,
attrs: {
fill: 'none',
stroke: '#3b82f6',
strokeWidth: 3,
strokeDasharray: '0',
},
},
});
} else {
node.attr('body/opacity', 0.1);
node.attr('image/opacity', 0.1);
node.attr('label/opacity', 0.1);
node.removeTools();
}
});
});
// 엔터 키 입력 시 검색된 첫 번째 항목으로 포커싱
searchInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
const query = e.target.value.toLowerCase().trim();
if (!query || !state.graph) return;
const matches = state.graph.getNodes().filter(node => {
const data = node.getData() || {};
const label = (node.attr('label/text') || '').toLowerCase();
const searchFields = [
node.id.toLowerCase(), label,
(data.ip || ''), (data.asset_tag || ''), (data.model || '')
];
return searchFields.some(f => f.toLowerCase().includes(query));
});
if (matches.length > 0) {
// 첫 번째 매치된 항목으로 줌인
state.graph.zoomToCell(matches[0], {
padding: 100,
animation: { duration: 600 }
});
state.graph.select(matches[0]);
}
}
});
}