Skip to content

Settings: split into General / Work / Make repo / Advanced sub-tabs - #37

Merged
tpaulshippy merged 1 commit into
mainfrom
settings-subtabs
Oct 20, 2026
Merged

tpaulshippy merged 1 commit into
mainfrom
settings-subtabs

Conversation

@tpaulshippy

@tpaulshippy tpaulshippy commented Oct 20, 2026 •

Copy link
Copy Markdown
Owner

The Settings tab was 10 workflows stacked flat (API key, gateway, login, sharing, open repo, branches, create, promote, repo list, commit, raw git) — worst at the bottom on mobile.

This splits it into 4 sub-tabs by intent:

  • General — model setup (API key, gateway), GitHub account (login/out, token details collapsed behind disclosure), Sharing
  • Work — open repo + repo list in one card, branches (picker, switch, new proto branch), save (commit+push, pull, status, log)
  • Make repo — new repo from current files, and promote-branch-to-new-repo (keep history), as separate cards with labeled checkboxes
  • Advanced — delete branch + run raw git, behind a warning

Draft inputs persist across tab switches via ghDraft (previously every render wiped them). Token scopes collapsed; Refresh branches, Delete branch, Remote-only strings preserved.

Work / Make repo / Advanced show a login gate when logged out and unlock after GitHub login. Verified: tsc --noEmit clean, 352/352 tests pass.

settings-general

settings-mobile


Summary by cubic

Restructures the Settings tab from a flat 10-workflow stack into 4 sub-tabs grouped by intent — General (model setup, GitHub account, sharing), Work (open repo, branches, save), Make repo (create, promote), Advanced (delete branch, raw git) — so workflows are reachable without scrolling past everything else.

  • The active tab persists across reloads and defaults to Work once logged in.
  • Draft form inputs (repo names, commit message, branch name, checkboxes) survive tab switches via shared draft state; previously every re-render wiped them.
  • Token scopes and granted scopes are collapsed into a "token details" disclosure; the missing-workflow-scope and GitHub-App warnings remain visible.
  • Work, Make repo, and Advanced show a login gate when logged out and unlock after GitHub login.
  • Delete branch moved to Advanced with its input pre-filled from the last selected branch, and the direct Refresh branches button on the Work tab now refreshes the list without needing the picker.

Written for commit 977c1da. Summary will update on new commits.

View guided diff Turn on auto-fix

settings-linked-work

settings-linked-make-repo

settings-linked-advanced

Linked-tab shots use representative fixture data (same components, no OAuth in the screenshot env).

- Flat 10-workflow stack becomes 4 tabbed workflows
- Make repo (not Publish) holds Create + Promote cards
- Advanced isolates Delete branch + Run raw git
- Draft inputs persist across tab switches via ghDraft
- Token scopes collapsed behind details element

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

4 issues found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/index.ts">

<violation number="1" location="src/index.ts:3705">
P2: The selected branch draft is not scoped to the linked repository. Opening another repo leaves the old branch name in `ghDraft.pickedBranch`, so Advanced can prefill and submit a branch from the previous repo; reset branch/delete drafts when the repo changes.</violation>

<violation number="2" location="src/index.ts:3966">
P2: Draft fields now survive successful actions and are never cleared. After a promote, 'delete source branch' and 'include uncommitted' stay checked, and the completed repo name and commit message also remain. Clear the matching `ghDraft` fields on success in ghCreate, ghPromote, and ghCommitPush.</violation>

<violation number="3" location="src/index.ts:3999">
P2: Typing a branch into an initially empty delete field never enables `Delete branch` because the button's disabled state is calculated only during render. Recompute `delBtn.disabled` from `din.value` in the input handler.</violation>

<violation number="4" location="src/index.ts:4042">
P2: On the General tab, the Model API key and gateway controls render only after GitHub status loads. If `/api/github/status` fails or is still loading, the key input is missing, so BYOK users cannot set a key. Render the model setup section before the status-gated early return.</violation>
</file>

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread src/index.ts
const pdel = document.createElement("input");
pdel.type = "checkbox"; pdel.title = "delete source branch after promote";
pdel.checked = !!ghDraft.promoteDel;
pdel.onchange = () => { ghDraft.promoteDel = pdel.checked; };

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Draft fields now survive successful actions and are never cleared. After a promote, 'delete source branch' and 'include uncommitted' stay checked, and the completed repo name and commit message also remain. Clear the matching ghDraft fields on success in ghCreate, ghPromote, and ghCommitPush.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At src/index.ts, line 3966:

<comment>Draft fields now survive successful actions and are never cleared. After a promote, 'delete source branch' and 'include uncommitted' stay checked, and the completed repo name and commit message also remain. Clear the matching `ghDraft` fields on success in ghCreate, ghPromote, and ghCommitPush.</comment>

