Skip to content

feat: add copy increment button action#4219

Open
Christoph111 wants to merge 2 commits into
bitfocus:mainfrom
Christoph111:main
Open

feat: add copy increment button action#4219
Christoph111 wants to merge 2 commits into
bitfocus:mainfrom
Christoph111:main

Conversation

@Christoph111

@Christoph111 Christoph111 commented Jun 3, 2026

Copy link
Copy Markdown

Summary

  • Add a Copy +N button-grid action for copying a source button to multiple targets with incrementing values.
  • Add a settings modal to choose which numeric/text fields should be incremented and configure the step size.
  • Add TRPC support and a shared control increment utility to discover and apply incrementable button fields.
  • Cover the increment utility with focused tests for action options, feedback options, local variables, button labels, zero-padded values, and skipped expressions/colors.

Verification

  • git diff --check
  • yarn test --run companion/test/Controls/ControlIncrementUtil.test.ts
  • yarn check-types
  • Commit hook: eslint, prettier --check

Summary by CodeRabbit

  • New Features

    • Added "Copy +N" to the control grid for copying controls while incrementing selected numeric fields with a configurable step, per-paste offset, and on-screen guidance.
    • New settings modal to choose which fields to increment, set the step (validated range), and select/deselect all.
  • Tests

    • Added tests verifying discovery of incrementable fields, correct increment behavior (including preserved zero-padding), and that non-numeric/color/layout fields are ignored.

@CLAassistant

CLAassistant commented Jun 3, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d6a63bba-7f6d-4aaa-a2ad-73c3b7175611

📥 Commits

Reviewing files that changed from the base of the PR and between 5e15c0e and e34cf75.

📒 Files selected for processing (1)
  • webui/src/Buttons/ButtonGridActions.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • webui/src/Buttons/ButtonGridActions.tsx

📝 Walkthrough

Walkthrough

This PR implements a "Copy +N" feature: it discovers incrementable fields in a control's JSON, exposes options via TRPC, applies numeric/text increments to selected fields when copying controls, and adds a frontend modal and button workflow to configure and execute incremented copies.

Changes

Copy +N Control Increment Feature

Layer / File(s) Summary
Core increment utilities and tests
companion/lib/Controls/ControlIncrementUtil.ts, companion/test/Controls/ControlIncrementUtil.test.ts
Discovers expression-value fields in control JSON via traversal, validates numeric/string eligibility while excluding hex colors and layouts, formats human-readable labels for action sets, feedbacks, and local variables, and applies arithmetic or regex-based string increments while preserving padding. Tests validate filtering and selective incrementation.
Backend TRPC endpoints
companion/lib/Controls/ControlsTrpcRouter.ts
Adds getControlIncrementOptions query to return discoverable fields and copyControlWithOffset mutation to copy controls between locations with field increments applied, handling destination replacement, fresh ID generation, and redraw triggering.
Frontend UI and Copy +N workflow
webui/src/Buttons/ButtonGridActions.tsx, webui/src/scss/_button-grid.scss
Adds Copy +N button and CopyIncrementSettingsModal with step input, select-all/none and per-field checkboxes. Tracks modal/loading/error state, fetched increment options, selected fields, step, and paste index. Implements flow: select source to fetch options, configure modal, then paste to perform offset copies with advancing paste index. Includes SCSS for modal layout and field list.

Poem

🎛️ Copy once, increment with grace,
Numbers march forward, keeping place.
Select the fields, set a step, then go—
Paste again and watch them grow. ✨

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature addition: a new 'Copy +N' button action that enables copying controls with incrementing values.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4037edc9-8c62-4513-a02b-0ecfa7dbf2bc

📥 Commits

Reviewing files that changed from the base of the PR and between e0490e5 and 5e15c0e.

📒 Files selected for processing (5)
  • companion/lib/Controls/ControlIncrementUtil.ts
  • companion/lib/Controls/ControlsTrpcRouter.ts
  • companion/test/Controls/ControlIncrementUtil.test.ts
  • webui/src/Buttons/ButtonGridActions.tsx
  • webui/src/scss/_button-grid.scss

Comment thread webui/src/Buttons/ButtonGridActions.tsx

@Julusian Julusian left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR, I like the idea behind this!

From a UX side:

  • I feel like the placement of the button and calling it '+1' is not the most clear on what it does
  • This should be added to the context menu that was recently added to the grid
  • There needs to be a confirm step before replacing an existing button; I think it is too easy to forget it is still active and to accidentally replace a button you dont mean to.
image
  • I think it would be good to have a quick explainer block of text at the top to explain what this does
  • I would prefer the Local variable 1 (me) to be Local varible: me or perhaps it should be $(local:me) to show it in a familar way?
  • It looks like it has picked up colour feedback values, which is weird. It is hard to tell what these feedback values are.
  • As this is doing replacements in strings, it would be good to show a preview of what those values will become. Should it be incrementing every number or just the last found number?

I am wondering whether this should support adjusting any feedback/action/style option, or if it should be limited to just local variables. While I can see value in it being able to operate on anything, I think its going to either add a lot of complexity to be able to accurately filter and label what it is showing.

This is how it shows for one of my pretty complex buttons:
image

input.incrementBy
)

// Delete the control at the destination

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here onwards could probably be replaced with controlsController.importControl(toLocation, controlJson, true) and check the return was a string for success.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like some of this css shouldnt be necessary, it would be better to use existing util when possible. For the grid/layout stuff that should be possible, probably not for the badge

return key.replace(/^opt:/, '').replace(/_/g, ' ')
}

function isExpressionValueObject(value: unknown): value is { value: unknown; isExpression: boolean } {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is already a util for this

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not liking how generically this is searching. As some of the label generation shows, this loses all the context on what everything is, which is resulting in the functions for generating the label based on the paths, and leaves parts of the labels as abstract/internal names that don't mean anything to the user.
And I worry that as we adjust terminology or add functionality elsewhere, it will be very easy to forget about the label generation here resulting in them diverging

In my modules, a bunch of the options fields are named very poorly as they were chosen years ago but they arent user facing so there has been no reason to go through the effort of renaming them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants