yangzhang75 commented on code in PR #8438:
URL: https://github.com/apache/texera/pull/8438#discussion_r3945480121
##########
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:
Fixed. Confirmed in formly 7.1.0 source: the resetFieldOnHide extra defaults
to true, and changeHideState calls assignFieldValue(undefined) unless
field.resetOnHide===false. So node.resetOnHide=false is now set right where
node.hide=true. End-to-end also holds: the model is seeded from the operator
properties, so with the value kept the first valueChanges emission equals
current and the unchanged-guard skips the write, so opening the form no longer
writes the pinned value out. Added specs asserting resetOnHide===false on a
hidden sub-field (both the object and the repeated-section case) and that a
visible field never gets it. Verified at the source/config level; happy to also
do a live pass on the flag-on instance if you want belt-and-suspenders.
##########
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:
Fixed: node.resetOnHide=false is set alongside node.hide=true, so formly
does not strip the hidden sub-field's value from the model on render. See the
reply on the parallel thread (same line) for the formly-source confirmation and
the added tests.
##########
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:
Fixed, and verified this is real rather than assumed: object rows render via
ObjectTypeComponent, whose template has <p *ngIf="props.description">
(object.type.ts), so the row container's items.description would show once per
row. The builder wrapper now clears the row container's description before
walking its children, without walking it as a root (which would reprint the
array's title). Added a test with a builder row carrying a description.
##########
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:
Fixed, same class as the object-row case. A static object-array template
(fieldArray as an object with a fieldGroup) is itself an object row, so its
items.description would render via ObjectTypeComponent; the walk now clears the
template container's description independently of walking its children. Added a
test with a static object-array whose template carries a description. Note the
array container itself (ArrayTypeComponent) does not render a description, so
only the object row/template needed clearing.
--
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]