Skip to content

feat(apps): collaborative tracks — display, upload tagging, notifications, accept/leave (behind flag)#14466

Open
raymondjacobson wants to merge 11 commits into
mainfrom
claude/collab-apps
Open

feat(apps): collaborative tracks — display, upload tagging, notifications, accept/leave (behind flag)#14466
raymondjacobson wants to merge 11 commits into
mainfrom
claude/collab-apps

Conversation

@raymondjacobson

@raymondjacobson raymondjacobson commented Jun 9, 2026

Copy link
Copy Markdown
Member

Phase 3 — the apps client for collaborative tracks, all behind the new collaborative_tracks feature flag (default off), so it ships inert. Pairs with go-openaudio #345/#346/#349 (ETL) and AudiusProject/api #932 (api). Reviewing as one PR per your request; commits are sliced by concern.

What's implemented (web + mobile)

DisplayTrackMetadata.collaborators + adapter; <TrackArtists> renders owner + comma-separated collaborators with ellipsis overflow on web tiles/track page and mobile TrackCard/TrackDetailsTile. Flag-off = the previous single owner link.

SDK + hooksTrackCollaborator EntityType; TracksApi.acceptTrackCollaboration / rejectTrackCollaboration (reject = decline or leave); collaborators in the upload metadata schema; upload adapter maps tagged users → numeric on-chain ids; tan-query useAccept/RejectTrackCollaboration.

Upload taggingweb CollaboratorsField (reuses SearchUsersModal/ArtistChip) and mobile CollaboratorField (self-contained inline search + chips), both in the edit-track form behind the flag.

Notifications + accept/declinetrack_collaborator_invite / track_collaborator_accept types, adapter, web + mobile components + routing. Web invite notification has inline Accept/Decline.

Leave (remove yourself after accepting) — web TrackMenu and mobile track-page overflow both gain "Remove Me as Collaborator", shown to accepted collaborators (not the owner).

Deferred follow-ups (called out)

  • Standalone pending-invites list page — accept/decline currently drives off the invite notification (covers the primary flow); a list can use GET /users/:id/collaboration_invites.
  • SDK read-type regencollaborators on the generated Track type + the invites endpoint need an OpenAPI spec update + regen; the read path currently uses a small structural extension.
  • Editing drops pending invites — the edit form initializes from the API's accepted collaborators only, so re-saving a track with still-pending invites would drop them. Needs an owner-facing "all collaborators (incl. pending)" source.

Verification caveat

I could not run the apps typecheck/lint/build locally (the worktree's toolchain/deps don't match this environment). These changes are pattern-copies of the existing manager-invite/approve flow and are CI-pending — please let CI and your review be the gate. (Server-side: notification id hashing is already generic via trashid.HashifyJson, so the new types' data ids encode correctly with no api change.)

🤖 Generated with Claude Code

… flag)

Display slice of the apps phase: renders a track's accepted collaborators as a
comma-separated artist line on web track tiles and the track page, behind a new
`collaborative_tracks` flag (default off). Ships inert.

- packages/common: `TrackMetadata.collaborators` (UserMetadata[]), mapped in
  userTrackMetadataFromSDK and decoded like the owner. The field isn't in the
  generated SDK Track type yet, so it's read via a structural extension pending
  the SDK regen. New COLLABORATIVE_TRACKS feature flag.
- packages/web: <TrackArtists> renders the owner plus comma-separated
  collaborators on one ellipsizing line. With the flag off (or no
  collaborators) it returns a single owner <UserLink> — a safe drop-in. Wired
  into desktop TrackTile, mobile-web TrackTile, and GiantTrackTile.

Next apps slices: mobile-native tiles, upload tagging UI, notifications +
accept UX, SDK write methods.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jun 9, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: c315547

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

🌐 Web preview ready

Preview URL: https://audius-web-preview-pr-14466.audius.workers.dev

Unique preview for this PR (deployed from this branch).
Workflow run

…ind flag)

Mobile-native parity for the collaborator artist line, behind the
collaborative_tracks flag.

- <TrackArtists> (owner UserLink + collaborators) and <CollaboratorLinks>
  (collaborators-only append), both flag-gated so they're no-ops when off.
- TrackCard: owner UserLink -> TrackArtists (collaborators added to the track
  select). Wrapper centers to preserve the card's centered artist line.
- TrackDetailsTile: keeps the owner Text + UserBadges and appends
  CollaboratorLinks, so the flag-off rendering is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@raymondjacobson raymondjacobson changed the title feat(web): collaborative tracks — comma-separated artist line (behind flag) feat(apps): collaborative tracks — comma-separated artist line, web + mobile (behind flag) Jun 9, 2026
@pull-request-size pull-request-size Bot added size/L and removed size/M labels Jun 9, 2026
raymondjacobson and others added 3 commits June 8, 2026 19:27
- SDK: TrackCollaborator EntityType; TracksApi.acceptTrackCollaboration /
  rejectTrackCollaboration (EntityManager Approve/Reject; reject = decline or
  leave). collaborators added to UploadTrackMetadataSchema (numeric user ids).
