From: "Christoph Heiss" <c.heiss@proxmox.com>
To: "Dominik Csapak" <d.csapak@proxmox.com>
Cc: pdm-devel@lists.proxmox.com
Subject: Re: [PATCH yew-widget-toolkit v3 13/38] widget: kvlist: add widget for user-modifiable data tables
Date: Thu, 16 Apr 2026 16:18:54 +0200 [thread overview]
Message-ID: <DHUN7QLOFV9Q.2QZ4G6RHY5VBL@proxmox.com> (raw)
In-Reply-To: <3d4e0b0e-cd51-4041-87f9-9782be422357@proxmox.com>
Thanks for the review!
On Thu Apr 16, 2026 at 2:23 PM CEST, Dominik Csapak wrote:
> high level comment:
>
> i think this would better fit in the yew-comp crate, since it's not a
> general ui pattern.
Fine by me, I can move it. TBH I wasn't completely sure to begin with,
where exactly the line between the yew-widget-toolkit and yew-comp
crates is and put this.
>
> Not a big deal for me though.
>
> other comments inline
>
> On 4/3/26 6:55 PM, Christoph Heiss wrote:
[..]
>> +#[widget(pwt = crate, comp = ManagedFieldMaster<KeyValueListField<T>>, @input)]
>> +#[derive(Clone, PartialEq, Properties)]
>> +#[builder]
>> +/// A [`DataTable`]-based grid to hold a list of user-enterable key-value pairs.
>> +///
>> +/// Displays a [`DataTable`] with three columns; key, value and a delete button, with an add button
>> +/// below to create new rows.
>> +/// Both key and value are modifiable by the user.
>> +pub struct KeyValueList<
>> + T: 'static
>> + + Clone
>> + + Debug
>> + + Default
>> + + DeserializeOwned
>> + + Display
>> + + FromStr
>> + + PartialEq
>> + + Serialize,
>
> does the type really need all of these traits?
Yes (unfortunately), due to implementing `ManagedField` below.
>
> usually traits are only defined in the implementation blocks where
> this is needed, not as fixed types on the struct itself
>
> also e.g it's usually expected that Display and FromStr should be
> compatible, so that to_string().parse().unwrap() should work.
>
> so having them need to serialize/deserialize could be dropped here
> and parse/to_string is used?
>
> Or we just use 'Value' instead of making it generic?
That certainly would make a lot of things easier. If it may be even
preferred for yew stuff, I'll go this route.
>
>> +> {
>> + #[builder]
>> + #[prop_or_default]
>> + /// Initial value pairs to display.
>> + pub value: Vec<(String, T)>,
>> +
>> + #[builder]
>> + #[prop_or(tr!("Name"))]
>> + /// Label for the key column, defaults to "Name".
>> + pub key_label: String,
>> +
>> + #[builder]
>> + #[prop_or_default]
>> + /// Placeholder to display in the key columns fields, default is no placeholder.
>> + pub key_placeholder: String,
>> +
>> + #[builder]
>> + #[prop_or(tr!("Value"))]
>> + /// Label for the value column.
>> + pub value_label: String,
>> +
>> + #[builder]
>> + #[prop_or_default]
>> + /// Placeholder to display in the value columns fields, default is no placeholder.
>> + pub value_placeholder: String,
>
> I know we are a bit careless with it in the codebase, but it's generally
> recommended to use 'AttrValue' instead of String as properties.
>
> Reason is that AttrValue can be cheaply cloned if the value is
> just a &'static str
Thanks for the hint, I'll change it!
>
>> +
>> + #[builder]
>> + #[prop_or_default]
>> + /// Input type to set on the value columns fields, default is text.
>> + pub value_input_type: InputType,
>
> here i noticed that you use a fixed 'Field' for the value column.
>
> Maybe it would better to just use a text field and optionally let the
> user set a fieldrenderer callback?
>
> imho just setting the type is too restricting, e.g. for numbers i can't
> set the minimum/maximum/step size etc.
> (and you use it only once AFAICS)
Didn't consider that, definitely makes sense!
>
> also what is the relationship between this field and the actual value type?
>
> if i set "number" here, but T is e.g. String this does not make much
> sense?
Yeah, that was left to the callee. But that will away with using `Value`
and a custom field renderer callback anyway.
>
>> +
>> + #[builder_cb(IntoSubmitValidateFn, into_submit_validate_fn, Vec<(String, T)>)]
>> + #[prop_or_default]
>> + /// Callback to run on submit on the data in the table.
>> + pub submit_validate: Option<SubmitValidateFn<Vec<(String, T)>>>,
>> +}
>> +
>> +impl<T> KeyValueList<T>
>> +where
>> + T: 'static
>> + + Clone
>> + + Debug
>> + + Default
>> + + DeserializeOwned
>> + + Display
>> + + FromStr
>> + + PartialEq
>> + + Serialize,
>> +{
>> + pub fn new() -> Self {
>> + yew::props!(Self {})
>> + }
>> +}
>> +
>> +#[derive(Clone, Debug, PartialEq)]
>> +struct Entry<T: Clone + Debug + PartialEq> {
>> + index: usize,
>
> you use this as key, but does it really make sense to have multiple
> entries with the same 'key' field?
There certainly are usecases where this might be useful. E.g. the
auto-installer integration I'm working on, this component is used to be
able to define filters for udev properties of devices, where (depending
on the selected mode) either all must match or any.
For the latter, having e.g.
ID_SERIAL=S1ATN*
ID_SERIAL=SSDSC2*
can be useful, to match devices which match either serial number.
(Also, realised I actually broke this with v2 -> v3 of this series in
the PDM API .. so good time to revisit that as well, I guess.)
>
> if we could restrict ourselves to only having unique 'key' fields
> this field could be dropped, and the adding/removing logic could
> get simpler.
>
> alternatively, if we don't need the key at all (only as a marker
> for removal/adding), we could keep this, but only ever increase
> the count, so we don't have to change all indices when an entry
> gets removed
> (it's what extjs does too when it autogenerates keys,
> it never reuses one, always increases the counter)
I see, could make things simpler, I'll rework that too.
>
>> + key: String,
>> + value: T,
>> +}
>> +
[..]
>> +
>> + fn view(&self, ctx: &ManagedFieldContext<Self>) -> Html {
>> + let table = DataTable::new(Self::columns(ctx), self.store.clone())
>> + .border(true)
>> + .class(FlexFit);
>> +
>> + let button_row = Row::new()
>> + .with_child(
>> + Button::new(tr!("Add"))
>> + .class(ColorScheme::Primary)
>> + .icon_class("fa fa-plus-circle")
>> + .on_activate({
>> + let store = self.store.clone();
>> + move |_| {
>> + let mut data = store.write();
>> + let index = data.len();
>> +
>> + data.push(Entry {
>> + index,
>> + key: String::new(),
>> + value: T::default(),
>> + })
>> + }
>> + }),
>
> this button is not properly disabled when the whole field is disabled so
> it's always active,
>
> also it would be better if this was also an update message, like the
> removal, then the adding/removing/updating code is all together
>
Good catch, I'll fix both for v4.
next prev parent reply other threads:[~2026-04-16 14:19 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-03 16:53 [PATCH proxmox/yew-pwt/datacenter-manager/installer v3 00/38] add auto-installer integration Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 01/38] api-macro: allow $ in identifier name Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 02/38] schema: oneOf: allow single string variant Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 03/38] schema: implement UpdaterType for HashMap and BTreeMap Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 04/38] network-types: move `Fqdn` type from proxmox-installer-common Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 05/38] network-types: implement api type for Fqdn Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 06/38] network-types: add api wrapper type for std::net::IpAddr Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 07/38] network-types: cidr: implement generic `IpAddr::new` constructor Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 08/38] network-types: fqdn: implement standard library Error for Fqdn Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 09/38] node-status: make KernelVersionInformation Clone + PartialEq Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 10/38] installer-types: add common types used by the installer Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 11/38] installer-types: add types used by the auto-installer Christoph Heiss
2026-04-03 16:53 ` [PATCH proxmox v3 12/38] installer-types: implement api type for all externally-used types Christoph Heiss
2026-04-03 16:53 ` [PATCH yew-widget-toolkit v3 13/38] widget: kvlist: add widget for user-modifiable data tables Christoph Heiss
2026-04-16 12:23 ` Dominik Csapak
2026-04-16 14:18 ` Christoph Heiss [this message]
2026-04-03 16:53 ` [PATCH datacenter-manager v3 14/38] api-types, cli: use ReturnType::new() instead of constructing it manually Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 15/38] api-types: add api types for auto-installer integration Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 16/38] config: add auto-installer configuration module Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 17/38] acl: wire up new /system/auto-installation acl path Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 18/38] server: api: add auto-installer integration module Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 19/38] server: api: auto-installer: add access token management endpoints Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 20/38] client: add bindings for auto-installer endpoints Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 21/38] ui: auto-installer: add installations overview panel Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 22/38] ui: auto-installer: add prepared answer configuration panel Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 23/38] ui: auto-installer: add access token " Christoph Heiss
2026-04-03 16:53 ` [PATCH datacenter-manager v3 24/38] docs: add documentation for auto-installer integration Christoph Heiss
2026-04-03 16:53 ` [PATCH installer v3 25/38] install: iso env: use JSON boolean literals for product config Christoph Heiss
2026-04-03 16:53 ` [PATCH installer v3 26/38] common: http: allow passing custom headers to post() Christoph Heiss
2026-04-14 12:13 ` Lukas Wagner
2026-04-15 8:53 ` Christoph Heiss
2026-04-03 16:53 ` [PATCH installer v3 27/38] common: options: move regex construction out of loop Christoph Heiss
2026-04-03 16:54 ` [PATCH installer v3 28/38] assistant: support adding an authorization token for HTTP-based answers Christoph Heiss
2026-04-14 12:13 ` Lukas Wagner
2026-04-03 16:54 ` [PATCH installer v3 29/38] tree-wide: used moved `Fqdn` type to proxmox-network-types Christoph Heiss
2026-04-03 16:54 ` [PATCH installer v3 30/38] tree-wide: use `Cidr` type from proxmox-network-types Christoph Heiss
2026-04-03 16:54 ` [PATCH installer v3 31/38] tree-wide: switch to filesystem types from proxmox-installer-types Christoph Heiss
2026-04-03 16:54 ` [PATCH installer v3 32/38] post-hook: switch to types in proxmox-installer-types Christoph Heiss
2026-04-03 16:54 ` [PATCH installer v3 33/38] auto: sysinfo: switch to types from proxmox-installer-types Christoph Heiss
2026-04-03 16:54 ` [PATCH installer v3 34/38] fetch-answer: " Christoph Heiss
2026-04-03 16:54 ` [PATCH installer v3 35/38] fetch-answer: http: prefer json over toml for answer format Christoph Heiss
2026-04-14 12:13 ` Lukas Wagner
2026-04-03 16:54 ` [PATCH installer v3 36/38] fetch-answer: send auto-installer HTTP authorization token if set Christoph Heiss
2026-04-14 12:13 ` Lukas Wagner
2026-04-14 12:14 ` Lukas Wagner
2026-04-03 16:54 ` [PATCH installer v3 37/38] tree-wide: switch out `Answer` -> `AutoInstallerConfig` types Christoph Heiss
2026-04-03 16:54 ` [PATCH installer v3 38/38] auto: drop now-dead answer file definitions Christoph Heiss
2026-04-14 12:16 ` [PATCH proxmox/yew-pwt/datacenter-manager/installer v3 00/38] add auto-installer integration Lukas Wagner
2026-04-14 13:58 ` Lukas Wagner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=DHUN7QLOFV9Q.2QZ4G6RHY5VBL@proxmox.com \
--to=c.heiss@proxmox.com \
--cc=d.csapak@proxmox.com \
--cc=pdm-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox