From mboxrd@z Thu Jan  1 00:00:00 1970
Return-Path: <yew-devel-bounces@lists.proxmox.com>
Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9])
	by lore.proxmox.com (Postfix) with ESMTPS id 214B01FF187
	for <inbox@lore.proxmox.com>; Wed,  7 May 2025 16:37:49 +0200 (CEST)
Received: from firstgate.proxmox.com (localhost [127.0.0.1])
	by firstgate.proxmox.com (Proxmox) with ESMTP id D9B0D3DF86;
	Wed,  7 May 2025 16:38:06 +0200 (CEST)
From: Dominik Csapak <d.csapak@proxmox.com>
To: yew-devel@lists.proxmox.com
Date: Wed,  7 May 2025 16:38:00 +0200
Message-Id: <20250507143800.3461963-5-d.csapak@proxmox.com>
X-Mailer: git-send-email 2.39.5
In-Reply-To: <20250507143800.3461963-1-d.csapak@proxmox.com>
References: <20250507143800.3461963-1-d.csapak@proxmox.com>
MIME-Version: 1.0
X-SPAM-LEVEL: Spam detection results:  0
 AWL 0.022 Adjusted score from AWL reputation of From: address
 BAYES_00                 -1.9 Bayes spam probability is 0 to 1%
 DMARC_MISSING             0.1 Missing DMARC policy
 KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment
 SPF_HELO_NONE           0.001 SPF: HELO does not publish an SPF Record
 SPF_PASS               -0.001 SPF: sender matches SPF record
Subject: [yew-devel] [PATCH yew-comp 2/2] tasks: don't add entries we
 already loaded
X-BeenThere: yew-devel@lists.proxmox.com
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: Yew framework devel list at Proxmox <yew-devel.lists.proxmox.com>
List-Unsubscribe: <https://lists.proxmox.com/cgi-bin/mailman/options/yew-devel>, 
 <mailto:yew-devel-request@lists.proxmox.com?subject=unsubscribe>
List-Archive: <http://lists.proxmox.com/pipermail/yew-devel/>
List-Post: <mailto:yew-devel@lists.proxmox.com>
List-Help: <mailto:yew-devel-request@lists.proxmox.com?subject=help>
List-Subscribe: <https://lists.proxmox.com/cgi-bin/mailman/listinfo/yew-devel>, 
 <mailto:yew-devel-request@lists.proxmox.com?subject=subscribe>
Reply-To: Yew framework devel list at Proxmox <yew-devel@lists.proxmox.com>
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Errors-To: yew-devel-bounces@lists.proxmox.com
Sender: "yew-devel" <yew-devel-bounces@lists.proxmox.com>

If there is a new task in between loads due to scrolling, we got
old tasks from the api that we already loaded.

This happens because:
* tasks are sorted descending by their start time
* we initially request up to 500 from start 0
* we save the amount of tasks there are
* on a new load due to scrolling, we set start to the amount
  of tasks knew of -> if there are new tasks now, the start offset
  we sent would be too low

To fix this, skip the amount of tasks in the list that were added in the
meantime, which is the new total minus the new total.

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
ideally we could implement a kind of cursor for our tasks, so that
this scenario would not happen, but I'm not sure if this is feasible

alternatively/additionally we could implement some key constraints
for datastores, or use a Store with a HashMap instead of a vector
(we'd have to do the ordering manually in this case though, which
might be a big overhead for big task lists..)

 src/tasks.rs | 44 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 35 insertions(+), 9 deletions(-)

diff --git a/src/tasks.rs b/src/tasks.rs
index 3c531c1..ac8d1c5 100644
--- a/src/tasks.rs
+++ b/src/tasks.rs
@@ -95,7 +95,8 @@ pub enum ViewDialog {
 pub enum Msg {
     Redraw,
     ToggleFilter,
-    LoadBatch(u64), // start
+    LoadBatch(u64),                               // start
+    LoadFinished(Option<u64>, Vec<TaskListItem>), // total
     UpdateFilter,
     ShowTask,
 }
@@ -109,6 +110,7 @@ pub struct ProxmoxTasks {
     last_filter: serde_json::Value,
     load_timeout: Option<Timeout>,
     columns: Rc<Vec<DataTableHeader<TaskListItem>>>,
+    total: Option<u64>,
 }
 
 impl ProxmoxTasks {
@@ -192,6 +194,7 @@ impl LoadableComponent for ProxmoxTasks {
             start: 0,
             load_timeout: None,
             columns: Self::columns(ctx),
+            total: None,
         }
     }
 
@@ -206,8 +209,6 @@ impl LoadableComponent for ProxmoxTasks {
             None => format!("/nodes/{nodename}/tasks"),
         };
 
-        let store = self.store.clone();
-
         let form_context = self.filter_form_context.read();
         let mut filter = form_context.get_submit_data();
 
@@ -234,13 +235,11 @@ impl LoadableComponent for ProxmoxTasks {
         filter["start"] = start.into();
         filter["limit"] = BATCH_LIMIT.into();
 
+        let link = ctx.link().clone();
         Box::pin(async move {
-            let mut data: Vec<_> = crate::http_get(&path, Some(filter)).await?;
-            if start == 0 {
-                store.write().set_data(data);
-            } else {
-                store.write().append(&mut data);
-            }
+            let response = crate::http_get_full(&path, Some(filter)).await?;
+            let total = response.attribs.get("total").and_then(|v| v.as_u64());
+            link.send_message(Msg::LoadFinished(total, response.data));
             Ok(())
         })
     }
@@ -279,6 +278,33 @@ impl LoadableComponent for ProxmoxTasks {
                 }));
                 false
             }
+            Msg::LoadFinished(total, mut data) => {
+                let old_total = self.total.take();
+                self.total = total;
+                if self.start == 0 {
+                    self.store.write().set_data(data);
+                } else {
+                    // if new elements were added at the front, we need to skip as many from the
+                    // newly gathered list, otherwise we have duplicate items
+                    match (old_total, self.total) {
+                        (Some(old), Some(new)) if new > old => {
+                            let to_skip = (new - old) as usize;
+
+                            if to_skip <= data.len() {
+                                data.drain(..to_skip);
+                            }
+                        }
+                        _ => {}
+                    };
+
+                    if data.is_empty() {
+                        return false;
+                    } else {
+                        self.store.write().append(&mut data);
+                    }
+                }
+                true
+            }
             Msg::ShowTask => {
                 if let Some(on_show_task) = &ctx.props().on_show_task {
                     let selected_item = self
-- 
2.39.5



_______________________________________________
yew-devel mailing list
yew-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/yew-devel