fix spam re-order
This commit is contained in:
@@ -11,7 +11,7 @@ export function registerRenderer(fn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function loadWithOptions(options = {}) {
|
export async function loadWithOptions(options = {}) {
|
||||||
const { force = false } = options;
|
const { force = false, reorder = false } = options;
|
||||||
if (state.isLoading) {
|
if (state.isLoading) {
|
||||||
state.pendingForce = state.pendingForce || force;
|
state.pendingForce = state.pendingForce || force;
|
||||||
return;
|
return;
|
||||||
@@ -38,7 +38,7 @@ export async function loadWithOptions(options = {}) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
state.lastDigest = digest;
|
state.lastDigest = digest;
|
||||||
render(data);
|
render(data, { reorder });
|
||||||
|
|
||||||
if (!state.thumbnailsRequested) {
|
if (!state.thumbnailsRequested) {
|
||||||
state.thumbnailsRequested = true;
|
state.thumbnailsRequested = true;
|
||||||
|
|||||||
@@ -411,7 +411,7 @@ wireModalClose();
|
|||||||
const debouncedSearch = debounce(() => {
|
const debouncedSearch = debounce(() => {
|
||||||
state.page = 1;
|
state.page = 1;
|
||||||
state.lastDigest = "";
|
state.lastDigest = "";
|
||||||
loadWithOptions({ force: true });
|
loadWithOptions({ force: true, reorder: true });
|
||||||
}, 200);
|
}, 200);
|
||||||
|
|
||||||
searchInput?.addEventListener("input", (e) => {
|
searchInput?.addEventListener("input", (e) => {
|
||||||
@@ -423,7 +423,7 @@ sortSelect?.addEventListener("change", (e) => {
|
|||||||
state.sort = e.target.value;
|
state.sort = e.target.value;
|
||||||
state.page = 1;
|
state.page = 1;
|
||||||
state.lastDigest = "";
|
state.lastDigest = "";
|
||||||
loadWithOptions({ force: true });
|
loadWithOptions({ force: true, reorder: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
filterStatusSelect?.addEventListener("change", (e) => {
|
filterStatusSelect?.addEventListener("change", (e) => {
|
||||||
@@ -436,21 +436,21 @@ filterStatusSelect?.addEventListener("change", (e) => {
|
|||||||
}
|
}
|
||||||
state.page = 1;
|
state.page = 1;
|
||||||
state.lastDigest = "";
|
state.lastDigest = "";
|
||||||
loadWithOptions({ force: true });
|
loadWithOptions({ force: true, reorder: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
filterOsSelect?.addEventListener("change", (e) => {
|
filterOsSelect?.addEventListener("change", (e) => {
|
||||||
state.filterOs = e.target.value;
|
state.filterOs = e.target.value;
|
||||||
state.page = 1;
|
state.page = 1;
|
||||||
state.lastDigest = "";
|
state.lastDigest = "";
|
||||||
loadWithOptions({ force: true });
|
loadWithOptions({ force: true, reorder: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
initCountryPicker((code) => {
|
initCountryPicker((code) => {
|
||||||
state.filterCountry = code;
|
state.filterCountry = code;
|
||||||
state.page = 1;
|
state.page = 1;
|
||||||
state.lastDigest = "";
|
state.lastDigest = "";
|
||||||
loadWithOptions({ force: true });
|
loadWithOptions({ force: true, reorder: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
showOfflineToggle?.addEventListener("change", (e) => {
|
showOfflineToggle?.addEventListener("change", (e) => {
|
||||||
@@ -467,7 +467,7 @@ showOfflineToggle?.addEventListener("change", (e) => {
|
|||||||
}
|
}
|
||||||
state.page = 1;
|
state.page = 1;
|
||||||
state.lastDigest = "";
|
state.lastDigest = "";
|
||||||
loadWithOptions({ force: true });
|
loadWithOptions({ force: true, reorder: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
function updateBulkToolbar() {
|
function updateBulkToolbar() {
|
||||||
@@ -686,14 +686,14 @@ prevBtn?.addEventListener("click", () => {
|
|||||||
if (state.page > 1) {
|
if (state.page > 1) {
|
||||||
state.page -= 1;
|
state.page -= 1;
|
||||||
state.lastDigest = "";
|
state.lastDigest = "";
|
||||||
loadWithOptions({ force: true });
|
loadWithOptions({ force: true, reorder: true });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
nextBtn?.addEventListener("click", () => {
|
nextBtn?.addEventListener("click", () => {
|
||||||
state.page += 1;
|
state.page += 1;
|
||||||
state.lastDigest = "";
|
state.lastDigest = "";
|
||||||
loadWithOptions({ force: true });
|
loadWithOptions({ force: true, reorder: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener("click", (e) => {
|
window.addEventListener("click", (e) => {
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ export function createRenderer({
|
|||||||
const TOUCH_MOVE_CANCEL_PX = 10;
|
const TOUCH_MOVE_CANCEL_PX = 10;
|
||||||
let renderToken = 0;
|
let renderToken = 0;
|
||||||
|
|
||||||
function renderMerge(data) {
|
function renderMerge(data, options = {}) {
|
||||||
|
const { reorder = false } = options;
|
||||||
totalPill.textContent = `${data.online ?? data.total} online / ${data.total} total`;
|
totalPill.textContent = `${data.online ?? data.total} online / ${data.total} total`;
|
||||||
const totalPages = Math.max(1, Math.ceil(data.total / data.pageSize));
|
const totalPages = Math.max(1, Math.ceil(data.total / data.pageSize));
|
||||||
pageLabel.textContent = `Page ${data.page} of ${totalPages}`;
|
pageLabel.textContent = `Page ${data.page} of ${totalPages}`;
|
||||||
@@ -47,8 +48,8 @@ export function createRenderer({
|
|||||||
typeof window !== "undefined" &&
|
typeof window !== "undefined" &&
|
||||||
window.matchMedia &&
|
window.matchMedia &&
|
||||||
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||||
const animateLimit = Math.min(items.length, MAX_ANIMATED_CARDS);
|
|
||||||
const allowAnimation = !prefersReducedMotion && items.length <= 1000;
|
const hadCards = grid.querySelectorAll("article[data-id]").length > 0;
|
||||||
|
|
||||||
items.forEach((client) => {
|
items.forEach((client) => {
|
||||||
seen.add(client.id);
|
seen.add(client.id);
|
||||||
@@ -64,11 +65,20 @@ export function createRenderer({
|
|||||||
.filter((el) => !seen.has(el.dataset.id))
|
.filter((el) => !seen.has(el.dataset.id))
|
||||||
.forEach((el) => el.remove());
|
.forEach((el) => el.remove());
|
||||||
|
|
||||||
|
if (reorder) {
|
||||||
|
items.forEach((client) => {
|
||||||
|
const card = grid.querySelector(`article[data-id="${client.id}"]`);
|
||||||
|
if (card) grid.appendChild(card);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (newClients.length === 0) {
|
if (newClients.length === 0) {
|
||||||
moveOfflineToBottom();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const allowAnimation = !hadCards && !prefersReducedMotion && items.length <= 1000;
|
||||||
|
const animateLimit = Math.min(newClients.length, MAX_ANIMATED_CARDS);
|
||||||
|
|
||||||
let idx = 0;
|
let idx = 0;
|
||||||
const insertBatch = () => {
|
const insertBatch = () => {
|
||||||
if (renderId !== renderToken) return;
|
if (renderId !== renderToken) return;
|
||||||
@@ -91,35 +101,11 @@ export function createRenderer({
|
|||||||
requestAnimationFrame(insertBatch);
|
requestAnimationFrame(insertBatch);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
moveOfflineToBottom();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
insertBatch();
|
insertBatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveOfflineToBottom() {
|
|
||||||
const cards = Array.from(grid.querySelectorAll("article[data-id]"));
|
|
||||||
if (cards.length === 0) return;
|
|
||||||
|
|
||||||
const online = [];
|
|
||||||
const offline = [];
|
|
||||||
cards.forEach((card) => {
|
|
||||||
if (card.dataset.online === "true") {
|
|
||||||
online.push(card);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
offline.push(card);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (offline.length === 0) return;
|
|
||||||
|
|
||||||
const fragment = document.createDocumentFragment();
|
|
||||||
online.forEach((card) => fragment.appendChild(card));
|
|
||||||
offline.forEach((card) => fragment.appendChild(card));
|
|
||||||
grid.appendChild(fragment);
|
|
||||||
}
|
|
||||||
|
|
||||||
function prevBtnState(currentPage, totalPages) {
|
function prevBtnState(currentPage, totalPages) {
|
||||||
const prevBtn = document.getElementById("prev");
|
const prevBtn = document.getElementById("prev");
|
||||||
const nextBtn = document.getElementById("next");
|
const nextBtn = document.getElementById("next");
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ export const state = {
|
|||||||
page: 1,
|
page: 1,
|
||||||
pageSize: 12,
|
pageSize: 12,
|
||||||
searchTerm: "",
|
searchTerm: "",
|
||||||
sort: "last_seen_desc",
|
sort: "stable",
|
||||||
filterStatus: "all",
|
filterStatus: "all",
|
||||||
filterOs: "all",
|
filterOs: "all",
|
||||||
filterCountry: "all",
|
filterCountry: "all",
|
||||||
|
|||||||
@@ -92,6 +92,7 @@
|
|||||||
id="sort"
|
id="sort"
|
||||||
class="bg-slate-900/70 border border-slate-800 rounded-lg px-3 py-2 text-slate-100"
|
class="bg-slate-900/70 border border-slate-800 rounded-lg px-3 py-2 text-slate-100"
|
||||||
>
|
>
|
||||||
|
<option value="stable">Default</option>
|
||||||
<option value="last_seen_desc">Newest</option>
|
<option value="last_seen_desc">Newest</option>
|
||||||
<option value="host_asc">Host A→Z</option>
|
<option value="host_asc">Host A→Z</option>
|
||||||
<option value="ping_asc">Ping ↑</option>
|
<option value="ping_asc">Ping ↑</option>
|
||||||
|
|||||||
@@ -348,6 +348,8 @@ export function listClients(filters: ListFilters): ListResult {
|
|||||||
const orderBy = (() => {
|
const orderBy = (() => {
|
||||||
const bookmark = "bookmarked DESC";
|
const bookmark = "bookmarked DESC";
|
||||||
switch (sort) {
|
switch (sort) {
|
||||||
|
case "stable":
|
||||||
|
return `ORDER BY ${bookmark}, online DESC, id ASC`;
|
||||||
case "ping_asc":
|
case "ping_asc":
|
||||||
return `ORDER BY ${bookmark}, ping_ms IS NULL, ping_ms ASC, id ASC`;
|
return `ORDER BY ${bookmark}, ping_ms IS NULL, ping_ms ASC, id ASC`;
|
||||||
case "ping_desc":
|
case "ping_desc":
|
||||||
|
|||||||
Reference in New Issue
Block a user