Skip to content

feat: add connection duplication - #4371

Open
KairiYasumatsu wants to merge 2 commits into
bitfocus:mainfrom
KairiYasumatsu:feat/duplicate-connections-4034
Open

feat: add connection duplication#4371
KairiYasumatsu wants to merge 2 commits into
bitfocus:mainfrom
KairiYasumatsu:feat/duplicate-connections-4034

Conversation

@KairiYasumatsu

@KairiYasumatsu KairiYasumatsu commented Jul 26, 2026

Copy link
Copy Markdown

Summary

  • add a Duplicate command to each connection row
  • copy the source module, version, config, secrets, update policy, enabled state, and upgrade index
  • place the new connection immediately after the source in the same collection
  • open the duplicated connection for editing without copying or rewriting actions and feedbacks

The duplication is owned by the backend because connection config and secrets are intentionally not exposed in the connection-list client model. It reuses the existing connection creation, configuration, and reorder paths. The duplicate is created disabled, fully configured and positioned, and only then enabled when the source was enabled, so it cannot start with the temporary default config.

For legacy connections whose module version is null, duplication follows the existing add-connection behavior and resolves the latest installed version.

Validation

  • Node 26.5.0 / Yarn 4.17.1
  • yarn install --immutable
  • yarn build:ts
  • yarn build:graphics-types
  • yarn prettier --check .
  • yarn lint (no errors; six existing warnings)
  • yarn check-types
  • generated config-reference and satellite-schema checks
  • yarn workspace @companion-app/webui build
  • focused backend tests: 7 passed
  • focused Web UI test: 1 passed
  • browser layout check at 1440x900 and 390x844
  • full test suite: 3994 passed, 1 unrelated existing sunset scheduling assertion failed

Closes #4034

AI assistance was used for repository research, implementation, and test preparation. The resulting changes and validation output were reviewed locally.

Summary by CodeRabbit

  • New Features

    • Added a Duplicate action for connections in the connection list.
    • Duplicated connections copy configuration and secrets, preserve enabled/disabled state, and receive a unique label.
    • New duplicates are inserted immediately after the original within their collection ordering.
  • Bug Fixes

    • Displays/handles duplication failures when the source connection is unavailable.
  • Tests

    • Added coverage for connection duplication behavior and the UI duplicate action flow.

@CLAassistant

CLAassistant commented Jul 26, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds connection duplication across the instance controller, TRPC API, and web connection list. Duplicates copy configuration and ordering while excluding source control state, and the new UI action configures the duplicated connection.

Changes

Connection duplication

Layer / File(s) Summary
Controller duplication behavior
companion/lib/Instance/Controller.ts, companion/test/Instance/Connection/Duplicate.test.ts
Adds duplicateConnection to clone connection settings, preserve collection placement and enabled state, assign duplicate labels, and leave control state unchanged. Tests cover grouped, ungrouped, disabled, repeated, and missing-source cases.
TRPC duplication endpoint
companion/lib/Instance/Connection/TrpcRouter.ts
Adds the duplicate mutation, validates connectionId, returns the new connection ID, and reports missing connections as an error.
Connection row duplicate action
webui/src/Connections/ConnectionList/ConnectionsTableRow.tsx, webui/src/Connections/ConnectionList/__tests__/ConnectionsTableRow.test.tsx
Adds a clone-icon Duplicate menu item, invokes the mutation, and passes the returned ID to configureConnection; the UI test verifies the request and callback.

Poem

A connection takes a twin,
With settings neatly tucked within.
It finds its place in line,
Leaves old controls behind,
And blooms beneath its kin.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR adds a duplicate connection action, keeps the copy in the same collection beneath the source, and avoids copying actions or feedbacks.
Out of Scope Changes check ✅ Passed The changes stay focused on connection duplication plus matching UI and tests, with no obvious unrelated scope added.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding connection duplication.

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.

@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 Plus

Run ID: f397b19f-8d69-4d9a-84ea-7f143a6587b4

📥 Commits

Reviewing files that changed from the base of the PR and between 1c7bdb5 and bab1a45.

📒 Files selected for processing (5)
  • companion/lib/Instance/Connection/TrpcRouter.ts
  • companion/lib/Instance/Controller.ts
  • companion/test/Instance/Connection/Duplicate.test.ts
  • webui/src/Connections/ConnectionList/ConnectionsTableRow.tsx
  • webui/src/Connections/ConnectionList/__tests__/ConnectionsTableRow.test.tsx

Comment thread companion/lib/Instance/Controller.ts Outdated
@thedist

thedist commented Jul 26, 2026

Copy link
Copy Markdown
Member

My issue with this is that it would be a breaking feature for some modules. For example the Twitch module uses the OAuth Device Code Flow, so creating a duplicate connection would break the first. Similarly there are modules that connect to devices/services that only allow a limited number of concurrent connections in which case duplicating the connection with the same config could either cause the new connection to error or potentially disconnect the original connection.

