diff --git a/.DS_Store b/.DS_Store index d6be55e..4e23434 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/app.py b/app.py index 9210d42..1f00b7b 100644 --- a/app.py +++ b/app.py @@ -185,6 +185,14 @@ def enforce_edition_feature_limits(): def about_main_logo(): return send_from_directory(os.path.join(app.root_path, "picture", "logo"), "main_logo.png") + +@app.route("/assets/desktop_add_icon.png") +def desktop_add_icon(): + return send_from_directory( + os.path.join(app.root_path, "picture"), + "desktop_add_icon.png", + ) + # Force UTF-8 for all HTML responses to avoid mojibake. @app.after_request def add_charset(response): @@ -3850,7 +3858,14 @@ def client_test(): t.last_seen, t.date_added FROM client_test_devices t LEFT JOIN cabinets cab ON cab.id = t.cabinet_id - ORDER BY t.date_added DESC, t.id DESC + ORDER BY ( + NOT t.is_manual + AND t.is_online + AND t.last_seen IS NOT NULL + AND t.last_seen >= NOW() - INTERVAL '{CLIENT_TEST_OFFLINE_AFTER_SECONDS} seconds' + ) DESC, + t.date_added DESC, + t.id DESC """ ) rows = cur.fetchall() diff --git a/picture/.DS_Store b/picture/.DS_Store index 4d24234..aea655b 100644 Binary files a/picture/.DS_Store and b/picture/.DS_Store differ diff --git a/picture/desktop_add_icon.png b/picture/desktop_add_icon.png new file mode 100644 index 0000000..da7ab23 Binary files /dev/null and b/picture/desktop_add_icon.png differ diff --git a/templates/client_test.html b/templates/client_test.html index 388d10d..2292fdf 100644 --- a/templates/client_test.html +++ b/templates/client_test.html @@ -408,7 +408,7 @@ @@ -824,6 +824,14 @@ } function compareClientRows(leftRow, rightRow, key) { + const leftIsOnline = (leftRow.dataset.status || '').trim().toLowerCase() === 'online'; + const rightIsOnline = (rightRow.dataset.status || '').trim().toLowerCase() === 'online'; + if (leftIsOnline !== rightIsOnline) return leftIsOnline ? -1 : 1; + + if (!key) { + return Number(leftRow.dataset.initialOrder) - Number(rightRow.dataset.initialOrder); + } + const normalizeValue = (value) => { const cleaned = (value || '').trim(); return cleaned === '-' || cleaned === '—' ? '' : cleaned; @@ -844,7 +852,7 @@ } function applyClientSort(closeActions = true) { - if (!clientTableBody || !activeSortKey) return; + if (!clientTableBody) return; if (closeActions) closeClientActionRows(); const sortedRows = Array.from(rows).sort((leftRow, rightRow) => ( compareClientRows(leftRow, rightRow, activeSortKey) @@ -1129,6 +1137,7 @@ statusElement.classList.toggle('is-online', !isManual && isOnline); statusElement.classList.toggle('is-offline', !isManual && !isOnline); }); + applyClientSort(false); if (activeStatusFilter !== 'all') applyStatusFilter(false); } catch (_error) { // Keep the last displayed state until the server is reachable again. diff --git a/templates/home.html b/templates/home.html index 012bb6a..55c2f3e 100644 --- a/templates/home.html +++ b/templates/home.html @@ -68,17 +68,22 @@ z-index: 1100; display: flex; justify-content: flex-start; - max-height: calc(100vh - 48px); + max-width: calc(100vw - 16px); padding: 0 4px 8px; - overflow-x: hidden; - overflow-y: auto; - scrollbar-width: thin; + overflow: visible; } .home-top-action__stack { - display: flex; - flex-direction: column; - align-items: center; - gap: 10px; + display: grid; + grid-template-rows: repeat(11, max-content); + grid-auto-flow: column; + grid-auto-columns: 140px; + align-items: start; + justify-items: center; + gap: 10px 4px; + direction: rtl; + } + .home-top-action__stack > * { + direction: ltr; } .home-note { position: fixed; @@ -263,10 +268,7 @@ border: 0; } .home-shortcuts-list { - display: flex; - flex-direction: column; - align-items: center; - gap: 10px; + display: contents; } .home-custom-shortcut { cursor: pointer; @@ -280,6 +282,11 @@ max-width: 132px; overflow-wrap: anywhere; } + #homeShortcutAddBtn img { + width: 46px; + height: 46px; + object-fit: contain; + } .home-barcode-btn:active img, .home-barcode-btn.is-active img { filter: brightness(0.7); @@ -771,11 +778,16 @@ .home-computer-context-menu { position: fixed; z-index: 1600; - min-width: 170px; + min-width: 158px; padding: 3px; - border: 1px solid #000; - background: #dcdcdc; - box-shadow: 2px 2px 0 #777; + border: 1px solid; + border-color: #ffffff #101010 #101010 #ffffff; + outline: 1px solid #000; + background: #c0c0c0; + box-shadow: 1px 1px 0 #000; + color: #000; + font-family: 'Chicago Regular', 'MS Sans Serif', Tahoma, sans-serif; + font-size: 0.78rem; } .home-computer-context-menu.hidden { display: none; @@ -786,9 +798,11 @@ border: 0; background: transparent; color: #000; - padding: 5px 22px 5px 8px; + padding: 4px 24px 4px 22px; text-align: left; font: inherit; + line-height: 1.05; + white-space: nowrap; cursor: default; } .home-computer-context-menu__item:hover, @@ -797,6 +811,16 @@ background: #000080; color: #fff; } + .home-computer-context-menu__separator { + height: 2px; + margin: 3px 1px; + border-top: 1px solid #808080; + border-bottom: 1px solid #ffffff; + } + .home-computer-context-menu__access-key { + text-decoration: underline; + text-underline-offset: 1px; + } .home-rustdesk-connecting { position: fixed; right: 16px; @@ -912,7 +936,7 @@ Компьютерные
комплектующие
@@ -987,9 +1011,10 @@