From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) by lore.proxmox.com (Postfix) with ESMTPS id 9CFAF1FF136 for ; Mon, 04 May 2026 10:00:35 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id BC9A91559B; Mon, 4 May 2026 10:00:34 +0200 (CEST) Mime-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=UTF-8 Date: Mon, 04 May 2026 10:00:18 +0200 Message-Id: To: "Dominik Csapak" , Subject: Re: [PATCH datacenter-manager] views: catch unknown widget types From: "Lukas Wagner" X-Mailer: aerc 0.21.0-0-g5549850facc2-dirty References: <20260427111402.2322116-1-d.csapak@proxmox.com> In-Reply-To: <20260427111402.2322116-1-d.csapak@proxmox.com> X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1777881514279 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.054 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 Message-ID-Hash: P4YVAEQAQ7UPYT7CYT3IHAPPJVUQYLZ6 X-Message-ID-Hash: P4YVAEQAQ7UPYT7CYT3IHAPPJVUQYLZ6 X-MailFrom: l.wagner@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: Proxmox Datacenter Manager development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: On Mon Apr 27, 2026 at 1:13 PM CEST, Dominik Csapak wrote: > If there is a mismatch between backend and frontend, (e.g. after an > update or during development) deserialize unknown widget types in a way > that we can still show the remaining widgets. > > Use serde's untagged + flatten feature so we can save all extra > parameters and send it back to the backend. > > In the api, we reject all view updates that contain unknown widgets, > since the frontend should never send any types the backend does not > know. > > Signed-off-by: Dominik Csapak > --- > lib/pdm-api-types/Cargo.toml | 1 + > lib/pdm-api-types/src/views.rs | 30 +++++++++++++++++++++++++++++- > server/src/api/config/views.rs | 20 +++++++++++++++----- > ui/src/dashboard/view.rs | 25 ++++++++++++++++++++++++- > 4 files changed, 69 insertions(+), 7 deletions(-) > > diff --git a/lib/pdm-api-types/Cargo.toml b/lib/pdm-api-types/Cargo.toml > index 7aa7b64e..0c84d301 100644 > --- a/lib/pdm-api-types/Cargo.toml > +++ b/lib/pdm-api-types/Cargo.toml > @@ -12,6 +12,7 @@ http.workspace =3D true > regex.workspace =3D true > serde.workspace =3D true > serde_plain.workspace =3D true > +serde_json.workspace =3D true > =20 > proxmox-acme-api.workspace =3D true > proxmox-access-control =3D { workspace =3D true, features =3D ["acl"] } > diff --git a/lib/pdm-api-types/src/views.rs b/lib/pdm-api-types/src/views= .rs > index c1885828..89281bb3 100644 > --- a/lib/pdm-api-types/src/views.rs > +++ b/lib/pdm-api-types/src/views.rs > @@ -1,4 +1,7 @@ > -use std::{fmt::Debug, fmt::Display, str::FromStr, sync::OnceLock}; > +use std::collections::HashMap; > +use std::fmt::{Debug, Display}; > +use std::str::FromStr; > +use std::sync::OnceLock; > =20 > use anyhow::{bail, Error}; > use const_format::concatcp; > @@ -255,6 +258,24 @@ pub enum ViewLayout { > }, > } > =20 > +impl ViewLayout { > + /// Tests if this layout has unknown widget types > + pub fn has_unknown_widgets(&self) -> bool { > + match self { > + ViewLayout::Rows { rows } =3D> { > + for row in rows { > + for widget in row { > + if let WidgetType::UnknownWidget { .. } =3D widg= et.r#type { > + return true; > + } > + } > + } > + } > + } > + false > + } > +} > + > #[derive(Serialize, Deserialize, PartialEq, Clone)] > #[serde(rename_all =3D "kebab-case")] > pub struct RowWidget { > @@ -312,6 +333,13 @@ pub enum WidgetType { > #[serde(skip_serializing_if =3D "Option::is_none")] > remote_type: Option, > }, > + #[serde(untagged)] > + #[serde(rename_all =3D "kebab-case")] > + UnknownWidget { > + widget_type: String, > + #[serde(flatten)] > + extra: HashMap, > + }, This is `pub` and should therefore have some doc comments. Seems valuable to me to express the 'catch-all' behavior there. > } > =20 Looks good to me otherwise. Tested it by applying this patch and then modifying views.cfg manually, changing the widget-type of one widget to something unknown. Reviewed-by: Lukas Wagner Tested-by: Lukas Wagner