add go bench client
This commit is contained in:
@@ -14,33 +14,34 @@ let editingNotes = false;
|
||||
let editingUpgradeNotes = false;
|
||||
let editingPurchase = false;
|
||||
|
||||
const SECTION_ICON_PATHS = {
|
||||
motherboard: 'icons/icons8-motherboard-94.png',
|
||||
cpu: 'icons/icons8-processor-94.png',
|
||||
ram: 'icons/icons8-memory-slot-94.png',
|
||||
storage: 'icons/icons8-ssd-94.png',
|
||||
gpu: 'icons/icons8-gpu-64.png',
|
||||
network: 'icons/icons8-network-cable-94.png',
|
||||
usb: 'icons/icons8-usb-memory-stick-94.png',
|
||||
pci: 'icons/icons8-pcie-48.png',
|
||||
os: 'icons/icons8-operating-system-64.png',
|
||||
shares: 'icons/icons8-shared-folder-94.png',
|
||||
benchmarks: 'icons/icons8-benchmark-64.png',
|
||||
metadata: 'icons/icons8-hardware-64.png',
|
||||
images: 'icons/icons8-picture-48.png',
|
||||
pdf: 'icons/icons8-bios-94.png',
|
||||
links: 'icons/icons8-server-94.png',
|
||||
tags: 'icons/icons8-check-mark-48.png',
|
||||
notes: 'icons/icons8-edit-pencil-48.png',
|
||||
purchase: 'icons/icons8-laptop-50.png',
|
||||
upgrade: 'icons/icons8-workstation-94.png'
|
||||
// Section icon mapping - uses data-icon with IconManager
|
||||
const SECTION_ICON_NAMES = {
|
||||
motherboard: 'motherboard',
|
||||
cpu: 'cpu',
|
||||
ram: 'memory',
|
||||
storage: 'hdd',
|
||||
gpu: 'gpu',
|
||||
network: 'network',
|
||||
usb: 'usb',
|
||||
pci: 'pci',
|
||||
os: 'desktop',
|
||||
shares: 'folder',
|
||||
benchmarks: 'chart-line',
|
||||
metadata: 'info-circle',
|
||||
images: 'image',
|
||||
pdf: 'file-pdf',
|
||||
links: 'link',
|
||||
tags: 'tag',
|
||||
notes: 'edit',
|
||||
purchase: 'shopping-cart',
|
||||
upgrade: 'rocket'
|
||||
};
|
||||
|
||||
function getSectionIcon(key, altText) {
|
||||
const src = SECTION_ICON_PATHS[key];
|
||||
if (!src) return '';
|
||||
const iconName = SECTION_ICON_NAMES[key];
|
||||
if (!iconName) return '';
|
||||
const safeAlt = utils.escapeHtml(altText || key);
|
||||
return `<img src="${src}" alt="${safeAlt}" class="section-icon" loading="lazy">`;
|
||||
return `<span class="section-icon" data-icon="${iconName}" title="${safeAlt}"></span>`;
|
||||
}
|
||||
|
||||
// Load devices
|
||||
@@ -1083,6 +1084,117 @@ async function viewBenchmarkDetails(benchmarkId) {
|
||||
}
|
||||
}
|
||||
|
||||
// Render IP Display with edit capability
|
||||
function renderIPDisplay(snapshot, device) {
|
||||
// Extract non-loopback IPs
|
||||
const networkInterfaces = snapshot?.network_interfaces_json ?
|
||||
(typeof snapshot.network_interfaces_json === 'string' ? JSON.parse(snapshot.network_interfaces_json) : snapshot.network_interfaces_json) :
|
||||
[];
|
||||
|
||||
const ips = networkInterfaces
|
||||
.filter(iface => iface.ipv4 && iface.ipv4 !== '127.0.0.1' && iface.ipv4 !== 'N/A')
|
||||
.map(iface => iface.ipv4);
|
||||
|
||||
const displayIP = ips.length > 0 ? ips.join(', ') : 'N/A';
|
||||
const ipUrl = device.ip_url || (ips.length > 0 ? `http://${ips[0]}` : '');
|
||||
|
||||
return `
|
||||
<div style="display: flex; flex-direction: column; gap: 0.5rem;">
|
||||
<div style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
${ipUrl ? `<a href="${utils.escapeHtml(ipUrl)}" target="_blank" rel="noopener noreferrer" style="color: var(--color-info); text-decoration: none; font-weight: 600;" title="Ouvrir ${utils.escapeHtml(ipUrl)}">${utils.escapeHtml(displayIP)}</a>` : `<span>${utils.escapeHtml(displayIP)}</span>`}
|
||||
<button id="btn-edit-ip-url" class="icon-btn" data-icon="edit" title="Éditer le lien IP" type="button" style="padding: 0.25rem; font-size: 0.75rem;">
|
||||
<span data-icon="edit"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="ip-url-editor" style="display: none;">
|
||||
<input type="text" id="ip-url-input" class="ip-url-input" placeholder="http://${ips[0] || '10.0.0.1'}" value="${utils.escapeHtml(ipUrl)}" style="width: 100%; padding: 0.5rem; border: 1px solid var(--border-color); border-radius: 4px; background: var(--bg-primary); color: var(--text-primary);">
|
||||
<div style="display: flex; gap: 0.5rem; margin-top: 0.5rem;">
|
||||
<button id="btn-save-ip-url" class="btn btn-success btn-sm" data-icon="check" type="button">
|
||||
<span data-icon="check"></span> Sauvegarder
|
||||
</button>
|
||||
<button id="btn-cancel-ip-url" class="btn btn-secondary btn-sm" data-icon="times" type="button">
|
||||
<span data-icon="times"></span> Annuler
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
async function editIPUrl() {
|
||||
const editor = document.getElementById('ip-url-editor');
|
||||
const btnEdit = document.getElementById('btn-edit-ip-url');
|
||||
if (!editor || !btnEdit) return;
|
||||
|
||||
editor.style.display = 'block';
|
||||
btnEdit.style.display = 'none';
|
||||
document.getElementById('ip-url-input')?.focus();
|
||||
}
|
||||
|
||||
async function saveIPUrl() {
|
||||
if (!currentDevice) return;
|
||||
|
||||
const input = document.getElementById('ip-url-input');
|
||||
if (!input) return;
|
||||
|
||||
let url = input.value.trim();
|
||||
|
||||
// Auto-prefix http:// if not present and not empty
|
||||
if (url && !url.match(/^https?:\/\//)) {
|
||||
url = `http://${url}`;
|
||||
}
|
||||
|
||||
try {
|
||||
await apiClient.updateDevice(currentDevice.id, { ip_url: url || null });
|
||||
utils.showToast('Lien IP sauvegardé', 'success');
|
||||
await reloadCurrentDevice();
|
||||
} catch (error) {
|
||||
console.error('Failed to save IP URL:', error);
|
||||
utils.showToast(error.message || 'Échec de la sauvegarde du lien IP', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function cancelIPUrlEdit() {
|
||||
if (!currentDevice) return;
|
||||
|
||||
const editor = document.getElementById('ip-url-editor');
|
||||
const btnEdit = document.getElementById('btn-edit-ip-url');
|
||||
if (!editor || !btnEdit) return;
|
||||
|
||||
editor.style.display = 'none';
|
||||
btnEdit.style.display = 'inline-block';
|
||||
|
||||
// Reset input value
|
||||
const input = document.getElementById('ip-url-input');
|
||||
if (input) {
|
||||
input.value = currentDevice.ip_url || '';
|
||||
}
|
||||
}
|
||||
|
||||
// Search model on web
|
||||
function searchModelOnWeb() {
|
||||
const btn = document.getElementById('btn-search-model');
|
||||
if (!btn) return;
|
||||
|
||||
const model = btn.dataset.model;
|
||||
if (!model || model === 'N/A') {
|
||||
utils.showToast('Aucun modèle à rechercher', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
// Get search engine from settings (default: Google)
|
||||
const searchEngine = localStorage.getItem('searchEngine') || 'google';
|
||||
|
||||
const searchUrls = {
|
||||
google: `https://www.google.com/search?q=${encodeURIComponent(model)}`,
|
||||
duckduckgo: `https://duckduckgo.com/?q=${encodeURIComponent(model)}`,
|
||||
bing: `https://www.bing.com/search?q=${encodeURIComponent(model)}`
|
||||
};
|
||||
|
||||
const url = searchUrls[searchEngine] || searchUrls.google;
|
||||
window.open(url, '_blank', 'noopener,noreferrer');
|
||||
}
|
||||
|
||||
// Render device details (right panel)
|
||||
function renderDeviceDetails(device) {
|
||||
const previousDeviceId = currentDevice?.id;
|
||||
@@ -1118,6 +1230,14 @@ function renderDeviceDetails(device) {
|
||||
<div class="header-meta">${metaParts.length > 0 ? metaParts.join(' • ') : 'Aucune métadonnée'}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-row">
|
||||
<div>
|
||||
<div class="header-label">Adresse IP</div>
|
||||
<div class="header-value" id="ip-display-container">
|
||||
${renderIPDisplay(snapshot, device)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-row">
|
||||
<div>
|
||||
<div class="header-label">Marque</div>
|
||||
@@ -1127,7 +1247,12 @@ function renderDeviceDetails(device) {
|
||||
<div class="header-row">
|
||||
<div>
|
||||
<div class="header-label">Modèle</div>
|
||||
<div class="header-value">${utils.escapeHtml(model)}</div>
|
||||
<div class="header-value" style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<span>${utils.escapeHtml(model)}</span>
|
||||
<button id="btn-search-model" class="icon-btn" title="Recherche sur le Web" type="button" style="padding: 0.25rem; font-size: 0.75rem;" data-model="${utils.escapeHtml(model)}">
|
||||
<span data-icon="globe"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-row">
|
||||
@@ -1291,6 +1416,11 @@ function renderDeviceDetails(device) {
|
||||
|
||||
detailsContainer.innerHTML = headerHtml + orderedSections;
|
||||
|
||||
// Initialize icons using IconManager
|
||||
if (window.IconManager) {
|
||||
window.IconManager.inlineSvgIcons(detailsContainer);
|
||||
}
|
||||
|
||||
bindDetailActions();
|
||||
loadLinksSection(device.id);
|
||||
loadBenchmarkHistorySection(device.id);
|
||||
@@ -1305,6 +1435,14 @@ function bindDetailActions() {
|
||||
const btnUploadPDF = document.getElementById('btn-upload-pdf');
|
||||
const btnDelete = document.getElementById('btn-delete');
|
||||
|
||||
// IP URL editing
|
||||
const btnEditIpUrl = document.getElementById('btn-edit-ip-url');
|
||||
const btnSaveIpUrl = document.getElementById('btn-save-ip-url');
|
||||
const btnCancelIpUrl = document.getElementById('btn-cancel-ip-url');
|
||||
|
||||
// Web search
|
||||
const btnSearchModel = document.getElementById('btn-search-model');
|
||||
|
||||
if (btnEdit) btnEdit.addEventListener('click', toggleEditMode);
|
||||
if (btnSave) btnSave.addEventListener('click', saveDevice);
|
||||
if (btnCancel) {
|
||||
@@ -1317,6 +1455,14 @@ function bindDetailActions() {
|
||||
if (btnUploadImageHeader) btnUploadImageHeader.addEventListener('click', uploadImage);
|
||||
if (btnUploadPDF) btnUploadPDF.addEventListener('click', uploadPDF);
|
||||
if (btnDelete) btnDelete.addEventListener('click', deleteCurrentDevice);
|
||||
|
||||
// Bind IP URL actions
|
||||
if (btnEditIpUrl) btnEditIpUrl.addEventListener('click', editIPUrl);
|
||||
if (btnSaveIpUrl) btnSaveIpUrl.addEventListener('click', saveIPUrl);
|
||||
if (btnCancelIpUrl) btnCancelIpUrl.addEventListener('click', cancelIPUrlEdit);
|
||||
|
||||
// Bind web search
|
||||
if (btnSearchModel) btnSearchModel.addEventListener('click', searchModelOnWeb);
|
||||
}
|
||||
|
||||
async function loadLinksSection(deviceId) {
|
||||
|
||||
Reference in New Issue
Block a user