<file context>
@@ -3737,198 +3797,277 @@ function renderGitHub() {
+  const pdel = document.createElement("input");
+  pdel.type = "checkbox"; pdel.title = "delete source branch after promote";
+  pdel.checked = !!ghDraft.promoteDel;
+  pdel.onchange = () => { ghDraft.promoteDel = pdel.checked; };
+  pdelLbl.appendChild(pdel);
+  pdelLbl.appendChild(document.createTextNode("delete source branch"));
</file context>

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in #38: ghCreate/ghPromote/ghCommitPush (and ghNewBranch) now clear their ghDraft fields on success. Covered by the new served-page needles test in tests/branches.test.ts.

Comment thread src/index.ts
runB.onclick = () => ghRunCmd(cmd.value);
qrow.appendChild(cmd); qrow.appendChild(runB);
wrap.appendChild(qrow);
if (tab === "general") renderSharing(wrap);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: On the General tab, the Model API key and gateway controls render only after GitHub status loads. If /api/github/status fails or is still loading, the key input is missing, so BYOK users cannot set a key. Render the model setup section before the status-gated early return.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At src/index.ts, line 4042:

<comment>On the General tab, the Model API key and gateway controls render only after GitHub status loads. If `/api/github/status` fails or is still loading, the key input is missing, so BYOK users cannot set a key. Render the model setup section before the status-gated early return.</comment>

<file context>
@@ -3737,198 +3797,277 @@ function renderGitHub() {
-    runB.onclick = () => ghRunCmd(cmd.value);
-    qrow.appendChild(cmd); qrow.appendChild(runB);
-    wrap.appendChild(qrow);
+    if (tab === "general") renderSharing(wrap);
+    if (ghMsg) wrap.appendChild(el("pre", "out", ghMsg));
+    pane.appendChild(wrap);
</file context>

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in #38: model setup extracted to renderGhModelSetup and rendered before the status-gated early return, restoring the pre-split behavior where BYOK users always see the key field. Covered by the needles test.

Comment thread src/index.ts
din.type = "text"; din.placeholder = "branch, e.g. proto/my-prototype";
din.setAttribute("aria-label", "Branch to delete");
din.value = ghDraft.delBranch || (ghDraft.pickedBranch || "");
din.oninput = () => { ghDraft.delBranch = din.value; };

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: Typing a branch into an initially empty delete field never enables Delete branch because the button's disabled state is calculated only during render. Recompute delBtn.disabled from din.value in the input handler.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At src/index.ts, line 3999:

<comment>Typing a branch into an initially empty delete field never enables `Delete branch` because the button's disabled state is calculated only during render. Recompute `delBtn.disabled` from `din.value` in the input handler.</comment>

<file context>
@@ -3737,198 +3797,277 @@ function renderGitHub() {
+  din.type = "text"; din.placeholder = "branch, e.g. proto/my-prototype";
+  din.setAttribute("aria-label", "Branch to delete");
+  din.value = ghDraft.delBranch || (ghDraft.pickedBranch || "");
+  din.oninput = () => { ghDraft.delBranch = din.value; };
+  const delBtn = el("button", null, "Delete branch");
+  delBtn.disabled = ghBusy || !linked || !(din.value || "").trim();
</file context>
Suggested change
din.oninput = () => { ghDraft.delBranch = din.value; };
din.oninput = () => {
ghDraft.delBranch = din.value;
delBtn.disabled = ghBusy || !linked || !(din.value || "").trim();
};

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in #38: the Advanced delete row now recomputes delBtn.disabled from the input value in the input handler (syncDelBtn). Covered by the needles test.

Comment thread src/index.ts
const label = (b.current ? "● " : "") + b.name + (b.remote && !list.some((x) => x.name === b.name && !x.remote) ? " (remote)" : "");
const o = el("option", null, label);
o.value = b.name;
if (ghDraft.pickedBranch) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: The selected branch draft is not scoped to the linked repository. Opening another repo leaves the old branch name in ghDraft.pickedBranch, so Advanced can prefill and submit a branch from the previous repo; reset branch/delete drafts when the repo changes.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At src/index.ts, line 3705:

<comment>The selected branch draft is not scoped to the linked repository. Opening another repo leaves the old branch name in `ghDraft.pickedBranch`, so Advanced can prefill and submit a branch from the previous repo; reset branch/delete drafts when the repo changes.</comment>

<file context>
@@ -3628,11 +3666,73 @@ function ghIsRemoteOnly(name) {
+      const label = (b.current ? "● " : "") + b.name + (b.remote && !list.some((x) => x.name === b.name && !x.remote) ? " (remote)" : "");
+      const o = el("option", null, label);
+      o.value = b.name;
+      if (ghDraft.pickedBranch) {
+        if (b.name === ghDraft.pickedBranch) o.selected = true;
+      } else if (b.current || (!cur && ghStatus && ghStatus.linked && b.name === ghStatus.linked.branch)) o.selected = true;
</file context>

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in #38: ghResetBranches now clears pickedBranch/delBranch (runs on open/create/promote/logout), and switch/new/delete track the picked branch, so drafts never leak across repos. Covered by the needles test.

@tpaulshippy
tpaulshippy merged commit 5683f87 into main Oct 20, 2026
3 checks passed
@tpaulshippy
tpaulshippy deleted the settings-subtabs branch October 20, 2026 02:59
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.

1 participant