yangzhang75 opened a new pull request, #8846: URL: https://github.com/apache/texera/pull/8846
### What changes were proposed in this PR? Closes #8763. Part of the Form View feature (#8011); from the #8439 refinements (item 6). The Form View now names the operator on every field it renders (`props.operatorID`: `FIELD_OPERATOR_ID_PROP` / `fieldOperatorID` in `custom-formly-type.ts`); a shared widget that needs its operator reads it there, since nothing is highlighted on the form, and the same mark tells it which host it is on where the two must differ (its columns and headers; what decides whether it offers Add parameter). `ui-udf-parameters` is exposable, but its renderer hides formly's labels and draws fixed column headers (Value / Name / Type), so the author's per-sub-field overrides from the form (#8438) changed nothing the reader saw: a rename lands as `props.label` on every row's sub-field and a hide as `hide`, and the fixed headers papered over both -- a renamed column kept its old name, a hidden one kept its header over an empty cell. Reviewing it also turned up four more things the widget got wrong: three on a Form View card, one on the canvas. - On the Form View the widget decides which columns are in view from the first row's sub-fields (the rows all share one override per path; formly builds them on demand from a template this widget never sees decorated, and with no rows the list is not shown at all): a hidden column is left out, header and cells alike, and so is a column whose group is hidden, since formly hides the children with the group but marks only the group. The list is read live, on every check, not once at populate: the form's hide lands on a row's sub-field after formly has built the row, so a list fixed at populate still showed the hidden column (found on a running instance). The same array instance comes back while nothing changed, so the header's `ngFor` does not redraw. - The header text is read live from the first row too: the author's name for the column (`props.authorName`: the form puts a saved rename there as well as on the label, and the label wrapper writes a name being typed there, which otherwise would have shown only after the next rebuild), else the fixed label -- not the schema's own title, which the panel does not show either. - "Add parameter" works on a Form View card as it does on the panel. It inserts a declaration into an operator's code, and it took that operator from the canvas highlight -- on the form nothing is highlighted, or another step is, so it edited the wrong operator or failed with "code is not available". The widget now takes the operator the field is bound to when the field carries one, and the highlighted operator otherwise (the panel, as always). Whether a card offers it follows the card's own rule, the one the add and remove buttons of every list on the form follow: the field is editable (a writer's card, in or out of edit mode, since adding a parameter is adding a row; a reader's card is disabled). It followed the canvas's modification flag, which the Form View holds off outside edit mode against structural edits through its page, so a writer could add a row to any list on the page but not a parameter to this table without entering edit mode. The panel keeps the canvas's rule, the flag, unchanged. The check also sits in the method, not only on the button. - The declared parameters then reach the operator: the parser announces the UI parameters a UDF's code declares, and the operator property panel's frame writes them onto the operator for the operator it shows, only while it acts as the editor. With the panel closed or on another step nobody wrote them, so a parameter added from a card changed the code but no row appeared. The form writes them when the frame does not: a writer only, not while the step panel shows that very step live, and only for an operator still on the graph; the same value the frame writes. - A read-only reader's value cells are locked: the Form View marks a reader's field `props.disabled`, and the widget's own "the value is editable" used to re-enable the control after formly had disabled it. - The widget's own lock on the Name and Type cells now holds under any host, the one change the canvas sees. The cells are inferred from the code's `self.UiParameter(...)` declarations and the widget marks them `props.disabled` (a name typed into the table no longer matches a declaration, and the value then never reaches it -- checked on main: the table's name changes, the code's does not). The panel's `setInteractivity(true)` enables the whole form group, and formly mirrors a control's state back into `props.disabled`, so the one-time disable did not survive: on the canvas the cells came back editable (sometimes, depending on which of the two ran last) while the Form View, which never enables a group wholesale, showed them locked. The widget now registers, on each cell it locks, Angular's disabled-change hook of the control (`registerOnDisabledChange`, the same hook formly's mirror and the input's value accessor use): whenever a host enables the control, the hook disables it agai n in the microtask after that enable (so the accessor, told last, shows the box locked too), announcing the status change as the enable did (ng-zorro's `nz-input` paints its disabled attribute from the control's status changes, and told only "enabled" it painted the box editable again at the next change detection), and formly's mirror then records the lock in `props.disabled` as well. A cell the widget configures editable (the Value cell, or any cell once reconfigured) is released from the hook, so whether it is editable stays the host's call (a read-only panel, a reader's card). A formly expression was tried first and dropped: formly re-evaluates expressions on model changes only, not on an `enable()`. The frame is untouched. - Otherwise the operator property panel is unchanged: the three headers stay fixed, Add parameter adds to the highlighted operator, the value column stays editable. ### Any related issues, documentation, discussions? Closes #8763. Raised by Copilot on #8438; filed from #8439. Based on main. #8760 (the form's own code editor host) needs the same operator mark and the same write of the declared parameters; whichever lands second drops its copy. Checked under real formly while reviewing: hiding the `attribute` group itself keeps the rows' names and types in the model (formly resets a hidden field's children only on a hide that happens after the build; the form sets `hide` at build only, and a reader's card is rebuilt rather than toggled). Table semantics for assistive tech (the header and cells are plain `div`s, as on the canvas) stay a follow-up. One difference between the hosts is the Form View's own and not changed here: a writer's cards stay editable while a run is in flight (the add and remove buttons of every list included), so a card offers Add parameter then as well, while the operator property panel is locked during a run. ### How was this PR tested? Unit tests (vitest). The widget's spec: a renamed column shows its name and a hidden one is left out, in the header and the cells; rows built on demand are read from the first row; a hidden group hides its columns; the author's name shows while renaming and follows the typing without a rebuild; no rows keeps the fixed headers; the panel keeps them whatever the sub-fields carry; a reader's value cells are locked; Add parameter is offered on the form and adds to the card's operator, on the panel to the highlighted one; a writer's card offers it while the canvas's modification flag is off (the Form View holds it outside edit mode) and a reader's card, its field disabled, does not and adds nothing; on the panel `addParameter` adds nothing while modification is off, whoever calls. The widget's spec also pins the lock: a locked cell's control is held locked when the host enables it (in the microtask after the enable, announcing its status change) while the Value cell is left to the host ; a cell configured editable again is released; a cell the host disables again before the microtask is left alone; a group control gets no hook, and a control is hooked once. A second widget spec stands it up under real formly (`FormlyModule.forRoot`, a form, a builder row template as formly-jsonschema produces, the cells `nz-input`s as in the app): the rows build with Name and Type locked and Value editable; a wholesale `form.enable()`, as the panel does, leaves Name and Type locked, read from the inputs' disabled state, not only the controls'; a read-only `form.disable()` locks everything and a later `enable()` gives only Value back; a writer's Form View card offers Add parameter with the canvas's flag off, a reader's card (`props.disabled`, which formly turns into a disabled field) does not. The form's spec: every field carries its operator; a renamed sub-field carries the author's name apart from its label (a sub-field formly built without props too); the declared UI parameters are written for a writer when the panel is not editing that step, left to the frame while it shows the step live, written when it shows the step read-only, and not written for a reader or a vanished operator. `custom-formly-type`'s spec pins the operator mark. Each guard was deletion-checked and turned a named test red. eslint, prettier and the production (AOT) build pass; the full frontend suite passes; every statement, function and branch this PR adds is covered. Checked on a flag-on instance (main-demo; a Python source feeding a Python UDF whose code declares two UI parameters, `uiParameters` exposed with the Name column renamed "Parameter" and the Type column hidden), the canvas and the form open side by side. On main the card shows Value / Name / Type, the overrides ignored. With this PR the card shows Value / Parameter, the Type column gone, while the canvas panel still shows Value / Name / Type. A writer's card offers Add parameter in and out of edit mode (on main it appeared only in edit mode, while any list's rows could be added either way); adding `cutoff` (double) inserts `self.UiParameter(name="cutoff", type=AttributeType.DOUBLE)` into that UDF's code, and the new row appears on the card and in the canvas tab's panel within a few seconds, and is there after a reload. On the canvas panel (widened so that the Name and Type columns are in view; at its default width the table's fixed 250px columns clip them, a layout bug of its own since #5043, not touched here), main's Name and Type cells come back editable on about half the panel openings (2 of 4 loads; the frame enables the whole form group one task after each render, racing the widget's lock) and whenever the modification-enabled stream enables the group, e.g. when a run finishes. With this PR they stayed locked on 4 of 4 loads and through a forced wholesale enable followed by real change-detection passes, read from the DOM (the input's disabled state, the select's disabled class) as well as from the controls. The Value cell follows the host in both. #### Video **Before** _(to be added)_ **After** _(to be added)_ ### Was this PR authored or co-authored using generative AI tooling? Yes. Generated-by: Claude Code (Claude Fable 5.1, Anthropic). Co-authored with Claude, reviewed line by line by the author before submission. 🤖 Generated with [Claude Code](https://claude.com/claude-code) -- 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]
