Online_fix2
parent
0acdb5f1b8
commit
73cb28284d
10
app.py
10
app.py
|
|
@ -119,8 +119,12 @@ async def root():
|
|||
class ConnectionManager:
|
||||
def __init__(self):
|
||||
self.active_connections: list[WebSocket] = []
|
||||
self.max_connections = 100 # Ограничение числа подключений
|
||||
|
||||
async def connect(self, websocket: WebSocket):
|
||||
if len(self.active_connections) >= self.max_connections:
|
||||
await websocket.close(code=1008, reason="Too many connections")
|
||||
return
|
||||
await websocket.accept()
|
||||
self.active_connections.append(websocket)
|
||||
|
||||
|
|
@ -128,7 +132,7 @@ class ConnectionManager:
|
|||
self.active_connections.remove(websocket)
|
||||
|
||||
async def broadcast(self, message: str):
|
||||
for connection in self.active_connections:
|
||||
for connection in self.active_connections[:]: # Копируем список для безопасного удаления
|
||||
await connection.send_text(message)
|
||||
|
||||
manager = ConnectionManager()
|
||||
|
|
@ -359,7 +363,7 @@ async def upload_image(install_id: int = Form(...), file: UploadFile = File(...)
|
|||
# CORS для API
|
||||
api_app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["http://10.0.0.10:8001", "http://localhost:8001"],
|
||||
allow_origins=["https://rd.it-depot.ru"], # Обновлено для HTTPS
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
|
|
@ -368,7 +372,7 @@ api_app.add_middleware(
|
|||
# CORS для веб-интерфейса
|
||||
web_app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["http://10.0.0.10:8001", "http://localhost:8001"],
|
||||
allow_origins=["https://rd.it-depot.ru"], # Обновлено для HTTPS
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
|
|
|
|||
|
|
@ -8,10 +8,252 @@
|
|||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.12/themes/default/style.min.css">
|
||||
<style>
|
||||
/* Существующие стили остаются без изменений */
|
||||
.status-online { background-color: green; width: 10px; height: 10px; display: inline-block; border-radius: 50%; margin-left: 5px; }
|
||||
.status-offline { background-color: red; width: 10px; height: 10px; display: inline-block; border-radius: 50%; margin-left: 5px; }
|
||||
/* Остальные стили остаются без изменений */
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
height: 100vh;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
body.dark-theme {
|
||||
background-color: #222;
|
||||
color: #fff;
|
||||
}
|
||||
#tree-container, #installs-container, #notes-panel {
|
||||
overflow: auto;
|
||||
}
|
||||
#tree-container {
|
||||
width: 250px;
|
||||
min-width: 200px;
|
||||
border-right: 1px solid #ccc;
|
||||
padding: 10px;
|
||||
background-color: #fff;
|
||||
}
|
||||
#tree-container.dark-theme {
|
||||
border-right-color: #444;
|
||||
background-color: #333;
|
||||
}
|
||||
#installs-container {
|
||||
flex-grow: 1;
|
||||
padding: 10px;
|
||||
background-color: #fff;
|
||||
}
|
||||
#installs-container.dark-theme {
|
||||
background-color: #333;
|
||||
}
|
||||
#notes-panel {
|
||||
width: 300px;
|
||||
min-width: 200px;
|
||||
border-left: 1px solid #ccc;
|
||||
padding: 10px;
|
||||
background-color: #fff;
|
||||
}
|
||||
#notes-panel.dark-theme {
|
||||
border-left-color: #444;
|
||||
background-color: #333;
|
||||
}
|
||||
#splitter {
|
||||
width: 5px;
|
||||
background-color: #ccc;
|
||||
cursor: col-resize;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
#splitter.dark-theme {
|
||||
background-color: #444;
|
||||
}
|
||||
.header-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.header-logo img {
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.theme-toggle, #add-record-button {
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.theme-toggle.dark-theme, #add-record-button.dark-theme {
|
||||
background-color: #555;
|
||||
color: #fff;
|
||||
border: 1px solid #777;
|
||||
}
|
||||
.export-import-container {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#search-container {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#search-container.dark-theme input, #search-container.dark-theme select {
|
||||
background-color: #444;
|
||||
color: #fff;
|
||||
border: 1px solid #666;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-weight: bold;
|
||||
padding: 5px;
|
||||
background-color: #e0e0e0;
|
||||
cursor: pointer;
|
||||
}
|
||||
.header.dark-theme {
|
||||
background-color: #444;
|
||||
}
|
||||
.header div {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.sort-arrow {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.install-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 5px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
}
|
||||
.install-item.dark-theme {
|
||||
border-bottom-color: #555;
|
||||
background-color: #444;
|
||||
}
|
||||
.install-item:hover {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
.install-item.dark-theme:hover {
|
||||
background-color: #555;
|
||||
}
|
||||
.install-item.selected {
|
||||
background-color: #d0d0d0;
|
||||
}
|
||||
.install-item.dark-theme.selected {
|
||||
background-color: #666;
|
||||
}
|
||||
.computer-name, .connection-id, .install-time, .actions {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.protocol-icon {
|
||||
vertical-align: middle;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.connection-link {
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.connection-link.dark-theme {
|
||||
color: #66b0ff;
|
||||
}
|
||||
.action-buttons button {
|
||||
margin: 0 2px;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
.action-buttons.dark-theme button {
|
||||
background-color: #555;
|
||||
color: #fff;
|
||||
border: 1px solid #777;
|
||||
}
|
||||
#notes-content {
|
||||
padding: 10px;
|
||||
min-height: 200px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
#notes-content.dark-theme {
|
||||
border-color: #444;
|
||||
background-color: #444;
|
||||
}
|
||||
#modal-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1000;
|
||||
}
|
||||
#add-modal, #note-modal {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
z-index: 1001;
|
||||
width: 400px;
|
||||
}
|
||||
#add-modal.dark-theme, #note-modal.dark-theme {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
}
|
||||
#add-modal input, #add-modal select, #add-modal textarea,
|
||||
#note-modal textarea {
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
padding: 5px;
|
||||
}
|
||||
#add-modal.dark-theme input, #add-modal.dark-theme select, #add-modal.dark-theme textarea,
|
||||
#note-modal.dark-theme textarea {
|
||||
background-color: #444;
|
||||
color: #fff;
|
||||
border: 1px solid #666;
|
||||
}
|
||||
.markdown-buttons, .image-upload {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.time-hint {
|
||||
font-size: 0.8em;
|
||||
color: #666;
|
||||
}
|
||||
.time-hint.dark-theme {
|
||||
color: #bbb;
|
||||
}
|
||||
.status-online {
|
||||
background-color: green;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
}
|
||||
.status-offline {
|
||||
background-color: red;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
}
|
||||
.highlight {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
.highlight.dark-theme {
|
||||
background-color: #555;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -157,7 +399,7 @@
|
|||
|
||||
const containerRect = document.body.getBoundingClientRect();
|
||||
let newWidth = e.clientX - containerRect.left;
|
||||
const minWidth = parseInt(getComputedStyle(treeContainer).minWidth, 10);
|
||||
const minWidth = 200;
|
||||
const maxWidth = containerRect.width * 0.5;
|
||||
|
||||
if (newWidth < minWidth) newWidth = minWidth;
|
||||
|
|
@ -194,7 +436,6 @@
|
|||
$(items[currentIndex])[0].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
});
|
||||
|
||||
// Подключение к WebSocket
|
||||
connectWebSocket();
|
||||
});
|
||||
|
||||
|
|
@ -360,7 +601,8 @@
|
|||
if (ws) {
|
||||
ws.close();
|
||||
}
|
||||
ws = new WebSocket(`ws://${window.location.host}/ws`);
|
||||
// Используем wss для соответствия HTTPS
|
||||
ws = new WebSocket(`wss://${window.location.host}/ws`);
|
||||
ws.onmessage = function(event) {
|
||||
allInstalls = JSON.parse(event.data);
|
||||
displayInstalls(allInstalls.filter(i => !selectedFolderId || i.folder_id == selectedFolderId));
|
||||
|
|
@ -438,7 +680,7 @@
|
|||
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="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">Заметка</button></span></div>
|
||||
</div>
|
||||
|
|
@ -865,7 +1107,7 @@
|
|||
function formatItalic() {
|
||||
const textarea = $('#note-textarea');
|
||||
const start = textarea[0].selectionStart;
|
||||
const end = textarea[0].selectionEnd;
|
||||
end = textarea[0].selectionEnd;
|
||||
const text = textarea.val();
|
||||
const selected = text.substring(start, end);
|
||||
const newText = `*${selected}*`;
|
||||
|
|
|
|||
Loading…
Reference in New Issue