- Upload adapter maps form collaborator user objects -> numeric ids on-chain.
- tan-query: useAcceptTrackCollaboration, useRejectTrackCollaboration.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- CollaboratorsField: search + add collaborators (reuses SearchUsersModal /
  ArtistChip, like the invite-manager UI) with removable chips. Wired into
  TrackMetadataFields behind the collaborative_tracks flag.
- collaborators added to the upload form schema (full user objects).

Mobile upload tagging deferred (needs a native user picker); data plumbing
already supports it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…e (behind flag)

- Notification types track_collaborator_invite / track_collaborator_accept
  (NotificationType + PushNotificationType + interfaces + union + adapter cases).
- Web: invite notification with inline Accept/Decline (useAccept/RejectTrack-
  Collaboration), accept notification (display); routing in Notification.tsx.
  TrackMenu gains a 'Remove Me as Collaborator' item shown to accepted
  collaborators (not the owner) — the post-accept leave path.
- Mobile: invite/accept notification components + routing + navigation handlers
  (navigate to the track).

Deferred follow-ups: mobile upload picker, mobile overflow leave action,
a pending-invites list page, and SDK read-type regen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@pull-request-size pull-request-size Bot added size/XL and removed size/L labels Jun 9, 2026
@raymondjacobson raymondjacobson changed the title feat(apps): collaborative tracks — comma-separated artist line, web + mobile (behind flag) feat(apps): collaborative tracks — display, upload tagging, notifications, accept/leave (behind flag) Jun 9, 2026
Finishes the deferred mobile pieces.

- CollaboratorField: self-contained inline search (useSearchUserResults) +
  removable chips, added to the mobile edit-track form behind the flag.
  Selected users flow through the upload metadata adapter to numeric ids.
- "Remove Me as Collaborator" overflow action: new
  OverflowAction.LEAVE_TRACK_COLLABORATION, row label + drawer callback
  (rejectTrackCollaboration + toast), shown on the track page to accepted
  collaborators (not the owner).

Known limitation: editing a track initializes collaborators from the API's
accepted list only, so re-saving could drop still-pending invites — needs an
owner-facing "all collaborators" source to fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rder

- SDK: the generated Notification union/parser threw on unknown types and the
  adapter switch couldn't reference them. Add TrackCollaboratorNotification
  (+ Action/ActionData) generated models and wire them into Notification.ts
  (union + FromJSONTyped cases) so track_collaborator_invite/accept parse and
  typecheck. Hand-authored pending an OpenAPI regen.
- Fix import/order lint in web Notification.tsx and TrackMenu.tsx, and mobile
  TrackScreenDetailsTile.tsx.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
raymondjacobson and others added 4 commits June 9, 2026 15:21
…ivate tracks

- Remove the collaborative_tracks feature flag and its gating everywhere; the
  feature is always on now (display, upload tagging, notifications, leave).
- Fix the invite notification doing nothing on a private track: a pending
  collaborator can't load an unlisted track (the API filters it), so the
  `if (!track) return null` guard blanked the whole notification — including the
  Accept/Decline buttons. Render off the inviter alone, fall back to "a track"
  for the title, and act on the trackId carried by the notification.
- Add success/error toasts (and disable-while-submitting) to Accept/Decline so
  it's no longer silent. Same null-guard relaxed on the accept notifications and
  the mobile equivalents.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The API returns `collaborators` on track responses, but the generated SDK
Track/SearchTrack models' FromJSONTyped only copy known fields — so the field
was silently dropped during deserialization, and the adapter's structural cast
always read `undefined`. Result: accepted collaborators never rendered on track
pages/tiles even though the backend returned them.

Add `collaborators?: Array<User>` to the generated Track and SearchTrack models
(interface + FromJSONTyped + ToJSON, mirroring `user`) so the field survives,
and read it directly in the adapter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Now that the API swagger declares `collaborators` (deployed), ran the real
generator (typescript-fetch v7.5.0) against api.audius.co's spec. The output for
Track.ts/SearchTrack.ts is byte-identical to the prior hand-edit (only a
generator-emitted whitespace differs), confirming the field is now genuinely
generated rather than hand-patched. Other models left untouched (unrelated spec
drift not pulled in); the hand-authored notification models remain as-is.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The edit form seeded its collaborators field from the track's accepted-only
`collaborators`, so saving dropped any still-pending invites (the ETL reconciles
the metadata set). Initialize the field from accepted + pending instead.

- SDK Track/SearchTrack: add `pendingCollaborators` (hand-edit stopgap; the API
  swagger now declares `pending_collaborators` in AudiusProject/api#947, so the
  next regen reproduces this).
- Track model + adapter: expose `pending_collaborators` (owner-only).
- Web + mobile edit screens: seed the collaborators field with
  `[...collaborators, ...pending_collaborators]` so pending invites survive a
  save. Display still uses accepted-only `collaborators` (no regression).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant