@@ -757,8 +742,8 @@
<:panel hash="vcs" class="space-y-4">
<.section_header
- title="Version control"
- subtitle="View or modify external version control settings for this project."
+ title="Sync"
+ subtitle="Sync your project to version control or other environments from here."
permissions_message={"version control configuration#{@can_initiate_github_sync && " but you can initiate a sync." || "."}"}
can_perform_action={@can_install_github}
/>
@@ -767,6 +752,22 @@
id="sandbox-banner-vcs"
variant={:local}
/>
+
+ Learn more about synchronizing your project with GitHub at
+ <.link
+ target="_blank"
+ href="https://docs.openfn.org/documentation/link-to-GitHub"
+ class="font-medium underline"
+ >
+ docs.openfn.org/documentation/link-to-GitHub
+
+
+
<%= if assigns[:github_banner] do %>
{Phoenix.LiveView.TagEngine.component(
@@ -839,24 +840,27 @@
<% else %>
- Sync to GitHub
+ Connect to GitHub
Version Control is not configured for this Lightning instance. Contact the superuser for more information.
<% end %>
-
- Need to learn more about GitHub Sync?
- See
- <.link
+
+
+
Export your Project
+
+ Save your project as a YAML file to be edited locally, backed up, or deployed elsewhere.
+
+
+ <.button_link
+ theme="primary"
+ href={~p"/download/yaml?id=#{@project.id}"}
target="_blank"
- href="https://docs.openfn.org/documentation/deploy/portability#automated-version-control-with-github-and-lightning"
- class="link"
>
- portability docs
-
- for full documentation on associated GitHub actions and automated workflows.
+ Export project
+
<:panel hash="data-storage" class="space-y-4">
From 547f8cce501d623568d6b01362831d6941d18d50 Mon Sep 17 00:00:00 2001
From: Joe Clark
Date: Thu, 8 Oct 2026 15:38:45 +0100
Subject: [PATCH 02/25] Add CLI section to Sync tab
Co-Authored-By: Claude Sonnet 5.5
---
.../live/project_live/settings.html.heex | 40 ++++++++++++++++++-
1 file changed, 39 insertions(+), 1 deletion(-)
diff --git a/lib/lightning_web/live/project_live/settings.html.heex b/lib/lightning_web/live/project_live/settings.html.heex
index e0115e79e7..70be78b5b1 100644
--- a/lib/lightning_web/live/project_live/settings.html.heex
+++ b/lib/lightning_web/live/project_live/settings.html.heex
@@ -764,7 +764,7 @@
href="https://docs.openfn.org/documentation/link-to-GitHub"
class="font-medium underline"
>
- docs.openfn.org/documentation/link-to-GitHub
+ docs.openfn.org
@@ -862,6 +862,44 @@
Export project
+
+
+
Sync with CLI
+
+ Use the CLI to push and pull this project locally
+
+
+
+
+
+ Pull this project into a local workspace:
+
+
openfn project pull {@project.id}
+
+
+
+ Push local changes back to this project:
+
+
openfn project deploy
+
+
+
+ Run a workflow:
+
+
openfn <workflow-name>
+
+
+
+ Learn more in the
+ <.link
+ target="_blank"
+ href="https://docs.openfn.org/documentation/sync"
+ class="font-medium text-indigo-600 hover:text-indigo-900"
+ >
+ CLI Sync Docs
+
+
+
<:panel hash="data-storage" class="space-y-4">
<.section_header
From 9e3bd1133a1e2436b2673388522afdf756258f41 Mon Sep 17 00:00:00 2001
From: Joe Clark
Date: Thu, 8 Oct 2026 16:42:32 +0100
Subject: [PATCH 03/25] Refine GitHub sync form layout, copy and searchable
selects
Co-Authored-By: Claude Sonnet 5.5
---
assets/js/hooks/SearchableSelect.ts | 59 ++++++
assets/js/hooks/index.ts | 2 +
lib/lightning_web/components/new_inputs.ex | 22 +++
.../project_live/github_sync_component.ex | 16 +-
.../github_sync_component.html.heex | 181 +++++++++---------
.../live/project_live/settings.html.heex | 3 +-
6 files changed, 184 insertions(+), 99 deletions(-)
create mode 100644 assets/js/hooks/SearchableSelect.ts
diff --git a/assets/js/hooks/SearchableSelect.ts b/assets/js/hooks/SearchableSelect.ts
new file mode 100644
index 0000000000..adbea63e8e
--- /dev/null
+++ b/assets/js/hooks/SearchableSelect.ts
@@ -0,0 +1,59 @@
+import type { PhoenixHook } from './PhoenixHook';
+
+type SearchableSelect = PhoenixHook<{
+ search: HTMLInputElement | null;
+ applyFilter(): void;
+}>;
+
+/**
+ * Adds a text filter to the `custom-select` input (`searchable` attr).
+ *
+ * Options are filtered client-side by hiding non-matching `li[role=option]`
+ * elements. The filter is re-applied after every LiveView patch so a re-render
+ * of the options doesn't leave the list out of sync with the search box.
+ */
+const SearchableSelect = {
+ mounted() {
+ this.search = this.el.querySelector(
+ 'input[data-select-search]'
+ );
+
+ if (!this.search) return;
+
+ this.search.addEventListener('input', () => this.applyFilter());
+
+ this.search.addEventListener('keydown', e => {
+ // Don't submit the surrounding form.
+ if (e.key === 'Enter') {
+ e.preventDefault();
+ this.el
+ .querySelector('li[role=option]:not([hidden])')
+ ?.click();
+ }
+ });
+
+ // The wrapper's phx-click opens the list; focus the search box and start
+ // with a clean filter whenever the toggle button is clicked.
+ this.el.querySelector('button')?.addEventListener('click', () => {
+ requestAnimationFrame(() => {
+ if (!this.search) return;
+ this.search.value = '';
+ this.applyFilter();
+ this.search.focus();
+ });
+ });
+ },
+ updated() {
+ this.applyFilter();
+ },
+ applyFilter() {
+ const term = (this.search?.value ?? '').trim().toLowerCase();
+
+ this.el.querySelectorAll('li[role=option]').forEach(option => {
+ const label = (option.textContent ?? '').toLowerCase();
+ option.hidden = term !== '' && !label.includes(term);
+ });
+ },
+} as SearchableSelect;
+
+export { SearchableSelect };
diff --git a/assets/js/hooks/index.ts b/assets/js/hooks/index.ts
index 67f5407788..4bb524d0c5 100644
--- a/assets/js/hooks/index.ts
+++ b/assets/js/hooks/index.ts
@@ -25,6 +25,7 @@ import {
} from './KeyHandlers';
import LogLineHighlight from './LogLineHighlight';
import type { PhoenixHook } from './PhoenixHook';
+import { SearchableSelect } from './SearchableSelect';
import { TabbedContainer } from './TabbedContainer';
export {
@@ -34,6 +35,7 @@ export {
TemplateToWorkflow,
ElapsedIndicator,
TabbedContainer,
+ SearchableSelect,
SaveViaCtrlS,
InspectorSaveViaCtrlS,
OpenSyncModalViaCtrlShiftS,
diff --git a/lib/lightning_web/components/new_inputs.ex b/lib/lightning_web/components/new_inputs.ex
index 1cef631f16..4d9d47e43b 100644
--- a/lib/lightning_web/components/new_inputs.ex
+++ b/lib/lightning_web/components/new_inputs.ex
@@ -398,6 +398,10 @@ defmodule LightningWeb.Components.NewInputs do
attr :button_placement, :string, default: nil
+ attr :searchable, :boolean,
+ default: false,
+ doc: "custom-select only: show a text box that filters the options"
+
attr :placeholder, :string, default: ""
attr :autocomplete, :string, default: "off"
@@ -524,7 +528,9 @@ defmodule LightningWeb.Components.NewInputs do
- This option will commit a copy of your current OpenFn project to a GitHub repo.
+ This option will commit a copy of your current OpenFn project to GitHub. It does not affect any workflows or configuration here.
@@ -825,10 +822,7 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
Import from GitHub (overwrite this project)
- If you already have an openfn.yaml
- (or legacy config.json)
- tracked on GitHub and you want to overwrite
- this project on OpenFn, you can choose this advanced option.
+ This option will replace this project with the workflows, collections and channels that are already committed to GitHub.
@@ -886,7 +880,7 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
<% end %>
- Existing versions of these files on these branches will be overwritten. (I'll be able to find them in my git history if needed.)
+ Existing versions of these files on these branches will be overwritten (but will still exist in git history).
"""
diff --git a/lib/lightning_web/live/project_live/github_sync_component.html.heex b/lib/lightning_web/live/project_live/github_sync_component.html.heex
index 3c88963c7f..3b3ada2094 100644
--- a/lib/lightning_web/live/project_live/github_sync_component.html.heex
+++ b/lib/lightning_web/live/project_live/github_sync_component.html.heex
@@ -9,6 +9,9 @@
phx-submit="save"
phx-target={@myself}
>
+
+ Configure Two-Way Sync to GitHub
+
<%!-- Token is expired/invalid --%>
<.error_banner
:if={show_invalid_oauth_error?(@installations)}
@@ -56,93 +59,99 @@
There was a problem connecting to GitHub. Refresh the page or contact support if the problem persists.
<.sync_order_radio form={f} />
diff --git a/lib/lightning_web/live/project_live/settings.html.heex b/lib/lightning_web/live/project_live/settings.html.heex
index 70be78b5b1..fbd0e9279d 100644
--- a/lib/lightning_web/live/project_live/settings.html.heex
+++ b/lib/lightning_web/live/project_live/settings.html.heex
@@ -824,8 +824,7 @@
Connect your OpenFn account to GitHub
- To create a new GitHub version control connection you must first connect your OpenFn account to GitHub.
- Please click the button below to get started.
+ Connect your OpenFn account to GitHub. Click the button below to get started.
Date: Thu, 8 Oct 2026 16:59:36 +0100
Subject: [PATCH 04/25] Default GitHub sync to v2 YAML with a legacy format
switch
Co-Authored-By: Claude Sonnet 5.5
---
.../project_live/github_sync_component.ex | 82 +++++++++++++------
.../github_sync_component.html.heex | 11 +--
2 files changed, 61 insertions(+), 32 deletions(-)
diff --git a/lib/lightning_web/live/project_live/github_sync_component.ex b/lib/lightning_web/live/project_live/github_sync_component.ex
index 8592e04b38..c64b4a0f25 100644
--- a/lib/lightning_web/live/project_live/github_sync_component.ex
+++ b/lib/lightning_web/live/project_live/github_sync_component.ex
@@ -91,6 +91,24 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
end
end
+ def handle_event("toggle-legacy-format", _params, socket) do
+ changeset = socket.assigns.changeset
+ current = Ecto.Changeset.get_field(changeset, :sync_version)
+
+ # Form fields read from the changeset's params before its changes, so the
+ # flip has to go through the params, like the "validate" event does.
+ params =
+ (changeset.params || %{})
+ |> Map.put("project_id", socket.assigns.project.id)
+ |> Map.put("sync_version", to_string(!current))
+
+ {:noreply,
+ assign(socket,
+ changeset:
+ validate_changes(socket.assigns.project_repo_connection, params)
+ )}
+ end
+
def handle_event("refresh-installations", _params, socket) do
changeset = validate_changes(socket.assigns.project_repo_connection, %{})
user = socket.assigns.user
@@ -120,7 +138,11 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
}) do
socket
|> assign(
- changeset: ProjectRepoConnection.configure_changeset(repo_connection, %{})
+ # New connections default to the v2 YAML format.
+ changeset:
+ ProjectRepoConnection.configure_changeset(repo_connection, %{
+ sync_version: true
+ })
)
|> assign_async([:installations, :repos], fn ->
# repos are grouped using the installation_id
@@ -729,39 +751,45 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
attr :form, :map, required: true
attr :project_id, :string, required: true
+ attr :myself, :any, required: true
+ # Inverted: sync_version is true (v2) unless the legacy switch is on. The
+ # hidden input carries the current value with the form's phx-change events.
defp config_format_toggle(assigns) do
+ assigns = assign(assigns, :legacy?, !sync_version?(assigns.form))
+
~H"""
-
+
+
-
-
-
- Only enable this if you want to use the new openfn.yaml
- format instead of the legacy JSON config.
-
-
+
+ Use legacy YAML config format
+
"""
end
diff --git a/lib/lightning_web/live/project_live/github_sync_component.html.heex b/lib/lightning_web/live/project_live/github_sync_component.html.heex
index 3b3ada2094..39728400ef 100644
--- a/lib/lightning_web/live/project_live/github_sync_component.html.heex
+++ b/lib/lightning_web/live/project_live/github_sync_component.html.heex
@@ -165,11 +165,6 @@
class="placeholder:italic placeholder:text-slate-400"
/>
- <.config_format_toggle
- :if={f[:sync_direction].value != :deploy}
- form={f}
- project_id={@project.id}
- />
<%= if f[:branch].value do %>
<.accept_checkbox
project={@project}
@@ -194,6 +189,12 @@
Connect Branch & Initiate First Sync
+ Learn more about synchronizing your project with GitHub at
+ <.link
+ target="_blank"
+ href="https://docs.openfn.org/documentation/link-to-GitHub"
+ class="font-medium underline"
+ >
+ docs.openfn.org
+
+
- Learn more about synchronizing your project with GitHub at
- <.link
- target="_blank"
- href="https://docs.openfn.org/documentation/link-to-GitHub"
- class="font-medium underline"
- >
- docs.openfn.org
-
-
-
<%= if assigns[:github_banner] do %>
{Phoenix.LiveView.TagEngine.component(
From 2c97e07d12e1c852ffe4b6408c3af3e17c5515ca Mon Sep 17 00:00:00 2001
From: Joe Clark
Date: Thu, 8 Oct 2026 17:09:06 +0100
Subject: [PATCH 06/25] Tidy the connected GitHub sync panel
Co-Authored-By: Claude Sonnet 5.5
---
.../project_live/github_sync_component.ex | 2 +-
.../github_sync_component.html.heex | 70 +++++++++----------
2 files changed, 35 insertions(+), 37 deletions(-)
diff --git a/lib/lightning_web/live/project_live/github_sync_component.ex b/lib/lightning_web/live/project_live/github_sync_component.ex
index c64b4a0f25..47508a2fdc 100644
--- a/lib/lightning_web/live/project_live/github_sync_component.ex
+++ b/lib/lightning_web/live/project_live/github_sync_component.ex
@@ -531,7 +531,7 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
defp verify_connection_banner(assigns) do
~H"""
-
+ Learn more about synchronizing your project with GitHub at
+ <.link
+ target="_blank"
+ href="https://docs.openfn.org/documentation/link-to-GitHub"
+ class="font-medium underline"
+ >
+ docs.openfn.org
+
+
+
+ """
+ end
+
defp build_query_params do
config = Application.fetch_env!(:lightning, :github_app)
client_id = Keyword.fetch!(config, :client_id)
diff --git a/lib/lightning_web/live/project_live/github_sync_component.ex b/lib/lightning_web/live/project_live/github_sync_component.ex
index 47508a2fdc..902181be75 100644
--- a/lib/lightning_web/live/project_live/github_sync_component.ex
+++ b/lib/lightning_web/live/project_live/github_sync_component.ex
@@ -4,6 +4,7 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
use LightningWeb, :live_component
alias Lightning.VersionControl
alias Lightning.VersionControl.ProjectRepoConnection
+ alias LightningWeb.Components.GithubComponents
alias Phoenix.LiveView.AsyncResult
alias Phoenix.LiveView.JS
diff --git a/lib/lightning_web/live/project_live/github_sync_component.html.heex b/lib/lightning_web/live/project_live/github_sync_component.html.heex
index e2db2a4255..0420e1b47e 100644
--- a/lib/lightning_web/live/project_live/github_sync_component.html.heex
+++ b/lib/lightning_web/live/project_live/github_sync_component.html.heex
@@ -12,22 +12,7 @@
- Learn more about synchronizing your project with GitHub at
- <.link
- target="_blank"
- href="https://docs.openfn.org/documentation/link-to-GitHub"
- class="font-medium underline"
- >
- docs.openfn.org
-
-
+
<.verify_connection_banner
id="verify-connection-banner"
verify_connection={@verify_connection}
diff --git a/lib/lightning_web/live/project_live/settings.html.heex b/lib/lightning_web/live/project_live/settings.html.heex
index c357f0df49..088720611e 100644
--- a/lib/lightning_web/live/project_live/settings.html.heex
+++ b/lib/lightning_web/live/project_live/settings.html.heex
@@ -74,7 +74,7 @@
else:
"Projects are isolated workspaces that contain workflows, accessible to certain users."
}
- permissions_message="basic settings, but you can export a copy."
+ permissions_message="basic settings."
can_perform_action={@can_edit_project}
/>
<.sandbox_settings_banner
@@ -807,6 +807,7 @@
Connect your OpenFn account to GitHub
+
Connect your OpenFn account to GitHub. Click the button below to get started.
@@ -825,6 +826,7 @@
Connect to GitHub
+
Version Control is not configured for this Lightning instance. Contact the superuser for more information.
diff --git a/test/lightning_web/live/project_live/github_sync_ui_test.exs b/test/lightning_web/live/project_live/github_sync_ui_test.exs
index 282f961899..d1303d8a8e 100644
--- a/test/lightning_web/live/project_live/github_sync_ui_test.exs
+++ b/test/lightning_web/live/project_live/github_sync_ui_test.exs
@@ -10,6 +10,7 @@ defmodule LightningWeb.ProjectLive.GithubSyncUiTest do
import Lightning.Factories
import Lightning.GithubHelpers
import Mox
+ import Lightning.ApplicationHelpers, only: [put_temporary_env: 3]
setup :stub_usage_limiter_ok
setup :verify_on_exit!
@@ -146,6 +147,61 @@ defmodule LightningWeb.ProjectLive.GithubSyncUiTest do
end
end
+ describe "docs banner" do
+ @banner "#github-sync-docs-banner"
+
+ test "shows in the new connection form", %{conn: conn} do
+ view = open_new_connection_form(conn)
+
+ assert has_element?(view, "#project-repo-connection-form #{@banner}")
+ end
+
+ test "shows when the user must first connect their GitHub account",
+ %{conn: conn} do
+ project = insert(:project)
+ {conn, _user} = setup_project_user(conn, project, :admin)
+
+ {:ok, view, _html} = live(conn, ~p"/projects/#{project.id}/settings#vcs")
+
+ assert has_element?(view, "#connect-github-link")
+ assert has_element?(view, @banner)
+ end
+
+ test "shows when version control is not configured on the instance",
+ %{conn: conn} do
+ put_temporary_env(:lightning, :github_app,
+ cert: nil,
+ app_id: nil,
+ app_name: nil,
+ client_id: nil,
+ client_secret: nil
+ )
+
+ project = insert(:project)
+ {conn, _user} = setup_project_user(conn, project, :viewer)
+
+ {:ok, view, html} = live(conn, ~p"/projects/#{project.id}/settings#vcs")
+
+ assert html =~ "Version Control is not configured"
+ assert has_element?(view, @banner)
+ end
+
+ test "shows on the connected panel", %{conn: conn} do
+ {view, _html} = open_connected_panel(conn, :admin, sync_version: true)
+
+ assert has_element?(view, "div.bg-white:has(h6) #{@banner}")
+ end
+
+ test "links to the sync docs", %{conn: conn} do
+ view = open_new_connection_form(conn)
+
+ assert has_element?(
+ view,
+ ~s{#{@banner} a[target="_blank"][href="https://docs.openfn.org/documentation/link-to-GitHub"]}
+ )
+ end
+ end
+
describe "connected panel" do
test "v2 connections show the title and no legacy note or config path",
%{conn: conn} do
From fdfd620932887c51e03544360b0e570cf6e46240 Mon Sep 17 00:00:00 2001
From: Joe Clark
Date: Fri, 9 Oct 2026 11:01:27 +0100
Subject: [PATCH 10/25] Add changelog entries for the Sync tab changes (#5235)
Co-Authored-By: Claude Sonnet 5.5
---
CHANGELOG.md | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7be5660640..f427d16477 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -48,6 +48,8 @@ and this project adheres to
[#5202](https://github.com/OpenFn/lightning/pull/5202)
- Index to improve the performance of the dataclip deletion query.
[#5226](https://github.com/OpenFn/lightning/issues/5226)
+- The Repository and Branch dropdowns on the GitHub sync form now have a text
+ filter. [#5235](https://github.com/OpenFn/lightning/pull/5235)
### Changed
@@ -84,6 +86,12 @@ and this project adheres to
donuts show the success rate and the failure count in their middle. Triage
rows show each failure's state and adaptor, and the step bars show each step's
adaptor. [#5229](https://github.com/OpenFn/lightning/pull/5229)
+- The project settings "Sync to GitHub" tab is now "Sync", and holds the project
+ export and a new CLI section with commands for pulling, deploying and running
+ a project locally. New GitHub connections default to the v2 `openfn.yaml`
+ format, with a switch to use the legacy format, and the connected panel now
+ carries its own title, verification banner and a "Remove integration" button.
+ [#5235](https://github.com/OpenFn/lightning/pull/5235)
### Removed
From d216e07adbd02e7d1be63dfdffdce2c00d786755 Mon Sep 17 00:00:00 2001
From: Lucy Macartney
Date: Mon, 12 Oct 2026 16:55:34 +0100
Subject: [PATCH 11/25] Use shared components on the Sync tab
The docs banner now uses the shared alert, and the format switch uses the
shared toggle. The toggle is on for openfn.yaml and off for legacy
config.json, so the custom event that flipped it is gone. The CLI
commands get copy buttons using the existing Copy hook.
---
.../components/github_components.ex | 15 ++---
.../project_live/github_sync_component.ex | 59 ++-----------------
.../github_sync_component.html.heex | 1 -
.../live/project_live/settings.html.heex | 41 +++++++------
.../live/project_live/github_sync_ui_test.exs | 32 +++++-----
5 files changed, 51 insertions(+), 97 deletions(-)
diff --git a/lib/lightning_web/components/github_components.ex b/lib/lightning_web/components/github_components.ex
index 7460cb4d46..554dd8ef2b 100644
--- a/lib/lightning_web/components/github_components.ex
+++ b/lib/lightning_web/components/github_components.ex
@@ -38,15 +38,8 @@ defmodule LightningWeb.Components.GithubComponents do
"""
def sync_docs_banner(assigns) do
~H"""
-
+
+ <:message>
Learn more about synchronizing your project with GitHub at
<.link
target="_blank"
@@ -55,8 +48,8 @@ defmodule LightningWeb.Components.GithubComponents do
>
docs.openfn.org
-
-
+
+
"""
end
diff --git a/lib/lightning_web/live/project_live/github_sync_component.ex b/lib/lightning_web/live/project_live/github_sync_component.ex
index 902181be75..728d3bc30c 100644
--- a/lib/lightning_web/live/project_live/github_sync_component.ex
+++ b/lib/lightning_web/live/project_live/github_sync_component.ex
@@ -92,24 +92,6 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
end
end
- def handle_event("toggle-legacy-format", _params, socket) do
- changeset = socket.assigns.changeset
- current = Ecto.Changeset.get_field(changeset, :sync_version)
-
- # Form fields read from the changeset's params before its changes, so the
- # flip has to go through the params, like the "validate" event does.
- params =
- (changeset.params || %{})
- |> Map.put("project_id", socket.assigns.project.id)
- |> Map.put("sync_version", to_string(!current))
-
- {:noreply,
- assign(socket,
- changeset:
- validate_changes(socket.assigns.project_repo_connection, params)
- )}
- end
-
def handle_event("refresh-installations", _params, socket) do
changeset = validate_changes(socket.assigns.project_repo_connection, %{})
user = socket.assigns.user
@@ -752,45 +734,16 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
attr :form, :map, required: true
attr :project_id, :string, required: true
- attr :myself, :any, required: true
- # Inverted: sync_version is true (v2) unless the legacy switch is on. The
- # hidden input carries the current value with the form's phx-change events.
defp config_format_toggle(assigns) do
- assigns = assign(assigns, :legacy?, !sync_version?(assigns.form))
-
~H"""
-
-
+ <.input
+ id="sync-version-toggle"
+ type="toggle"
+ field={@form[:sync_version]}
+ label="Use openfn.yaml format (turn off for legacy config.json)"
/>
-
-
- Use legacy YAML config format
-
diff --git a/test/lightning_web/live/project_live/github_sync_ui_test.exs b/test/lightning_web/live/project_live/github_sync_ui_test.exs
index d1303d8a8e..a3f9944b5e 100644
--- a/test/lightning_web/live/project_live/github_sync_ui_test.exs
+++ b/test/lightning_web/live/project_live/github_sync_ui_test.exs
@@ -20,8 +20,7 @@ defmodule LightningWeb.ProjectLive.GithubSyncUiTest do
"account" => %{"type" => "User", "login" => "username"}
}
- @switch "#toggle-legacy-format-switch"
- @sync_version_input ~s{input[name="connection[sync_version]"]}
+ @switch "#sync-version-toggle"
defp open_new_connection_form(conn) do
project = insert(:project)
@@ -97,32 +96,36 @@ defmodule LightningWeb.ProjectLive.GithubSyncUiTest do
refute has_element?(view, "#select-installations-input-searchable")
end
- test "defaults to the v2 format with the legacy switch off", %{conn: conn} do
+ test "defaults to the openfn.yaml format with the switch on",
+ %{conn: conn} do
view = open_new_connection_form(conn)
- assert has_element?(view, "#{@switch}[aria-checked=false]")
- assert has_element?(view, ~s{#{@sync_version_input}[value=true]})
+ assert has_element?(view, "#{@switch}[checked]")
end
- test "flipping the switch selects the legacy format and flips it back",
+ test "turning the switch off selects the legacy format and back on again",
%{conn: conn} do
view = open_new_connection_form(conn)
- view |> element(@switch) |> render_click()
+ view
+ |> form("#project-repo-connection-form")
+ |> render_change(connection: %{sync_version: "false"})
- assert has_element?(view, "#{@switch}[aria-checked=true]")
- assert has_element?(view, ~s{#{@sync_version_input}[value=false]})
+ refute has_element?(view, "#{@switch}[checked]")
- view |> element(@switch) |> render_click()
+ view
+ |> form("#project-repo-connection-form")
+ |> render_change(connection: %{sync_version: "true"})
- assert has_element?(view, "#{@switch}[aria-checked=false]")
- assert has_element?(view, ~s{#{@sync_version_input}[value=true]})
+ assert has_element?(view, "#{@switch}[checked]")
end
test "the legacy choice survives changing a dropdown", %{conn: conn} do
view = open_new_connection_form(conn)
- view |> element(@switch) |> render_click()
+ view
+ |> form("#project-repo-connection-form")
+ |> render_change(connection: %{sync_version: "false"})
view
|> form("#project-repo-connection-form")
@@ -130,8 +133,7 @@ defmodule LightningWeb.ProjectLive.GithubSyncUiTest do
connection: %{github_installation_id: @installation["id"]}
)
- assert has_element?(view, "#{@switch}[aria-checked=true]")
- assert has_element?(view, ~s{#{@sync_version_input}[value=false]})
+ refute has_element?(view, "#{@switch}[checked]")
end
test "the switch is hidden when importing from GitHub", %{conn: conn} do
From cdb5061e4dfcf139c18933bbed4e4d023d47729d Mon Sep 17 00:00:00 2001
From: Lucy Macartney
Date: Mon, 12 Oct 2026 17:03:40 +0100
Subject: [PATCH 12/25] Tone down the GitHub sync confirm box
The box was bright amber, and on import it set amber and red backgrounds at once. It now uses pale yellow or pale red with a border, smaller text, and file paths that wrap under their icon.
---
.../project_live/github_sync_component.ex | 32 +++++++++++--------
1 file changed, 19 insertions(+), 13 deletions(-)
diff --git a/lib/lightning_web/live/project_live/github_sync_component.ex b/lib/lightning_web/live/project_live/github_sync_component.ex
index 728d3bc30c..7664d7f15b 100644
--- a/lib/lightning_web/live/project_live/github_sync_component.ex
+++ b/lib/lightning_web/live/project_live/github_sync_component.ex
@@ -821,8 +821,11 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
defp accept_checkbox(assigns) do
~H"""
<.input
type="checkbox"
@@ -830,7 +833,7 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
required="true"
hidden_input={false}
/>
-
+
I understand that
<%= if @form[:sync_direction].value == :deploy do %>
my current OpenFn project will be destroyed and
@@ -838,25 +841,28 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
the following files will be committed to <%= @form[
:repo
].value %>:
-
-
-
+
+
Connect your OpenFn account to GitHub. Click the button below to get started.
-
+
<% end %>
<% else %>
-
+
Connect to GitHub
-
-
+
+
Version Control is not configured for this Lightning instance. Contact the superuser for more information.
From 95eece7aefb3ce286426f2acbad858be40240e32 Mon Sep 17 00:00:00 2001
From: Lucy Macartney
Date: Mon, 12 Oct 2026 17:12:25 +0100
Subject: [PATCH 14/25] Add copy feedback to the CLI commands on the Sync tab
The copy buttons sit in a tooltip wrapper, so hovering shows "Copy to
clipboard" and clicking shows "Copied!". They also get a pointer cursor and
a centred icon.
---
.../live/project_live/settings.html.heex | 22 ++++++++++++-------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/lib/lightning_web/live/project_live/settings.html.heex b/lib/lightning_web/live/project_live/settings.html.heex
index 4b1603f62a..044f4d8146 100644
--- a/lib/lightning_web/live/project_live/settings.html.heex
+++ b/lib/lightning_web/live/project_live/settings.html.heex
@@ -868,16 +868,22 @@
{label}
{command}
-
+
+
From 082193b772d4cb1b7ce9e287c6f933865dff118d Mon Sep 17 00:00:00 2001
From: Lucy Macartney
Date: Mon, 12 Oct 2026 17:19:05 +0100
Subject: [PATCH 15/25] Centre the connection check banner on the Sync tab
---
lib/lightning_web/live/project_live/github_sync_component.ex | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/lightning_web/live/project_live/github_sync_component.ex b/lib/lightning_web/live/project_live/github_sync_component.ex
index 8188a81b15..73dbee7403 100644
--- a/lib/lightning_web/live/project_live/github_sync_component.ex
+++ b/lib/lightning_web/live/project_live/github_sync_component.ex
@@ -597,8 +597,8 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
- Choose how to handle setup: you can export this project to GitHub, or import an existing project on GitHub here.
+ Export this project to GitHub, or replace it with a project that's already on GitHub.
- <%= if f[:branch].value do %>
+ <%= if f[:branch].value not in [nil, ""] do %>
<.accept_checkbox
project={@project}
form={f}
diff --git a/test/lightning_web/live/project_live/github_sync_ui_test.exs b/test/lightning_web/live/project_live/github_sync_ui_test.exs
index 54af23ead5..8ab6cb7735 100644
--- a/test/lightning_web/live/project_live/github_sync_ui_test.exs
+++ b/test/lightning_web/live/project_live/github_sync_ui_test.exs
@@ -147,6 +147,25 @@ defmodule LightningWeb.ProjectLive.GithubSyncUiTest do
refute has_element?(view, @switch)
end
+
+ test "the confirm box waits until a branch is picked", %{conn: conn} do
+ view = open_new_connection_form(conn)
+ confirm = ~s{input[name="connection[accept]"]}
+
+ view
+ |> form("#project-repo-connection-form")
+ |> render_change(
+ connection: %{github_installation_id: @installation["id"]}
+ )
+
+ refute has_element?(view, confirm)
+
+ view
+ |> form("#project-repo-connection-form")
+ |> render_change(connection: %{branch: "main"})
+
+ assert has_element?(view, confirm)
+ end
end
describe "docs banner" do
From 82a6a3b92c1f61a23fe6820c060881a1e41f7f45 Mon Sep 17 00:00:00 2001
From: Lucy Macartney
Date: Mon, 12 Oct 2026 18:18:29 +0100
Subject: [PATCH 18/25] Bring back the legacy format switch on the Sync tab
The shared toggle could only mean "use openfn.yaml", which read the wrong
way round. This restores the hand-built switch, where on means the legacy
format.
---
.../project_live/github_sync_component.ex | 59 +++++++++++++++++--
.../github_sync_component.html.heex | 1 +
.../live/project_live/github_sync_ui_test.exs | 32 +++++-----
3 files changed, 69 insertions(+), 23 deletions(-)
diff --git a/lib/lightning_web/live/project_live/github_sync_component.ex b/lib/lightning_web/live/project_live/github_sync_component.ex
index 332ab69e4d..466965cd7c 100644
--- a/lib/lightning_web/live/project_live/github_sync_component.ex
+++ b/lib/lightning_web/live/project_live/github_sync_component.ex
@@ -92,6 +92,24 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
end
end
+ def handle_event("toggle-legacy-format", _params, socket) do
+ changeset = socket.assigns.changeset
+ current = Ecto.Changeset.get_field(changeset, :sync_version)
+
+ # Form fields read from the changeset's params before its changes, so the
+ # flip has to go through the params, like the "validate" event does.
+ params =
+ (changeset.params || %{})
+ |> Map.put("project_id", socket.assigns.project.id)
+ |> Map.put("sync_version", to_string(!current))
+
+ {:noreply,
+ assign(socket,
+ changeset:
+ validate_changes(socket.assigns.project_repo_connection, params)
+ )}
+ end
+
def handle_event("refresh-installations", _params, socket) do
changeset = validate_changes(socket.assigns.project_repo_connection, %{})
user = socket.assigns.user
@@ -734,16 +752,45 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
attr :form, :map, required: true
attr :project_id, :string, required: true
+ attr :myself, :any, required: true
+ # Inverted: sync_version is true (v2) unless the legacy switch is on. The
+ # hidden input carries the current value with the form's phx-change events.
defp config_format_toggle(assigns) do
+ assigns = assign(assigns, :legacy?, !sync_version?(assigns.form))
+
~H"""
-
- <.input
- id="sync-version-toggle"
- type="toggle"
- field={@form[:sync_version]}
- label="Use openfn.yaml format (turn off for legacy config.json)"
+
<.input
type="text"
field={f[:config_path]}
- label="Path to config (required)"
+ label={
+ if f[:sync_direction].value == :deploy,
+ do: "Path to config (required)",
+ else: "Path to config (optional)"
+ }
placeholder={"./openfn-#{@project.id}-config.json"}
class="placeholder:italic placeholder:text-slate-400"
/>
diff --git a/test/lightning/version_control/project_repo_connection_test.exs b/test/lightning/version_control/project_repo_connection_test.exs
index 92cd7e57d4..77b8ac4ced 100644
--- a/test/lightning/version_control/project_repo_connection_test.exs
+++ b/test/lightning/version_control/project_repo_connection_test.exs
@@ -233,6 +233,58 @@ defmodule Lightning.VersionControl.ProjectRepoConnectionTest do
end
end
+ describe "config path when importing from GitHub (configure_changeset/2)" do
+ setup do
+ %{
+ attrs: %{
+ project_id: insert(:project).id,
+ repo: "openfn/example",
+ branch: "main",
+ github_installation_id: "1234",
+ sync_direction: "deploy",
+ accept: true
+ }
+ }
+ end
+
+ test "a legacy import needs a path to config", %{attrs: attrs} do
+ changeset =
+ ProjectRepoConnection.configure_changeset(
+ %ProjectRepoConnection{},
+ Map.put(attrs, :sync_version, false)
+ )
+
+ refute changeset.valid?
+
+ assert {"you must specify a path to an existing config file", _} =
+ changeset.errors[:config_path]
+ end
+
+ test "a legacy import is valid with a path", %{attrs: attrs} do
+ changeset =
+ ProjectRepoConnection.configure_changeset(
+ %ProjectRepoConnection{},
+ Map.merge(attrs, %{sync_version: false, config_path: "./config.json"})
+ )
+
+ assert changeset.valid?
+ end
+
+ test "a v2 import needs no path and uses openfn.yaml", %{attrs: attrs} do
+ changeset =
+ ProjectRepoConnection.configure_changeset(
+ %ProjectRepoConnection{},
+ Map.put(attrs, :sync_version, true)
+ )
+
+ assert changeset.valid?
+
+ assert ProjectRepoConnection.config_path(
+ Ecto.Changeset.apply_changes(changeset)
+ ) == "openfn.yaml"
+ end
+ end
+
describe "tree_branch_conflict?/4" do
test "returns false when no other connection in the tree uses the (repo, branch)" do
root = insert(:project)
diff --git a/test/lightning_web/live/project_live/github_sync_ui_test.exs b/test/lightning_web/live/project_live/github_sync_ui_test.exs
index b7c691281f..607f3635a2 100644
--- a/test/lightning_web/live/project_live/github_sync_ui_test.exs
+++ b/test/lightning_web/live/project_live/github_sync_ui_test.exs
@@ -22,6 +22,7 @@ defmodule LightningWeb.ProjectLive.GithubSyncUiTest do
@switch "#toggle-legacy-format-switch"
@sync_version_input ~s{input[name="connection[sync_version]"]}
+ @config_path_input ~s{input[name="connection[config_path]"]}
defp open_new_connection_form(conn) do
project = insert(:project)
@@ -134,16 +135,73 @@ defmodule LightningWeb.ProjectLive.GithubSyncUiTest do
assert has_element?(view, ~s{#{@sync_version_input}[value=false]})
end
- test "the switch is hidden when importing from GitHub", %{conn: conn} do
+ test "the switch stays visible when importing from GitHub", %{conn: conn} do
view = open_new_connection_form(conn)
+ view
+ |> form("#project-repo-connection-form")
+ |> render_change(connection: %{sync_direction: "deploy"})
+
assert has_element?(view, @switch)
+ end
+
+ test "a v2 import has no path to config input", %{conn: conn} do
+ view = open_new_connection_form(conn)
view
|> form("#project-repo-connection-form")
|> render_change(connection: %{sync_direction: "deploy"})
- refute has_element?(view, @switch)
+ assert has_element?(view, "#{@switch}[aria-checked=false]")
+ refute has_element?(view, @config_path_input)
+ end
+
+ test "a legacy import asks for the path to config", %{conn: conn} do
+ view = open_new_connection_form(conn)
+
+ view
+ |> form("#project-repo-connection-form")
+ |> render_change(connection: %{sync_direction: "deploy"})
+
+ view |> element(@switch) |> render_click()
+
+ assert has_element?(view, @config_path_input)
+
+ view |> element(@switch) |> render_click()
+
+ refute has_element?(view, @config_path_input)
+ end
+
+ test "an export-first v2 sync has no path to config", %{conn: conn} do
+ view = open_new_connection_form(conn)
+
+ refute has_element?(view, @config_path_input)
+ end
+
+ test "an export-first legacy sync shows an optional path to config",
+ %{conn: conn} do
+ view = open_new_connection_form(conn)
+
+ view |> element(@switch) |> render_click()
+
+ assert has_element?(view, @config_path_input)
+ assert render(view) =~ "Path to config (optional)"
+
+ view |> element(@switch) |> render_click()
+
+ refute has_element?(view, @config_path_input)
+ end
+
+ test "a legacy import marks the path to config as required", %{conn: conn} do
+ view = open_new_connection_form(conn)
+
+ view
+ |> form("#project-repo-connection-form")
+ |> render_change(connection: %{sync_direction: "deploy"})
+
+ view |> element(@switch) |> render_click()
+
+ assert render(view) =~ "Path to config (required)"
end
test "the confirm box waits until a branch is picked", %{conn: conn} do
From c2db6fcf5893f880613cd2d3677349af8a256073 Mon Sep 17 00:00:00 2001
From: Joe Clark
Date: Tue, 13 Oct 2026 11:09:03 +0100
Subject: [PATCH 20/25] tooltip for legacy formats
---
.../live/project_live/github_sync_component.ex | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/lib/lightning_web/live/project_live/github_sync_component.ex b/lib/lightning_web/live/project_live/github_sync_component.ex
index e8b7612e58..8267ab14d2 100644
--- a/lib/lightning_web/live/project_live/github_sync_component.ex
+++ b/lib/lightning_web/live/project_live/github_sync_component.ex
@@ -4,6 +4,7 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
use LightningWeb, :live_component
alias Lightning.VersionControl
alias Lightning.VersionControl.ProjectRepoConnection
+ alias LightningWeb.Components.Common
alias LightningWeb.Components.GithubComponents
alias Phoenix.LiveView.AsyncResult
alias Phoenix.LiveView.JS
@@ -760,7 +761,13 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
assigns = assign(assigns, :legacy?, !sync_version?(assigns.form))
~H"""
-
+
Use legacy formats (config.json)
-
+
"""
end
From 8153983ed30839f7b4c5d7dd9dacebc81387c8ba Mon Sep 17 00:00:00 2001
From: Joe Clark
Date: Tue, 13 Oct 2026 11:25:08 +0100
Subject: [PATCH 21/25] better UI if permissions are disabled
---
.../live/project_live/settings.html.heex | 22 ++++-
.../live/project_live/github_sync_ui_test.exs | 81 +++++++++++++++++++
2 files changed, 101 insertions(+), 2 deletions(-)
diff --git a/lib/lightning_web/live/project_live/settings.html.heex b/lib/lightning_web/live/project_live/settings.html.heex
index 7dda06102a..ed3ce0f234 100644
--- a/lib/lightning_web/live/project_live/settings.html.heex
+++ b/lib/lightning_web/live/project_live/settings.html.heex
@@ -744,8 +744,6 @@
<.section_header
title="Sync"
subtitle="Sync your project with GitHub, export it, or work on it with the CLI."
- permissions_message={"version control configuration#{@can_initiate_github_sync && " but you can initiate a sync." || "."}"}
- can_perform_action={@can_install_github}
/>
<.sandbox_settings_banner
:if={@sandbox?}
@@ -779,6 +777,26 @@
}
/>
<% else %>
+
+
+ Configure two-way sync to GitHub
+
+
+ <:message>
+ Role based permissions: You cannot modify this project's version control configuration{if @can_initiate_github_sync,
+ do: " but you can initiate a sync.",
+ else: "."}
+
+
+
<.live_component
:if={user_has_valid_oauth_token(@current_user)}
diff --git a/test/lightning_web/live/project_live/github_sync_ui_test.exs b/test/lightning_web/live/project_live/github_sync_ui_test.exs
index 607f3635a2..05422de3dd 100644
--- a/test/lightning_web/live/project_live/github_sync_ui_test.exs
+++ b/test/lightning_web/live/project_live/github_sync_ui_test.exs
@@ -279,6 +279,87 @@ defmodule LightningWeb.ProjectLive.GithubSyncUiTest do
end
end
+ describe "permissions banner" do
+ @permissions_banner "#vcs-permissions-banner"
+
+ defp open_sync_tab(conn, role) do
+ project = insert(:project)
+ {conn, _user} = setup_project_user(conn, project, role)
+
+ {:ok, view, _html} = live(conn, ~p"/projects/#{project.id}/settings#vcs")
+ view
+ end
+
+ test "viewers are told they can't change the connection", %{conn: conn} do
+ view = open_sync_tab(conn, :viewer)
+
+ assert has_element?(
+ view,
+ @permissions_banner,
+ "You cannot modify this project's version control configuration."
+ )
+
+ refute render(view) =~ "but you can initiate a sync"
+ end
+
+ test "editors are told they can still initiate a sync", %{conn: conn} do
+ view = open_sync_tab(conn, :editor)
+
+ assert has_element?(
+ view,
+ @permissions_banner,
+ "version control configuration but you can initiate a sync."
+ )
+ end
+
+ test "admins see no permissions banner", %{conn: conn} do
+ view = open_sync_tab(conn, :admin)
+
+ refute has_element?(view, @permissions_banner)
+ end
+
+ test "the message sits in a plain box where the form would be",
+ %{conn: conn} do
+ view = open_sync_tab(conn, :viewer)
+
+ assert has_element?(
+ view,
+ "#vcs-permissions-box h6",
+ "Configure two-way sync to GitHub"
+ )
+
+ assert has_element?(
+ view,
+ "#vcs-permissions-box #vcs-permissions-banner"
+ )
+
+ # the real form is not rendered, so nothing calls GitHub
+ refute has_element?(view, "#project-repo-connection-form")
+ refute has_element?(view, "#connect-github-link")
+ end
+
+ test "admins get the real form and no permissions box", %{conn: conn} do
+ view = open_new_connection_form(conn)
+
+ refute has_element?(view, "#vcs-permissions-box")
+ assert has_element?(view, "#project-repo-connection-form")
+ end
+
+ test "a connected project shows its connection, not the box",
+ %{conn: conn} do
+ {view, _html} = open_connected_panel(conn, :editor, sync_version: true)
+
+ assert has_element?(view, "h6", "Connected to GitHub")
+ refute has_element?(view, "#vcs-permissions-box")
+ end
+
+ test "the message no longer sits in the section header", %{conn: conn} do
+ view = open_sync_tab(conn, :viewer)
+
+ refute has_element?(view, "#vcs-panel small.text-red-700")
+ end
+ end
+
describe "connected panel" do
test "v2 connections show the title and no legacy note or config path",
%{conn: conn} do
From d63f065f0c5670400a22df041ccdd69075033104 Mon Sep 17 00:00:00 2001
From: Joe Clark
Date: Tue, 13 Oct 2026 11:35:12 +0100
Subject: [PATCH 22/25] link to more docs
---
.../live/project_live/settings.html.heex | 10 ++++++++++
.../live/project_live/github_sync_ui_test.exs | 12 ++++++++++++
2 files changed, 22 insertions(+)
diff --git a/lib/lightning_web/live/project_live/settings.html.heex b/lib/lightning_web/live/project_live/settings.html.heex
index ed3ce0f234..cbe5938184 100644
--- a/lib/lightning_web/live/project_live/settings.html.heex
+++ b/lib/lightning_web/live/project_live/settings.html.heex
@@ -910,6 +910,16 @@
<:panel hash="data-storage" class="space-y-4">
diff --git a/test/lightning_web/live/project_live/github_sync_ui_test.exs b/test/lightning_web/live/project_live/github_sync_ui_test.exs
index 05422de3dd..656aafc2bd 100644
--- a/test/lightning_web/live/project_live/github_sync_ui_test.exs
+++ b/test/lightning_web/live/project_live/github_sync_ui_test.exs
@@ -279,6 +279,18 @@ defmodule LightningWeb.ProjectLive.GithubSyncUiTest do
end
end
+ describe "CLI card" do
+ test "links to more CLI examples", %{conn: conn} do
+ view = open_sync_tab(conn, :viewer)
+
+ assert has_element?(
+ view,
+ ~s{#cli-more-examples-link[target="_blank"][href="https://docs.openfn.org/documentation/cli-usage"]},
+ "See more CLI examples"
+ )
+ end
+ end
+
describe "permissions banner" do
@permissions_banner "#vcs-permissions-banner"
From 5e8ea0a3f2ebd118e2dc39be595817401086e7c4 Mon Sep 17 00:00:00 2001
From: Joe Clark
Date: Wed, 14 Oct 2026 10:32:56 +0100
Subject: [PATCH 23/25] wording tweaks
---
lib/lightning_web/live/project_live/settings.html.heex | 4 ++--
test/lightning_web/live/project_live/github_sync_ui_test.exs | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/lightning_web/live/project_live/settings.html.heex b/lib/lightning_web/live/project_live/settings.html.heex
index cbe5938184..dcce5a3f23 100644
--- a/lib/lightning_web/live/project_live/settings.html.heex
+++ b/lib/lightning_web/live/project_live/settings.html.heex
@@ -869,7 +869,7 @@
Sync with CLI
- Use the OpenFn CLI to work on this project on your computer. Learn more in the <.link
+ Use the OpenFn CLI to download, deploy and execute workflows in this project. Learn more in the <.link
target="_blank"
href="https://docs.openfn.org/documentation/sync"
class="font-medium text-indigo-600 hover:text-indigo-900"
@@ -917,7 +917,7 @@
href="https://docs.openfn.org/documentation/cli-usage"
class="font-medium text-indigo-600 hover:text-indigo-900"
>
- See more CLI examples
+ See more CLI commands
diff --git a/test/lightning_web/live/project_live/github_sync_ui_test.exs b/test/lightning_web/live/project_live/github_sync_ui_test.exs
index 656aafc2bd..42e14f6cc9 100644
--- a/test/lightning_web/live/project_live/github_sync_ui_test.exs
+++ b/test/lightning_web/live/project_live/github_sync_ui_test.exs
@@ -286,7 +286,7 @@ defmodule LightningWeb.ProjectLive.GithubSyncUiTest do
assert has_element?(
view,
~s{#cli-more-examples-link[target="_blank"][href="https://docs.openfn.org/documentation/cli-usage"]},
- "See more CLI examples"
+ "See more CLI commands"
)
end
end
From bf9a41bbc5f01071cc455dd3b23ceaf8e793e407 Mon Sep 17 00:00:00 2001
From: Joe Clark
Date: Wed, 14 Oct 2026 10:39:27 +0100
Subject: [PATCH 24/25] more wording tweaks
---
.../live/project_live/github_sync_component.ex | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/lib/lightning_web/live/project_live/github_sync_component.ex b/lib/lightning_web/live/project_live/github_sync_component.ex
index 8267ab14d2..41905ce532 100644
--- a/lib/lightning_web/live/project_live/github_sync_component.ex
+++ b/lib/lightning_web/live/project_live/github_sync_component.ex
@@ -812,10 +812,10 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
~H"""
<.label>
- Initial Setup Action
+ Initial Setup
- Export this project to GitHub, or replace it with a project that's already on GitHub.
+ Choose the direction of the first sync: export this project to GitHub, or import an existing project from GitHub.
@@ -858,7 +858,7 @@ defmodule LightningWeb.ProjectLive.GithubSyncComponent do
Import from GitHub (overwrite this project)
- This option will replace this project with the workflows, collections and channels that are already committed to GitHub.
+ Replace this OpenFn project with the workflows, collections and channels that are already committed to GitHub.
From 11b3d8e1515c1694975caff7c195aa7674ba11b8 Mon Sep 17 00:00:00 2001
From: Joe Clark
Date: Wed, 14 Oct 2026 10:54:11 +0100
Subject: [PATCH 25/25] add PAT note
---
.../live/project_live/settings.html.heex | 12 ++++++++++++
.../live/project_live/github_sync_ui_test.exs | 15 +++++++++++++++
2 files changed, 27 insertions(+)
diff --git a/lib/lightning_web/live/project_live/settings.html.heex b/lib/lightning_web/live/project_live/settings.html.heex
index dcce5a3f23..245ad064e0 100644
--- a/lib/lightning_web/live/project_live/settings.html.heex
+++ b/lib/lightning_web/live/project_live/settings.html.heex
@@ -877,6 +877,18 @@
CLI sync docs.
+
+ <:message>
+ You'll need to configure a Personal Access Token and add it to your environment for these commands to work: see
+ <.link
+ target="_blank"
+ href="https://docs.openfn.org/documentation/sync#authorization"
+ class="font-medium underline"
+ >
+ Authorization docs
+
+
+