From: Christoph Heiss <c.heiss@proxmox.com>
To: pdm-devel@lists.proxmox.com
Subject: Re: [PATCH datacenter-manager v2] ui: auto-installer: show assistant command line in text area
Date: Wed, 11 Nov 2026 10:54:39 +0100 [thread overview]
Message-ID: <4ab4eaba-6036-4802-bb26-3754b1da4bff@proxmox.com> (raw)
In-Reply-To: <20260605142631.1576216-1-c.heiss@proxmox.com>
Ping, still applies.
On 6/5/26 16:26, Christoph Heiss wrote:
> .. instead of a single-line, password-type input.
>
> Adds a simple component for displaying the command line as a
> `<textarea>` element, hiding the contents by default.
>
> The show/hide icon was converted into a button and moved outside the
> input element itself - as having it inside the textarea is kind of
> awkward.
>
> Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
> ---
> v1: https://lore.proxmox.com/pdm-devel/20260528111123.1225933-1-c.heiss@proxmox.com/
>
> Results in a slightly different UI for the token field vs. command line
> field, but definitely makes sense having a textarea there IMHO.
>
> The idea is based on an idea from the v1's discussion, to have a
> separate component for it. Displaying the command line in a textarea
> (which by design is made for displaying lots of text) came to mind,
> instead of a single-line input element, hiding most of the command line.
>
> To component could be factored out in the future if ever needed, but
> as said in the previous thread, it's bit of a special case.
>
> .../command_line_display_field.rs | 118 ++++++++++++++++++
> ui/src/remotes/auto_installer/mod.rs | 1 +
> .../auto_installer/prepared_answer_form.rs | 55 ++++----
> 3 files changed, 140 insertions(+), 34 deletions(-)
> create mode 100644 ui/src/remotes/auto_installer/command_line_display_field.rs
>
> diff --git a/ui/src/remotes/auto_installer/command_line_display_field.rs b/ui/src/remotes/auto_installer/command_line_display_field.rs
> new file mode 100644
> index 00000000..76c601c7
> --- /dev/null
> +++ b/ui/src/remotes/auto_installer/command_line_display_field.rs
> @@ -0,0 +1,118 @@
> +//! A hidden-by-default [`TextArea`] to display the generated command line for
> +//! `proxmox-auto-install-assistant`.
> +
> +use yew::Properties;
> +
> +use proxmox_yew_comp::utils::copy_text_to_clipboard;
> +use pwt::{
> + css::{self, ColorScheme},
> + prelude::*,
> + widget::{Button, Column, Row, Tooltip, form::TextArea},
> +};
> +use pwt_macros::{builder, widget};
> +
> +#[widget(comp=CommandLineDisplayFieldComponent, @input)]
> +#[derive(Clone, PartialEq, Properties)]
> +#[builder]
> +pub struct CommandLineDisplayField {
> + /// Content to display.
> + #[prop_or_default]
> + #[builder]
> + value: AttrValue,
> +}
> +
> +impl CommandLineDisplayField {
> + pub fn new() -> Self {
> + yew::props!(Self {})
> + }
> +}
> +
> +enum Message {
> + Reveal,
> + Hide,
> +}
> +
> +struct CommandLineDisplayFieldComponent {
> + hidden: bool,
> +}
> +
> +impl Component for CommandLineDisplayFieldComponent {
> + type Properties = CommandLineDisplayField;
> + type Message = Message;
> +
> + fn create(_ctx: &Context<Self>) -> Self {
> + Self { hidden: true }
> + }
> +
> + fn view(&self, ctx: &Context<Self>) -> Html {
> + let props = ctx.props();
> + let hidden = self.hidden;
> +
> + let toggle_hidden_cb = ctx.link().callback(move |_| {
> + if hidden {
> + Self::Message::Reveal
> + } else {
> + Self::Message::Hide
> + }
> + });
> +
> + let (toggle_hidden_icon, toggle_hidden_tip, value) = if hidden {
> + (
> + "fa fa-eye",
> + tr!("Show Command Line"),
> + "\u{2022}".repeat(props.value.len()).into(),
> + )
> + } else {
> + (
> + "fa fa-eye-slash",
> + tr!("Hide Command Line"),
> + props.value.clone(),
> + )
> + };
> +
> + Row::new()
> + .with_std_props(&props.std_props)
> + .class(css::Display::Flex)
> + .class("pwt-fill-grid-row")
> + .gap(2)
> + .with_child(
> + TextArea::new()
> + .attribute("rows", "10")
> + .attribute("resize", "both")
> + .read_only(true)
> + .class("pwt-w-100")
> + .value(value)
> + )
> + .with_child(
> + Column::new().gap(2).with_child(
> + Tooltip::new(
> + Button::new_icon(toggle_hidden_icon)
> + .class(ColorScheme::Primary)
> + .on_activate(toggle_hidden_cb)
> + )
> + .tip(toggle_hidden_tip),
> + )
> + .with_child(
> + Tooltip::new(
> + Button::new_icon("fa fa-clipboard")
> + .class(ColorScheme::Primary)
> + .on_activate({
> + let value = props.value.clone();
> + move |_| copy_text_to_clipboard(&value)
> + }),
> + )
> + .tip(tr!("Copy template command line to clipboard. Replace INPUT.iso with your installation ISO.")),
> + )
> + )
> + .into()
> + }
> +
> + fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
> + match msg {
> + Self::Message::Reveal => self.hidden = false,
> + Self::Message::Hide => self.hidden = true,
> + }
> +
> + true
> + }
> +}
> diff --git a/ui/src/remotes/auto_installer/mod.rs b/ui/src/remotes/auto_installer/mod.rs
> index 99508f4b..1e5fb437 100644
> --- a/ui/src/remotes/auto_installer/mod.rs
> +++ b/ui/src/remotes/auto_installer/mod.rs
> @@ -1,5 +1,6 @@
> //! Implements the UI for the proxmox-auto-installer integration.
>
> +mod command_line_display_field;
> mod installations_panel;
> mod prepared_answer_add_wizard;
> mod prepared_answer_edit_window;
> diff --git a/ui/src/remotes/auto_installer/prepared_answer_form.rs b/ui/src/remotes/auto_installer/prepared_answer_form.rs
> index 960decae..db2701a2 100644
> --- a/ui/src/remotes/auto_installer/prepared_answer_form.rs
> +++ b/ui/src/remotes/auto_installer/prepared_answer_form.rs
> @@ -32,7 +32,7 @@ use pwt::{
> props::FieldStdProps,
> state::Store,
> widget::{
> - Button, Column, Container, Dialog, Fa, FieldLabel, FieldPosition, InputPanel, Row, Tooltip,
> + Button, Container, Dialog, Fa, FieldLabel, FieldPosition, InputPanel, Row, Tooltip,
> form::{
> Checkbox, Combobox, DisplayField, Field, FormContext, InputType, Number, TextArea,
> ValidateFn,
> @@ -41,7 +41,9 @@ use pwt::{
> };
>
> use super::pdm_origin;
> -use crate::remotes::auto_installer::token_selector::TokenSelector;
> +use crate::remotes::auto_installer::{
> + command_line_display_field::CommandLineDisplayField, token_selector::TokenSelector,
> +};
>
> pub fn prepare_form_data(mut value: serde_json::Value) -> Result<serde_json::Value> {
> let obj = value
> @@ -1010,7 +1012,7 @@ pub fn render_show_secret_dialog(
>
> let copy_token_view = Container::new()
> .key("copy-token-view")
> - .class("pwt-form-grid-col4")
> + .class("pwt-form-grid-col4 pwt-w-100")
> .with_child(FieldLabel::new(tr!("Token")))
> .with_child(
> Row::new()
> @@ -1043,45 +1045,27 @@ pub fn render_show_secret_dialog(
> .unwrap_or_else(|| "https://pdm.example.com:8443")
> );
>
> - let mut commandline = format!(
> - "proxmox-auto-install-assistant prepare-iso --fetch-from http --url {answer_url} --answer-auth-token {token}",
> - );
> + let mut commandline = vec![
> + "proxmox-auto-install-assistant prepare-iso".into(),
> + "--fetch-from http".into(),
> + format!("--url {answer_url}"),
> + format!("--answer-auth-token {token}"),
> + ];
>
> if let Some(fingerprint) = fingerprint {
> - commandline = format!("{commandline} --cert-fingerprint {fingerprint}");
> + commandline.push(format!("--cert-fingerprint {fingerprint}"));
> }
>
> - commandline = format!("{commandline} INPUT.iso");
> + commandline.push("INPUT.iso".into());
> + let commandline = commandline.join(" \\\n ");
>
> let copy_commandline_view = Container::new()
> .key("copy-commandline-view")
> - .class("pwt-form-grid-col4")
> + .class("pwt-form-grid-col4 pwt-w-100")
> .with_child(FieldLabel::new(tr!("Command Line")))
> - .with_child(
> - Row::new()
> - .class("pwt-fill-grid-row")
> - .gap(2)
> - .with_child(
> - Field::new()
> - .input_type(InputType::Password)
> - .class(FlexFit)
> - .value(commandline.to_owned())
> - .read_only(true),
> - )
> - .with_child(
> - Tooltip::new(
> - Button::new_icon("fa fa-clipboard")
> - .class(ColorScheme::Primary)
> - .on_activate({
> - let commandline = commandline.to_owned();
> - move |_| copy_text_to_clipboard(&commandline)
> - }),
> - )
> - .tip(tr!("Copy template command line to clipboard. Replace INPUT.iso with your installation ISO.")),
> - ),
> - );
> + .with_child(CommandLineDisplayField::new().value(commandline.clone().into()));
>
> - let mut panel = InputPanel::new().padding(4);
> + let mut panel = InputPanel::new().padding(4).class("pwt-w-100");
>
> if let Some(id) = config_id {
> panel.add_large_field(
> @@ -1095,7 +1079,10 @@ pub fn render_show_secret_dialog(
> panel.add_large_custom_child(copy_token_view);
> panel.add_large_custom_child(copy_commandline_view);
>
> - let dialog = Dialog::new(tr!("New Answer Token")).on_close(on_close).with_child(Column::new().with_child(panel))
> + let dialog = Dialog::new(tr!("New Answer Token"))
> + .width(900)
> + .on_close(on_close)
> + .with_child(Container::new().class(FlexFit).class("pwt-w-100").with_child(panel))
> .with_child(
> Container::new()
> .padding(4)
prev parent reply other threads:[~2026-11-11 9:54 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-05 14:25 [PATCH datacenter-manager v2] ui: auto-installer: show assistant command line in text area Christoph Heiss
2026-11-11 9:54 ` Christoph Heiss [this message]
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=4ab4eaba-6036-4802-bb26-3754b1da4bff@proxmox.com \
--to=c.heiss@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