Skip to content

feat(create-from,github): materialize sheet + GitHub label/assignee pickers (G16, G18) - #74

Merged
Adron merged 2 commits into
mainfrom
feat/create-from-and-github-depth
Sep 14, 2026
Merged

Adron merged 2 commits into
mainfrom
feat/create-from-and-github-depth

Conversation

@Adron

@Adron Adron commented Sep 14, 2026

Copy link
Copy Markdown
Member

Closes #45. Lands Thread C — G16 "Create from…" (materialize) and G18 GitHub metadata depth — which had been written but never opened as a PR.

What's here

One commit, 22 files (+2,704 / −45), rebased from its original base (629662c) onto current main (4e168a2).

  • G16POST /api/materialize. Models/Materialize.swift (camelCase wire contract, sourceKey encodes an explicit null for user-added columns), MaterializePlanner + MarkdownBlocks (pure ports of the backend's build-list.ts / markdown-blocks.ts so the seeded columns and preview match what the server builds), CreateFromSheet + CreateFromColumnEditor, and entry points on a message, a multi-message selection, a list, list rows (one via context menu, many via selection mode), and a document. Only ids go over the wire. Subscriber-gated at every entry point; a 403 maps to neutral copy so the body's "Subscribe…" text can't reach the UI (Guideline 3.1.1).
  • G18APIClient+GitHub.swift: githubLabels / githubAssignees / githubOrgs / githubNextIssueNumber. ListItemFormView gains a multiselect case backed by real repo options; CreateListView's repo picker gains an org filter. The write path is unchanged — still the full-row updateItem proxy, never GitHub's issue routes.

Rebase notes (4 conflicts, all resolved deliberately)

main moved 8 PRs since this branch was cut (#43 AI, #67 identity status, #68#73).

File Resolution
FeedView.swift Kept this branch's selection-mode row wrapper and grafted #70's onMute: callback onto MessageRow. visibleMessages now filters through isVisibleAuthor so it honours both the block list and the new mute list — previously it only checked blockedUserIds.
MessageDetailView.swift Additive @State; the Create from… sheet modifier is ordered ahead of #70's .muteConfirmation / .task.
ListsView.swift Purely additive both ways (contributors state from #68 + materialize/GitHub state here; loadData awaits both).
project.pbxproj 14 hunks, both sides kept. Verified no UUID collisions between the 30 refs this branch adds and the 74 main added; plutil -lint clean and all 12 new files confirmed in the right target via the xcodeproj gem.

Verification

  • Unit suite: 1,147 tests, 0 failures (iPhone 16 UDID 302E002E-…, dedicated -derivedDataPath, -parallel-testing-enabled NO, E2E skipped).
  • Live manual pass against the .env account (messenger, subscriber), driven through the real app in the simulator. Every entry point confirmed present and correctly gated:
Entry point Affordance
Feed multi-select Select posts2 posts selectedCreate from… (correctly disabled at 0 selected)
Message detail Post actionsCreate from…
Whole list List actionsCreate from list…
One row long-press → Create from this row…
Many rows Select rows…2 rows selectedCreate from…
Document Document optionsCreate from…

The sheet shows the destination switch (To List / To Doc / To List & Doc), source summary, prefilled title, public/include-rows toggles, seeded columns with rename + retype + add, and a live preview of the real source data under an "Approximate — the server rebuilds every value" note.

  • One real create, end to end (authorised, then cleaned up): creating from 2 messages produced schema content:textarea, author:text, posted:text, links:textarea, tags:text — exactly what the sheet's column editor showed — and 2 rows carrying the real content, author, timestamp and tags. The list was deleted afterwards; the account is back to its prior state.

Not verified live

G18's label/assignee pickers. The .env account has no GitHub connection — /api/github/repos and /api/github/orgs both return 200 [] and none of its lists is GitHub-backed — so there was nothing live to point the pickers at. Covered by APIClientGitHubMetadataTests (both the bare-array and {orgs:[]} response shapes), and the UI's documented fallback is to hide the multiselect rather than degrade to raw comma-separated text.

🤖 Generated with Claude Code

https://claude.ai/code/session_017bss5MgZa7Jvj2m9zdaUd1

Adron and others added 2 commits September 14, 2026 08:52
…ickers

Thread C: closes G16 ("Create from…") and G18 (GitHub metadata depth) from
work-consolidation.md. Stacked on refactor/apiclient-transport-seam — the new
endpoints live in `APIClient+*.swift` files, which that refactor made possible.

G16 — POST /api/materialize
- Models/Materialize.swift: the camelCase wire contract. `sourceKey` encodes as
  an explicit null for user-added columns (the contract documents `string|null`,
  and omission is a different thing).
- Services/MaterializePlanner.swift + MarkdownBlocks.swift: pure ports of the
  backend's build-list.ts / markdown-blocks.ts, so the sheet's seeded columns and
  preview match what the server will build. Optionless select/multiselect columns
  are downgraded to text — the server's DSL validator rejects them outright, and
  GitHub-backed lists hit exactly that with labels/assignees.
- Views/CreateFromSheet.swift + CreateFromColumnEditor.swift: destination picker
  (List / Doc / Both), column rename/retype/remove/add, live preview, and the
  created-result summary. Only ids go over the wire.
- Entry points: a message (detail), multi-select messages (feed), a whole list,
  list rows (single via context menu, many via selection mode), and a document.
- Subscriber-gated: every entry point is hidden for free users, and a 403 maps to
  neutral copy — the raw body carries "Subscribe…" text that must not appear
  in-app (Guideline 3.1.1).

G18 — GitHub repo metadata
- APIClient+GitHub.swift: githubLabels / githubAssignees / githubOrgs /
  githubNextIssueNumber. Orgs decode from either a bare array or an { orgs: [] }
  envelope — production and the backend source currently disagree.
- ListItemFormView gains a `multiselect` case backed by real repo options;
  ListDetailView fetches them and now shows labels/assignees instead of hiding
  them. Falls back to free text when options can't load, and the write path is
  unchanged — still the full-row `updateItem` proxy, never GitHub's issue routes
  (a partial PUT renames the issue to "Untitled").
- CreateListView repo picker gains an org filter; list detail shows the next
  issue number.

Shared: SelectionActionBar.swift extracts the selection row + bottom bar that the
feed and list detail both needed.

Verified: build green; 902 unit tests, 0 failures (823 baseline + 79 new);
app launches clean in the simulator with no runtime errors. Not yet driven by
hand against a live account — tapping Create writes real data to the shared test
account, so that pass is deliberately left to a human.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WFg1zPdWuasXD9ab6HJGHk
work-consolidation.md still listed G16 and G18 as open and G18 as partial.
G15 landed in #43, G16/G18 in #74, G17 in #40. The file is superseded for
open work by epic #44 (#45#66), so this records status and the pointer
rather than restating the epic here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bss5MgZa7Jvj2m9zdaUd1
@Adron
Adron merged commit 6523f20 into main Sep 14, 2026
1 check passed
@Adron
Adron deleted the feat/create-from-and-github-depth branch September 14, 2026 19:34
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.

W1: Land Thread C — "Create from…" (G16) and GitHub label/assignee pickers (G18)

1 participant