Skip to content

feat(v2-marketplace): manifest detail page at /v2/marketplace/:installableId#439

Closed
samxu01 wants to merge 2 commits into
mainfrom
phase-3/marketplace-detail
Closed

feat(v2-marketplace): manifest detail page at /v2/marketplace/:installableId#439
samxu01 wants to merge 2 commits into
mainfrom
phase-3/marketplace-detail

Conversation

@samxu01
Copy link
Copy Markdown
Contributor

@samxu01 samxu01 commented May 24, 2026

Summary

Scope (intentionally minimum-viable)

  • Identity: name / displayName / kind / category / publisher / verified badge / version
  • Pitch: description + readme (rendered via the existing react-markdown v2 already uses for inspector + message bubble — no new dep)
  • Shape: components[] (type + name) + requires[] (scopes)
  • Stats: total installs (formatted) + rating (with rating count)
  • Action: "Install" button → routes to /v2/agents/browse. No duplicated install UX here.

Token-aligned

CSS consumes only existing --v2-* tokens. No new tokens, no gradients, single accent, borders not shadows, 80ms hover transitions — matches the design-system discipline.

Not in this PR (intentional scope cap)

  • Publish / fork / deprecate flows (separate backend endpoints exist; UI is its own follow-up)
  • Version timeline rendering
  • Forks list (separate /forks endpoint)
  • AppCard → detail navigation wire (cards still click-to-install; detail is URL-deep-linkable for now)

Test plan

  • Five test cases in frontend/src/v2/marketplace/__tests__/V2MarketplaceDetailPage.test.tsx: happy path full manifest, 404, generic error, endpoint URL shape, minimal manifest with default fallbacks
  • CI green
  • After merge + deploy: visit https://app-dev.commonly.me/v2/marketplace/<installableId> for any real Installable, confirm identity + readme + components render

🤖 Generated with Claude Code

samxu01 and others added 2 commits May 24, 2026 00:36
…lableId

V2 surface for /api/marketplace/manifests/:installableId (backend
shipped in PR #215/#230 — never had a UI). Companion to the legacy
AppsMarketplacePage that v2 mounts at /v2/marketplace; this is the
missing detail surface flagged as the next-biggest gap in
docs/audits/ui-smoke-2026-05-23/marketplace-v2-gaps.md.

## Scope (deliberately minimum-viable)

- Identity: displayName / name / kind / category / publisher / verified
  badge / version
- Pitch: description + readme (rendered via the existing
  react-markdown that v2 already uses for V2PodInspector +
  V2MessageBubble — no new dep)
- Shape: components[] (kind + name) + requires[] (scopes)
- Stats: totalInstalls (formatted) + rating (with rating count)
- Action: "Install" button → routes to /v2/agents/browse, which
  already owns the install dialog. No duplicated install UX here.

## Token-aligned

CSS in `frontend/src/v2/marketplace/V2MarketplaceDetailPage.css`
consumes only existing v2.css tokens (`--v2-text-primary`,
`--v2-text-secondary`, `--v2-accent`, `--v2-accent-strong`,
`--v2-accent-soft`, `--v2-accent-text`, `--v2-border-soft`,
`--v2-bg-subtle`, `--v2-radius`, `--v2-font`, `--v2-font-mono`).
No new tokens, no gradients, single accent, borders not shadows,
80ms ease for hover transitions — matches the design system
discipline.

## Not in this PR (intentional scope cap)

- Publish / fork / deprecate flows (separate backend endpoints
  exist; UI is its own follow-up).
- Version timeline rendering (versions[] is in the doc but needs
  a real timeline component we don't have).
- Forks list (separate /forks endpoint).
- AppCard → detail navigation wire (current cards click Install
  directly per Cody's earlier marketplace rewire; cards-link-to-
  detail is a 5-line follow-up but I left it out so this PR stays
  scope-tight). Detail is currently URL-deep-linkable only.

## Routing

`frontend/src/v2/V2App.tsx`:
- new route `marketplace/:installableId` mounted under v2 shell with
  `feature(...)` chrome; sets `withChrome=false` to let the detail
  page own its own header (Back link + identity block).
- existing `marketplace` route (list) unchanged.

## Tests

`frontend/src/v2/marketplace/__tests__/V2MarketplaceDetailPage.test.tsx`
— five cases:

- happy path: full manifest renders all sections (identity, stats,
  components, scopes, readme)
- 404: shows "Manifest not found" with back link
- non-404 fetch failure: shows generic error
- axios endpoint shape: GET /api/marketplace/manifests/:installableId
- minimal manifest (no marketplace metadata): defaults apply
  (kind=app, category=other, 0 installs, unrated, by unknown)

Follow-up issue worth filing: deep-link install (clicking Install on
detail page pre-opens the install dialog in /v2/agents/browse) —
right now it just navigates to the list and the operator clicks
Install on the matching row.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…kdown body

ReactMarkdown's jest behavior is already covered by V2PodInspector +
V2MessageBubble tests. This leaf component just needs to verify the
readme path triggers (section header renders) — let the markdown
internals test themselves elsewhere.

CI surfaced the original 'A short greeting.' assertion fails because
ReactMarkdown wraps text in nested elements that defeat getByText's
default exact-string matcher.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@samxu01
Copy link
Copy Markdown
Contributor Author

samxu01 commented May 24, 2026

Merged via local squash to main.

samxu01 added a commit that referenced this pull request May 24, 2026
…lableId (#439)

V2-native surface for /api/marketplace/manifests/:installableId
(backend shipped in PR #215/#230 — never had a UI). Companion to
the legacy AppsMarketplacePage mounted at /v2/marketplace; this is
the missing detail surface flagged as the next-biggest gap in
docs/audits/ui-smoke-2026-05-23/marketplace-v2-gaps.md.

## Scope (minimum-viable)

  - Identity: displayName / name / kind / category / publisher /
    verified badge / version
  - Pitch: description + readme (rendered via the existing
    react-markdown v2 already uses for V2PodInspector +
    V2MessageBubble — no new dep)
  - Shape: components[] (type + name) + requires[] (scopes)
  - Stats: total installs (formatted) + rating (with rating count)
  - Action: "Install" button → routes to /v2/agents/browse, which
    already owns the install dialog. No duplicated install UX.

## Token-aligned

CSS consumes only existing --v2-* tokens (bg / text-primary /
text-secondary / accent / accent-strong / accent-soft / accent-text /
border-soft / bg-subtle / radius / font / font-mono). No new
tokens, no gradients, single accent, borders not shadows, 80ms
hover transitions.

## Not in this PR (intentional scope cap)

  - Publish / fork / deprecate flows
  - Version timeline rendering
  - Forks list
  - AppCard → detail nav wire (cards still click-to-install;
    detail is URL-deep-linkable for now)

## Tests

frontend/src/v2/marketplace/__tests__/V2MarketplaceDetailPage.test.tsx
— five cases:

  - happy path full manifest renders identity / stats / components /
    scopes / readme-section header
  - 404 → "Manifest not found" with back link
  - non-404 → generic error
  - axios called with /api/marketplace/manifests/:installableId
  - minimal manifest (no marketplace metadata) → defaults apply

Readme body content is NOT asserted (ReactMarkdown internals are
already covered by V2PodInspector + V2MessageBubble tests; asserting
on its output here makes the test brittle to markdown library
behavior).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@samxu01 samxu01 closed this May 24, 2026
@samxu01 samxu01 deleted the phase-3/marketplace-detail branch May 24, 2026 07:51
samxu01 added a commit that referenced this pull request May 24, 2026
…, closes #445)

Extends seed-native-agents.ts so each FIRST_PARTY_APPS entry also upserts an
Installable row (source='builtin', kind='app', scope='instance') alongside
its existing AgentRegistry row. Unblocks PR #439 v2 marketplace detail page —
without the projection, /v2/marketplace/:installableId could never resolve
a first-party app like pod-welcomer / task-clerk / pod-summarizer by direct
URL.

Browse continues to filter source='marketplace' (community-published items
only); detail page reads any source.

Idempotent — subsequent boots refresh display metadata via \$set without
touching stats.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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