@KairiYasumatsu

Copy link
Copy Markdown
Author

Thanks for pointing this out. I overlooked the module-specific side effects of copying credentials and immediately starting the duplicated connection.

Would creating duplicates in a disabled state be sufficient, or should duplication require explicit module support? I’m happy to revise the implementation based on your preferred direction.

@thedist

thedist commented Jul 27, 2026

Copy link
Copy Markdown
Member

Duplicated connections starting in a disabled state would help with some, such as those that connect to devices/services that have limitations on concurrent connections, but for others such as Twitch as I mentioned there's no suitable way to handle duplication as even if the duplicate connection is in a disabled state when you enable it the original connection will effectively be killed and unusable until the user goes through the entire authentication process again which completely negates the point of duplicating the connection.

IMO I would suggest an update to the module API that would allow module developers to control if their module can or can't be duplicated, as that way the user will then only have the option to duplicate connections that is safe to do so and can't accidently duplicate a connection that would kill the original because they are unaware of the technical side of things.

@Julusian

Copy link
Copy Markdown
Member

What if this was done on the ui side? It could then show a config form for the new connection (driven by the config fields of the old connection), allowing it to be edited before being created.
Perhaps during this we should even actively prune out any values that dont have a corresponding config field?

I don't know how to handle disabled connections for this though, we won't have any known config fields for them..

IMO I would suggest an update to the module API that would allow module developers to control if their module can or can't be duplicated, as that way the user will then only have the option to duplicate connections that is safe to do so

It also means it would be an incredibly slow rollout of the feature. While I am against doing this if we need to, it would be nice to find a way to avoid this.
It is worth noting that since the release of 4.3 in mid April, only 6% of modules have been updated to the 2.0 API that has been supported since 4.3.

Also worth noting that is roughly the same as the number of new modules. I dont know what adoption of 2.0 in older modules, but some new ones aren't 2.0 because Buttons doesn't yet support api 2.0

@thedist

thedist commented Jul 27, 2026

Copy link
Copy Markdown
Member

Perhaps during this we should even actively prune out any values that dont have a corresponding config field?

That would help with the Twitch module, as I store OAuth tokens in the config but they don't have an associated config field. This would also help with certain modules that download several MB of data from devices and store that in a connection config, as there's no sense duplicating all that data along with the connection if it's just going to be pointed to a completely separate device so would need fresh data anyway.

One other thing I'm curious about is how much use this feature really will be? If your duplicating connections then chances are you are going to need to edit the config of them anyway, such as a camera connection that's duplicated you still need to edit the config to point to a different camera. How often do users need to duplicate a connection and not need to edit the config?

If the goal of this PR is to reduce the number of clicks to add a new connection then perhaps a change there would be more appropriate (for example currently when you add a connection it goes to that new connections config, but if there was a 'add multiple connections' button you could create multiple connections without needing to go back to the list and find the module each time. As either way doing it like that, or duplicating an existing connection, you're likely going to have to edit the connection config either way so at least creating multiple new connections would not have the same issues as duplicating existing ones.

@Julusian

Copy link
Copy Markdown
Member

but if there was a 'add multiple connections' button you could create multiple connections without needing to go back to the list and find the module each time.

Or perhaps an 'add another' instead of duplicate?

But I would say that having a duplicate means that for the bunch of fields which dont need changing (port number, perhaps some common credentials, any module functionality toggles) being able to duplicate can avoid the repetition of configuring from scratch (or checking what the old one was set to).

This would also help with certain modules that download several MB of data from devices and store that in a connection config, as there's no sense duplicating all that data along with the connection

Or maybe there is? If that data is a definition of the functionality of the device, and is needed for actions/feedbacks to exist, preserving this means they can do an initial program offline.
(Same reason I think it can make sense to preserve through an export/import cycle)

@Julusian

Copy link
Copy Markdown
Member

Oh, it is also worth noting that Buttons already has a duplicate button, so it would be good to have a solution that we could recommend to them (which isnt simply don't allow it unless the module has opted into it)

@thedist

thedist commented Jul 27, 2026

Copy link
Copy Markdown
Member

(which isnt simply don't allow it unless the module has opted into it)

Would an opt-out be better? so by default all modules regardless of API version can be duplicated, but modules that wish to opt-out could download a new API version that provides a flag on the instance to disable it. The negative impact then would be limited to Companion users on a version of Companion that has duplication while also running a module version that has not updated to disable it should they need to. This also allows for all modules, even those no longer maintained, to be duplicated.

@KairiYasumatsu

Copy link
Copy Markdown
Author

That makes sense to me.
I’m happy to update the PR once the API shape is settled.

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.

Duplicate connection button

4 participants