Copilot commented on code in PR #8438:
URL: https://github.com/apache/texera/pull/8438#discussion_r3945126124


##########
frontend/src/app/workspace/component/workflow-form/workflow-form.component.ts:
##########
@@ -367,9 +364,104 @@ export class WorkflowFormComponent implements OnInit, 
OnDestroy {
       field.props = { ...(field.props ?? {}), disabled: true };
     }
 
+    this.applyFieldOverrides(field, binding);
     return { resolved, fields: [field], form, model };
   }
 
+  /**
+   * The template for one row of a repeated section. formly's `fieldArray` may 
be the template
+   * object or a function that builds one per row; resolve both so an array 
property's sub-fields
+   * are reachable (treating the function case as a leaf hid them). @internal, 
exported for tests.
+   */
+  public static arrayItemOf(node: FormlyFieldConfig): FormlyFieldConfig | 
undefined {
+    const fa = node.fieldArray;
+    if (!fa) {
+      return undefined;
+    }
+    if (typeof fa !== "function") {
+      return fa;
+    }
+    try {
+      return fa(node);
+    } catch {
+      // A builder that needs more context than we can give it tells us 
nothing about the row's
+      // shape; better to list no sub-fields than to guess at them.
+      return undefined;
+    }
+  }
+
+  /**
+   * The override path for a child field: the parent path joined with the 
child's key, but array
+   * indices are dropped so one override entry covers every row of a repeated 
section. @internal,
+   * exported for tests.
+   */
+  public static childPath(parent: string, key: unknown): string {
+    if (typeof key !== "string" || key === "" || /^\d+$/.test(key)) {
+      return parent;
+    }
+    return parent ? parent + "." + key : key;
+  }
+
+  /**
+   * Walk the field and its sub-fields, dropping the operator schema's own 
per-field descriptions
+   * (author notes about the operator, not guidance to a form reader) and 
applying the author's
+   * stored per-sub-field overrides (rename, hide), keyed by field path. A 
repeated section builds
+   * its row template on demand, so its builder is wrapped to decorate every 
row formly ever makes.
+   */
+  private applyFieldOverrides(field: FormlyFieldConfig, binding: 
FormFieldBinding): void {
+    const walk = (node: FormlyFieldConfig, path: string): void => {
+      // Drop the schema's own description on every field, nested ones 
included: on this page the
+      // one piece of guidance is the help text the form's author writes, 
rendered once by the card.
+      node.props = { ...(node.props ?? {}), description: "" };
+      // Apply the author's stored overrides so a reader sees each sub-field 
renamed and hidden as
+      // set up. The root (path "") carries the binding's own displayName, set 
in renderField.
+      if (path) {
+        const override = binding.overrides?.[path] ?? {};
+        if (override.displayName) {
+          node.props = { ...(node.props ?? {}), label: override.displayName };
+        }
+        if (override.hidden) {
+          node.hide = true;
+        }

Review Comment:
   Formly clears a field's model value when it is hidden unless `resetOnHide` 
is disabled. Because this card later writes the whole nested object back, 
merely opening/editing a form with a hidden sub-field can delete the author's 
existing value, contradicting `FormFieldOverride.hidden`'s contract that the 
value still applies. Preserve the model when applying the visibility override.



##########
frontend/src/app/workspace/component/workflow-form/workflow-form.component.ts:
##########
@@ -367,9 +364,104 @@ export class WorkflowFormComponent implements OnInit, 
OnDestroy {
       field.props = { ...(field.props ?? {}), disabled: true };
     }
 
+    this.applyFieldOverrides(field, binding);
     return { resolved, fields: [field], form, model };
   }
 
+  /**
+   * The template for one row of a repeated section. formly's `fieldArray` may 
be the template
+   * object or a function that builds one per row; resolve both so an array 
property's sub-fields
+   * are reachable (treating the function case as a leaf hid them). @internal, 
exported for tests.
+   */
+  public static arrayItemOf(node: FormlyFieldConfig): FormlyFieldConfig | 
undefined {
+    const fa = node.fieldArray;
+    if (!fa) {
+      return undefined;
+    }
+    if (typeof fa !== "function") {
+      return fa;
+    }
+    try {
+      return fa(node);
+    } catch {
+      // A builder that needs more context than we can give it tells us 
nothing about the row's
+      // shape; better to list no sub-fields than to guess at them.
+      return undefined;
+    }
+  }
+
+  /**
+   * The override path for a child field: the parent path joined with the 
child's key, but array
+   * indices are dropped so one override entry covers every row of a repeated 
section. @internal,
+   * exported for tests.
+   */
+  public static childPath(parent: string, key: unknown): string {
+    if (typeof key !== "string" || key === "" || /^\d+$/.test(key)) {
+      return parent;
+    }
+    return parent ? parent + "." + key : key;
+  }
+
+  /**
+   * Walk the field and its sub-fields, dropping the operator schema's own 
per-field descriptions
+   * (author notes about the operator, not guidance to a form reader) and 
applying the author's
+   * stored per-sub-field overrides (rename, hide), keyed by field path. A 
repeated section builds
+   * its row template on demand, so its builder is wrapped to decorate every 
row formly ever makes.
+   */
+  private applyFieldOverrides(field: FormlyFieldConfig, binding: 
FormFieldBinding): void {
+    const walk = (node: FormlyFieldConfig, path: string): void => {
+      // Drop the schema's own description on every field, nested ones 
included: on this page the
+      // one piece of guidance is the help text the form's author writes, 
rendered once by the card.
+      node.props = { ...(node.props ?? {}), description: "" };
+      // Apply the author's stored overrides so a reader sees each sub-field 
renamed and hidden as
+      // set up. The root (path "") carries the binding's own displayName, set 
in renderField.
+      if (path) {
+        const override = binding.overrides?.[path] ?? {};
+        if (override.displayName) {
+          node.props = { ...(node.props ?? {}), label: override.displayName };
+        }
+        if (override.hidden) {
+          node.hide = true;
+        }
+      }
+      // A repeated section may build its row template on demand, once per 
row. Decorating the
+      // object it returns is pointless -- the next row gets a fresh one. Wrap 
the builder instead,
+      // so every row formly ever creates comes out decorated.
+      if (typeof node.fieldArray === "function") {
+        const build = node.fieldArray;
+        node.fieldArray = (f: FormlyFieldConfig) => {
+          const row = build(f);
+          // Walk what is INSIDE each row, never the row container itself: the 
container carries the
+          // array property's own name, so decorating it as a root (path "") 
printed the group title
+          // a second time above the rows. Its sub-fields keep their own key 
paths, the same ones
+          // their overrides are stored under.
+          const children = row.fieldGroup ?? [];

Review Comment:
   When a builder returns an object row, the row container itself is never 
walked, so an `items.description` remains on `row.props` and is rendered by 
`ObjectTypeComponent` for every row. Clear only the row's description before 
walking its children; this avoids reapplying the parent label while still 
fulfilling the description-removal behavior.



##########
frontend/src/app/workspace/component/workflow-form/workflow-form.component.ts:
##########
@@ -367,9 +364,104 @@ export class WorkflowFormComponent implements OnInit, 
OnDestroy {
       field.props = { ...(field.props ?? {}), disabled: true };
     }
 
+    this.applyFieldOverrides(field, binding);
     return { resolved, fields: [field], form, model };
   }
 
+  /**
+   * The template for one row of a repeated section. formly's `fieldArray` may 
be the template
+   * object or a function that builds one per row; resolve both so an array 
property's sub-fields
+   * are reachable (treating the function case as a leaf hid them). @internal, 
exported for tests.
+   */
+  public static arrayItemOf(node: FormlyFieldConfig): FormlyFieldConfig | 
undefined {
+    const fa = node.fieldArray;
+    if (!fa) {
+      return undefined;
+    }
+    if (typeof fa !== "function") {
+      return fa;
+    }
+    try {
+      return fa(node);
+    } catch {
+      // A builder that needs more context than we can give it tells us 
nothing about the row's
+      // shape; better to list no sub-fields than to guess at them.
+      return undefined;
+    }
+  }
+
+  /**
+   * The override path for a child field: the parent path joined with the 
child's key, but array
+   * indices are dropped so one override entry covers every row of a repeated 
section. @internal,
+   * exported for tests.
+   */
+  public static childPath(parent: string, key: unknown): string {
+    if (typeof key !== "string" || key === "" || /^\d+$/.test(key)) {
+      return parent;
+    }
+    return parent ? parent + "." + key : key;
+  }
+
+  /**
+   * Walk the field and its sub-fields, dropping the operator schema's own 
per-field descriptions
+   * (author notes about the operator, not guidance to a form reader) and 
applying the author's
+   * stored per-sub-field overrides (rename, hide), keyed by field path. A 
repeated section builds
+   * its row template on demand, so its builder is wrapped to decorate every 
row formly ever makes.
+   */
+  private applyFieldOverrides(field: FormlyFieldConfig, binding: 
FormFieldBinding): void {
+    const walk = (node: FormlyFieldConfig, path: string): void => {
+      // Drop the schema's own description on every field, nested ones 
included: on this page the
+      // one piece of guidance is the help text the form's author writes, 
rendered once by the card.
+      node.props = { ...(node.props ?? {}), description: "" };
+      // Apply the author's stored overrides so a reader sees each sub-field 
renamed and hidden as
+      // set up. The root (path "") carries the binding's own displayName, set 
in renderField.
+      if (path) {
+        const override = binding.overrides?.[path] ?? {};
+        if (override.displayName) {
+          node.props = { ...(node.props ?? {}), label: override.displayName };
+        }
+        if (override.hidden) {
+          node.hide = true;
+        }
+      }
+      // A repeated section may build its row template on demand, once per 
row. Decorating the
+      // object it returns is pointless -- the next row gets a fresh one. Wrap 
the builder instead,
+      // so every row formly ever creates comes out decorated.
+      if (typeof node.fieldArray === "function") {
+        const build = node.fieldArray;
+        node.fieldArray = (f: FormlyFieldConfig) => {
+          const row = build(f);
+          // Walk what is INSIDE each row, never the row container itself: the 
container carries the
+          // array property's own name, so decorating it as a root (path "") 
printed the group title
+          // a second time above the rows. Its sub-fields keep their own key 
paths, the same ones
+          // their overrides are stored under.
+          const children = row.fieldGroup ?? [];
+          if (children.length === 0) {
+            // A scalar array (a list of strings): the builder returns a leaf 
row with no sub-fields,
+            // so decorate the row itself, mirroring the leaf case of the 
non-function branch below.
+            walk(row, path);
+          }
+          for (const child of children) {
+            walk(child, WorkflowFormComponent.childPath(path, child.key));
+          }
+          return row;
+        };
+        return;
+      }
+      const arrayItem = WorkflowFormComponent.arrayItemOf(node);
+      const children = node.fieldGroup ?? arrayItem?.fieldGroup ?? [];

Review Comment:
   The value-backed object-array path also skips the row template whenever it 
has a `fieldGroup`, leaving an `items.description` visible on each object row. 
Clear the template description independently of walking its children, just as 
for scalar array items.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to