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 @@