yangzhang75 opened a new pull request, #8843: URL: https://github.com/apache/texera/pull/8843
### What changes were proposed in this PR? Closes #8761. Part of the Form View feature (#8011); from the #8439 refinements (item 2). An exposed drag-reorder property -- Projection's columns, formly type `repeat-section-dnd` -- fell back to a plain repeated list in the Form View (`CANVAS_ONLY_FORMLY_TYPES`): a reader could edit the rows but not reorder them, which is what the widget is for. The fallback assumed the drag had nowhere to attach on a form; the widget carries its own CDK drop list, and the row template it needs comes from the operator's own schema (the per-instance one, with the upstream columns), which the form already builds. - `repeat-section-dnd` leaves `CANVAS_ONLY_FORMLY_TYPES`; the set now holds the code editor only. On the form the widget renders with the drag, and a reorder reaches the operator through the card's `valueChanges` write-back (the canvas's `reorder` callback is optional, as it always was). - The widget gets a keyboard path, as the form's own step list has: Move up / Move down on every row, through the same move as the drag (model, field configs, form controls, then the parent's callback). At the ends the buttons are `aria-disabled`, not disabled, so the focused button is not dropped; after a move the focus is put back on the same button of the row where it landed, since a moved DOM node loses it. The drag handle is hidden from assistive tech, and the drag is disabled with the section. These buttons appear wherever the widget renders, so the operator property panel's Projection rows gain them too (two small buttons per row); an a11y gain there as well, called out here so it is a decision, not a surprise. - Two defects in the widget itself, found while reviewing this and in reach of the form for the first time: every button now has `type="button"` -- `nz-button` sets no type, so inside a form (the card's, the panel's) a typeless button is the submit button and Enter in a row's input clicked it, removing the first row (the fallback the form used before had typed buttons; the panel has had this since the widget exists); and the rows are re-keyed to their positions after a move, as formly's own `remove()` does -- formly keys rows by position and writes a cell's value into the model by that key path, so a value typed into a moved row landed on the row that used to be there (the same after a drag on the panel, until the operator was re-selected). ### Any related issues, documentation, discussions? Closes #8761. Raised by @mengw15 on #8436; filed from #8439. Builds on the sub-field walk from #8438. #8760 (proper) also shrinks `CANVAS_ONLY_FORMLY_TYPES`; whichever lands second deletes the then-empty set. Known limitation, not this PR's code: the Form View rebuilds every card on every compilation, including the one a card's own write triggers, so on the form a Move's write redraws the row buttons about a second later, drops the keyboard focus the widget had just put back, and can undo a second Move made in the last 150 ms before that redraw. The canvas panel has no such rebuild. It is filed separately with a fix verified on a branch (the form rebuilds only when the schema, the set of inputs or a value it does not hold changed); this PR is independent of it. Other follow-ups: a card's model is seeded once and never re-seeded from a co-editor's edit of the same property, so a reorder writes the whole array back over such an edit (pre-existing for every array/object property; a r eorder is one more trigger); the HuggingFace and codearea widgets also carry typeless buttons. ### How was this PR tested? Unit tests (vitest). The widget's spec: a keyboard move reorders the model, the field configs and the form controls and tells the parent; at the ends it goes nowhere and the buttons stay in the tab order; the focus is put back on the moved row's button, Move up and Move down alike (asserted on the restoring call, since jsdom does not model the browser's focus drop); a disabled section locks the move buttons and the drag; the handle is hidden from assistive tech; every button carries `type="button"`; a keyless row's children are re-keyed to the row's new position, as formly's own remove() does. A second spec stands the widget up under real formly (`FormlyModule.forRoot`, a form, a model): a move changes the model and the cells and keeps the rows' keys in step with their positions, and a value typed into a moved row lands on that row's entry. The form's spec: Projection's `attributes` renders through `repeat-section-dnd`. `custom-formly-type`'s spec pins the set. Each guard was dele tion-checked (the move in the wrong direction; no focus restore; the Move-up restore aimed at the Move-down button; no guard at the ends; the parent never told; the drag live for a disabled section; the move buttons live; `disabled` instead of `aria-disabled` at the ends; the handle exposed; the type back in the canvas-only set; the re-keying dropped; the remove button typeless) 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 with four columns feeding a Projection whose `attributes` is exposed), with the canvas and the form open side by side: on main the card is a plain list (no handle, no Move buttons); with this PR the card shows the drag handles and the Move buttons, as the panel does. Move down on the first row: the operator's order follows in the canvas tab's panel within a second and in the saved workflow. Dragging the last row to the top with the mouse: the same. An alias typed into the moved row lands on that column, not its neighbour; Enter in an alias input removes no row; a reload shows the same order. A Move made on the canvas panel reaches the form within a second. ### 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]
