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