From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id C07CF1FF141 for ; Mon, 30 Mar 2026 14:52:58 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 0325C1FEDB; Mon, 30 Mar 2026 14:53:25 +0200 (CEST) From: Dominik Csapak To: yew-devel@lists.proxmox.com Subject: [RFC PATCH yew-comp 3/3] log-view: improve display of lines with '\r' Date: Mon, 30 Mar 2026 14:53:08 +0200 Message-ID: <20260330125320.507302-4-d.csapak@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260330125320.507302-1-d.csapak@proxmox.com> References: <20260330125320.507302-1-d.csapak@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL -1.458 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 RCVD_IN_VALIDITY_CERTIFIED_BLOCKED 1 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_RPBL_BLOCKED 1 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. RCVD_IN_VALIDITY_SAFE_BLOCKED 1 ADMINISTRATOR NOTICE: The query to Validity was blocked. See https://knowledge.validity.com/hc/en-us/articles/20961730681243 for more information. SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: SVCXK3UOBNYLY53LPYVK53RGOTC4MLUZ X-Message-ID-Hash: SVCXK3UOBNYLY53LPYVK53RGOTC4MLUZ X-MailFrom: d.csapak@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Yew framework devel list at Proxmox List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Some tools, like 'dd', will output '\r' as line delimiter, so it overwrites the last line in the cli output. Since the browser typically ignores '\r' in the DOM, this kind of output leads to very long and unreadable lines. In ExtJS, the problem is circumvented somewhat: it uses '.innerHTML' which leads to the browser parsing and normalizing line endings. This "works", in the sense that the lines will displayed separately, but interferes with the paging algorithm that depends on the backend line count (which counts "\n" only currently). We can improve this in the frontend only, by only displaying the 'last line' (everything after the last '\r') by default, and adding a hint icon that shows the full output in a tooltip. This fixes the issue with readability, does not interfere with the paging algorithm, and sill provides the full output (on demand). Signed-off-by: Dominik Csapak --- this is a pattern we don't have yet, showing inline icons in task log I did not want to do the same thing extjs does, since it can break the virtual scrolling. the long-term fix is to fix the command invokations to replace \r to \n but this does not fix already existing task logs and older PVE/PBS servers, so having a workaround/solution in the gui is still useful IMHO. src/log_view.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/log_view.rs b/src/log_view.rs index fdfce4c..90000d4 100644 --- a/src/log_view.rs +++ b/src/log_view.rs @@ -9,13 +9,14 @@ use serde_json::json; use yew::html::{IntoEventCallback, IntoPropValue}; use yew::virtual_dom::{Key, VComp, VNode}; +use pwt::css; use pwt::dom::DomSizeObserver; use pwt::prelude::*; use pwt::props::{ AsClassesMut, AsCssStylesMut, ContainerBuilder, CssMarginBuilder, CssPaddingBuilder, CssStyles, WidgetBuilder, WidgetStyleBuilder, }; -use pwt::widget::Container; +use pwt::widget::{Container, Fa, Tooltip}; use pwt::AsyncPool; use pwt_macros::builder; @@ -478,7 +479,27 @@ impl Component for PwtLogView { let page_ref = page_ref.take().unwrap_or_default(); for item in page.lines.iter() { - tag.add_child(format!("{}\n", item.t)); + if let Some(idx) = item.t.rfind('\r') { + tag.add_child(&item.t[idx + 1..]); + tag.add_child( + Tooltip::new( + Fa::new("info-circle").class(css::FontColor::Warning), + ) + .rich_tip( + Container::new() + .class(css::WhiteSpace::Pre) + .with_child(tr!("Full Output:")) + .with_child( + item.t.replace("\r\n", "\n").replace("\r", "\n"), + ), + ) + .padding_start(1) + .class(css::Display::Inline), + ); + } else { + tag.add_child(&item.t); + } + tag.add_child("\n"); } let html: Html = tag.into_html_with_ref(page_ref); -- 2.47.3