main
Satur@it-depot.ru 2025-03-11 11:36:46 +03:00
parent c5de24cc08
commit 51da9cd359
4 changed files with 43 additions and 45 deletions

BIN
templates/icons/copy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
templates/icons/delete.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 B

BIN
templates/icons/edit.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -152,17 +152,17 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.protocol-icon { .protocol-icon img {
vertical-align: middle; height: 32px;
height: 16px; width: 32px;
width: 16px;
margin-right: 5px; margin-right: 5px;
vertical-align: middle;
} }
.connection-link { .connection-link {
color: #007bff; color: #007bff;
text-decoration: none; text-decoration: none;
flex-grow: 1; flex-grow: 1;
margin-right: 8px; /* Отступ перед иконками */ margin-right: 8px;
} }
.connection-link.dark-theme { .connection-link.dark-theme {
color: #66b0ff; color: #66b0ff;
@ -172,23 +172,41 @@
padding: 2px 5px; padding: 2px 5px;
display: flex; display: flex;
align-items: center; align-items: center;
background: none;
border: none;
cursor: pointer;
} }
.action-buttons.dark-theme button { .action-buttons.dark-theme button {
background-color: #555; background-color: #555;
color: #fff; color: #fff;
border: 1px solid #777; border: 1px solid #777;
} }
.edit-button, .copy-button, .note-button { .custom-icon {
margin-left: 8px; /* Отступ слева от текста */ height: 32px;
background: none; width: 32px;
background-size: contain;
background-repeat: no-repeat;
background-position: center;
border: none; border: none;
cursor: pointer;
font-size: 14px;
color: #000;
padding: 0; padding: 0;
cursor: pointer;
transition: background-color 0.2s, transform 0.2s;
} }
.edit-button.dark-theme, .copy-button.dark-theme, .note-button.dark-theme { .custom-icon:hover {
color: #fff; /* Темные иконки становятся белыми на темной теме */ background-color: #e0e0e0; /* Светлый фон при наведении */
transform: scale(1.1); /* Небольшое увеличение */
}
.custom-icon.dark-theme:hover {
background-color: #444; /* Темный фон при наведении на темной теме */
}
.edit-icon { background-image: url('/icons/edit.png'); }
.copy-icon { background-image: url('/icons/copy.png'); }
.note-icon { background-image: url('/icons/note.png'); }
.delete-icon { background-image: url('/icons/delete.png'); }
.folder-edit-icon { background-image: url('/icons/edit.png'); }
.folder-delete-icon { background-image: url('/icons/delete.png'); }
.edit-icon.dark-theme, .copy-icon.dark-theme, .note-icon.dark-theme, .delete-icon.dark-theme, .folder-edit-icon.dark-theme, .folder-delete-icon.dark-theme {
filter: brightness(0) invert(1); /* Инверсия для темной темы */
} }
#notes-content { #notes-content {
padding: 10px; padding: 10px;
@ -377,7 +395,6 @@
}; };
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
// Восстановление ширины окна с папками из localStorage
const savedWidth = localStorage.getItem('treeContainerWidth'); const savedWidth = localStorage.getItem('treeContainerWidth');
if (savedWidth) { if (savedWidth) {
document.getElementById('tree-container').style.width = savedWidth + 'px'; document.getElementById('tree-container').style.width = savedWidth + 'px';
@ -407,7 +424,7 @@
} }
localStorage.setItem('theme', defaultTheme); localStorage.setItem('theme', defaultTheme);
$('#installs-list').on('click', '.action-buttons button:nth-child(2)', function () { $('#installs-list').on('click', '.note-icon', function () {
const installId = $(this).closest('.install-item').data('id'); const installId = $(this).closest('.install-item').data('id');
const install = allInstalls.find(i => i.id === installId); const install = allInstalls.find(i => i.id === installId);
openNoteModal(installId, install?.note || ''); openNoteModal(installId, install?.note || '');
@ -440,7 +457,6 @@
document.addEventListener('mouseup', () => { document.addEventListener('mouseup', () => {
isResizing = false; isResizing = false;
document.body.style.cursor = 'default'; document.body.style.cursor = 'default';
// Сохраняем ширину в localStorage
const width = treeContainer.offsetWidth; const width = treeContainer.offsetWidth;
localStorage.setItem('treeContainerWidth', width); localStorage.setItem('treeContainerWidth', width);
}); });
@ -532,7 +548,6 @@
'core': { 'core': {
'data': function (node, cb) { 'data': function (node, cb) {
$.getJSON(`${API_URL}/folders`, function (data) { $.getJSON(`${API_URL}/folders`, function (data) {
console.log("Loaded folders:", data);
allFolders = data; allFolders = data;
const sortedFolders = [...data].sort((a, b) => a.name.localeCompare(b.name)); const sortedFolders = [...data].sort((a, b) => a.name.localeCompare(b.name));
const treeData = [ const treeData = [
@ -540,8 +555,8 @@
].concat(sortedFolders.map(folder => ({ ].concat(sortedFolders.map(folder => ({
id: folder.id, id: folder.id,
text: `${folder.name} <span class="folder-actions">` + text: `${folder.name} <span class="folder-actions">` +
`<button onclick="editFolder(${folder.id}, '${folder.name}')">✏️</button>` + `<button class="custom-icon folder-edit-icon" onclick="editFolder(${folder.id}, '${folder.name}')"></button>` +
`<button onclick="deleteFolder(${folder.id})">🗑️</button></span>`, `<button class="custom-icon folder-delete-icon" onclick="deleteFolder(${folder.id})"></button></span>`,
parent: folder.parent_id ? folder.parent_id : "root" parent: folder.parent_id ? folder.parent_id : "root"
}))); })));
cb(treeData); cb(treeData);
@ -608,20 +623,15 @@
}); });
$('#installs-list').on('dragstart', '.install-item', function (e) { $('#installs-list').on('dragstart', '.install-item', function (e) {
console.log('Drag start:', $(this).data('id'));
e.originalEvent.dataTransfer.setData('text/plain', $(this).data('id')); e.originalEvent.dataTransfer.setData('text/plain', $(this).data('id'));
}); });
$('#folder-tree').on('dragover', function (e) { $('#folder-tree').on('dragover', function (e) {
e.preventDefault(); e.preventDefault();
console.log('Drag over');
}).on('drop', function (e) { }).on('drop', function (e) {
e.preventDefault(); e.preventDefault();
console.log('Drop event triggered');
const installId = e.originalEvent.dataTransfer.getData('text'); const installId = e.originalEvent.dataTransfer.getData('text');
console.log('Dropped installId:', installId);
let targetFolderId = $(e.target).closest('.jstree-node').attr('id'); let targetFolderId = $(e.target).closest('.jstree-node').attr('id');
console.log('Target folderId:', targetFolderId);
if (installId && targetFolderId) { if (installId && targetFolderId) {
targetFolderId = targetFolderId === "root" ? null : targetFolderId; targetFolderId = targetFolderId === "root" ? null : targetFolderId;
moveInstallToFolder(installId, targetFolderId); moveInstallToFolder(installId, targetFolderId);
@ -653,8 +663,8 @@
}; };
ws.onclose = function() { ws.onclose = function() {
console.log('WebSocket disconnected, retrying...'); console.log('WebSocket disconnected, retrying...');
let retryDelay = 1000; // Начальная задержка 1 секунда let retryDelay = 1000;
const maxDelay = 30000; // Максимальная задержка 30 секунд const maxDelay = 30000;
const maxAttempts = 10; const maxAttempts = 10;
let attempts = 0; let attempts = 0;
@ -684,7 +694,6 @@
function loadInstalls(folderId) { function loadInstalls(folderId) {
$.getJSON(`${API_URL}/installs`, function (data) { $.getJSON(`${API_URL}/installs`, function (data) {
console.log("Loaded installs:", data);
allInstalls = data; allInstalls = data;
let filtered = folderId ? data.filter(i => i.folder_id == folderId && i.folder_id !== null) : data; let filtered = folderId ? data.filter(i => i.folder_id == folderId && i.folder_id !== null) : data;
displayInstalls(filtered); displayInstalls(filtered);
@ -703,8 +712,6 @@
const query = $('#search-input').val().toLowerCase().trim(); const query = $('#search-input').val().toLowerCase().trim();
const folderId = $('#folder-select').val() || ''; const folderId = $('#folder-select').val() || '';
console.log("Search query:", query, "Folder ID:", folderId);
let filteredInstalls = [...allInstalls]; let filteredInstalls = [...allInstalls];
if (folderId) { if (folderId) {
@ -725,21 +732,20 @@
} }
function displayInstalls(installs) { function displayInstalls(installs) {
console.log("Displaying installs:", installs);
const isDarkTheme = document.body.classList.contains('dark-theme'); const isDarkTheme = document.body.classList.contains('dark-theme');
if (installs.length === 0) { if (installs.length === 0) {
$('#installs-list').html('<p>Нет результатов</p>'); $('#installs-list').html('<p>Нет результатов</p>');
} else { } else {
$('#installs-list').html(installs.map(item => { $('#installs-list').html(installs.map(item => {
const lastSeen = new Date(item.last_seen || '1970-01-01'); const lastSeen = new Date(item.last_seen || '1970-01-01');
const isOnline = (new Date() - lastSeen) < 60000; // Онлайн, если менее 1 минуты const isOnline = (new Date() - lastSeen) < 60000;
const statusClass = isOnline ? 'status-online' : 'status-offline'; const statusClass = isOnline ? 'status-online' : 'status-offline';
return ` return `
<div class="install-item ${isDarkTheme ? 'dark-theme' : ''}" data-id="${item.id}" draggable="true"> <div class="install-item ${isDarkTheme ? 'dark-theme' : ''}" data-id="${item.id}" draggable="true">
<div class="computer-name">${item.computer_name} <button class="edit-button ${isDarkTheme ? 'dark-theme' : ''}" onclick="editField(${item.id}, 'computer_name', '${item.computer_name}')">✏️</button></div> <div class="computer-name">${item.computer_name} <button class="custom-icon edit-icon" onclick="editField(${item.id}, 'computer_name', '${item.computer_name}')"></button></div>
<div class="connection-id"><span class="protocol-icon">${protocolIcons[item.protocol]}</span><a href="${protocolLinks[item.protocol]}${item.rust_id}" class="connection-link ${isDarkTheme ? 'dark-theme' : ''}" target="_blank">${item.rust_id}</a><span class="${statusClass}"></span> <button class="copy-button ${isDarkTheme ? 'dark-theme' : ''}" onclick="copyToClipboard('${item.rust_id}')">📋</button> <button class="edit-button ${isDarkTheme ? 'dark-theme' : ''}" onclick="editField(${item.id}, 'rust_id', '${item.rust_id}')">✏️</button></div> <div class="connection-id"><span class="protocol-icon">${protocolIcons[item.protocol]}</span><a href="${protocolLinks[item.protocol]}${item.rust_id}" class="connection-link ${isDarkTheme ? 'dark-theme' : ''}" target="_blank">${item.rust_id}</a><span class="${statusClass}"></span> <button class="custom-icon copy-icon" onclick="copyToClipboard('${item.rust_id}')"></button> <button class="custom-icon edit-icon" onclick="editField(${item.id}, 'rust_id', '${item.rust_id}')"></button></div>
<div class="install-time">${item.install_time} <button class="edit-button ${isDarkTheme ? 'dark-theme' : ''}" onclick="editField(${item.id}, 'install_time', '${item.install_time}')">✏️</button></div> <div class="install-time">${item.install_time} <button class="custom-icon edit-icon" onclick="editField(${item.id}, 'install_time', '${item.install_time}')"></button></div>
<div class="actions"><span class="action-buttons"><button onclick="deleteInstall(${item.id})">Удалить</button> <button class="note-button ${isDarkTheme ? 'dark-theme' : ''}">Заметка</button></span></div> <div class="actions"><span class="action-buttons"><button class="custom-icon delete-icon" onclick="deleteInstall(${item.id})"></button> <button class="custom-icon note-icon"></button></span></div>
</div> </div>
`; `;
}).join('')); }).join(''));
@ -951,7 +957,6 @@
} }
function moveInstallToFolder(installId, folderId) { function moveInstallToFolder(installId, folderId) {
console.log('Moving installId:', installId, 'to folderId:', folderId);
const install = allInstalls.find(i => i.id === parseInt(installId)); const install = allInstalls.find(i => i.id === parseInt(installId));
if (!install) { if (!install) {
console.error('Install not found:', installId); console.error('Install not found:', installId);
@ -970,7 +975,6 @@
note: install.note note: install.note
}), }),
success: function () { success: function () {
console.log('Move successful');
loadInstalls(selectedFolderId); loadInstalls(selectedFolderId);
}, },
error: function (xhr, status, error) { error: function (xhr, status, error) {
@ -1016,7 +1020,6 @@
} }
function openNoteModal(installId, currentNote) { function openNoteModal(installId, currentNote) {
console.log('Opening note modal for installId:', installId, 'with note:', currentNote);
selectedInstallId = installId; selectedInstallId = installId;
$('#note-textarea').val(currentNote || ''); $('#note-textarea').val(currentNote || '');
$('#note-modal').show(); $('#note-modal').show();
@ -1043,7 +1046,6 @@
processData: false, processData: false,
contentType: false, contentType: false,
success: function (response) { success: function (response) {
console.log('Image uploaded:', response);
const imageUrl = response.url; const imageUrl = response.url;
const textarea = $('#note-textarea'); const textarea = $('#note-textarea');
const cursorPos = textarea[0].selectionStart; const cursorPos = textarea[0].selectionStart;
@ -1062,9 +1064,7 @@
} }
function saveNote() { function saveNote() {
console.log('Saving note for installId:', selectedInstallId);
if (!selectedInstallId) { if (!selectedInstallId) {
console.error('No install selected');
alert('Выберите запись для редактирования заметки.'); alert('Выберите запись для редактирования заметки.');
return; return;
} }
@ -1086,7 +1086,6 @@
note: note note: note
}), }),
success: function () { success: function () {
console.log('Note saved successfully');
loadInstalls(selectedFolderId); loadInstalls(selectedFolderId);
selectedInstallId = currentSelectedId; selectedInstallId = currentSelectedId;
closeNoteModal(); closeNoteModal();
@ -1164,7 +1163,7 @@
function formatItalic() { function formatItalic() {
const textarea = $('#note-textarea'); const textarea = $('#note-textarea');
const start = textarea[0].selectionStart; const start = textarea[0].selectionStart;
end = textarea[0].selectionEnd; const end = textarea[0].selectionEnd;
const text = textarea.val(); const text = textarea.val();
const selected = text.substring(start, end); const selected = text.substring(start, end);
const newText = `*${selected}*`; const newText = `*${selected}*`;
@ -1207,7 +1206,6 @@
contentType: 'application/json', contentType: 'application/json',
data: JSON.stringify({ name: folder.name, parent_id: newParentId }), data: JSON.stringify({ name: folder.name, parent_id: newParentId }),
success: function () { success: function () {
console.log(`Folder ${folderId} moved to parent ${newParentId}`);
loadFolders(); loadFolders();
$('#folder-tree').jstree(true).refresh(); $('#folder-tree').jstree(true).refresh();
}, },
@ -1228,7 +1226,7 @@
}).fail(function(jqxhr, textStatus, error) { }).fail(function(jqxhr, textStatus, error) {
console.error("Error syncing installs:", textStatus, error); console.error("Error syncing installs:", textStatus, error);
}); });
}, 60000); // Каждые 60 секунд }, 60000);
} }
startPeriodicSync(); startPeriodicSync();