feat(marketplace): destination tab picker and completion feedback - #8487
Open
LWS49 wants to merge 11 commits into
Open
feat(marketplace): destination tab picker and completion feedback#8487LWS49 wants to merge 11 commits into
LWS49 wants to merge 11 commits into
Conversation
LWS49
force-pushed
the
lws49/feat-marketplace-pr5-preview
branch
2 times, most recently
from
July 17, 2026 07:14
a31b07a to
85ab1fc
Compare
LWS49
force-pushed
the
lws49/feat-marketplace-pr5b-misc
branch
from
July 17, 2026 07:27
2fce896 to
a3e493d
Compare
- add Listing and Adoption models under Course::Assessment::Marketplace namespace, with course_assessment_marketplace_ prefix on both tables - Listing tracks published state and publisher, with a uniqueness constraint per assessment and an adoption_count helper - Adoption links a listing to a destination course and duplicated assessment, one adoption per duplicated assessment - wire has_one :marketplace_listing onto Course::Assessment - add AssessmentMarketplaceAbilityComponent: admins can publish listings, course managers/owners can access, duplicate, and preview published listings
- add publish/remove listing endpoints (admin-gated create/destroy) - expose canPublishToMarketplace + listing state on assessment show DTO - add Publish/Remove to Marketplace button on the assessment header - warn in the delete Prompt when a listed assessment is removed - add MarketplaceAPI client, translations, and controller/FE specs
- add cross-instance listings index (published only, live counts) - add browse page with title search, adoptions/newest sort, row select - add sidebar admin entry + /courses/:id/marketplace route - add "Import Assessments" button on assessments index (from_tab) - add FE api/operations/types, controller + component specs
- add DuplicationJob: copies listings into a course tab, writes adoption - add bulk duplicate endpoint enqueuing the job for selected listings - add DuplicateConfirmation modal with row + bulk triggers, job polling - add MarketplaceAPI.duplicate and duplicateListings poll operation - serialize and assert live distinct-course adoption count in index
Add the read-only backend for the marketplace browse flow: - listings#show serializes a curated, read-only view of a published assessment (config + per-question summaries) for the listing preview. - questions#show serializes a single question's detail, dispatching to per-type detail partials (multiple/text/voice/forum/programming/ rubric/scribing) so each renderer gets exactly the data it needs. - The listings index gains destination tabs plus preview/duplicate URLs so the browse table can link into the flow and target a tab. Type labels are serialized human-readable (question_type_readable) to match the real assessment show page, while the demodulized discriminator is kept for frontend renderer dispatch. The base controller pulls in AssessmentsHelper so the preview views can reuse display_graded_test_types, and the sidebar component now uses the :marketplace (storefront) icon.
…port Extract the assessment/tab/question tree from AssessmentsListing into a reusable DuplicationAssessmentTree component so both the duplication page and the marketplace duplicate dialog render an identical tree. The old DuplicateItemsConfirmation listing is rewired onto it. Also add the shared table primitives the marketplace index needs: - renderEmpty flows through TableTemplate -> Body -> MuiTable so a table can render a custom empty state when it has no rows. - hideSelectAll drops the select-all header checkbox while keeping the per-row checkboxes. - Register the storefront icon in COURSE_COMPONENT_ICONS.
Build the read-only browse experience on top of the preview endpoints: - Marketplace index: single-toolbar table with pagination, empty states, hidden select-all, and links into the listing preview / duplicate flow. - Listing preview page: read-only assessment config, per-question cards (type chip, staff-only notes, expandable options) and a Duplicate Assessment action. - Question detail preview: header chip plus a renderer dispatcher with a renderer per question type (multiple/text/voice/forum/programming/ rubric/scribing). - Duplicate dialog now shows the destination course and the shared assessment tree. Includes the api client, operations, types, translations and locale strings backing the above.
Thread the origin assessment tab (from_tab) through the whole browse flow (index -> listing -> question preview and back) via withFromTab helpers, so a duplication always imports into the tab the user started from no matter how they navigate. Add the route data handles that build the marketplace / listing / question breadcrumbs, preserving from_tab on the crumb links.
LWS49
force-pushed
the
lws49/feat-marketplace-pr5-preview
branch
from
July 17, 2026 08:11
85ab1fc to
a7086e3
Compare
LWS49
force-pushed
the
lws49/feat-marketplace-pr5b-misc
branch
from
July 17, 2026 08:12
a3e493d to
3bc206d
Compare
Replace the static destination summary with an in-dialog tab picker and report duplication results honestly: - Add DestinationTabPicker, a radio tree grouping the current course's tabs by category, so the duplicator chooses the destination tab inside the dialog instead of it being fixed by the launching `from_tab`. The selection seeds from `from_tab` (falling back to the first tab) and re-seeds on each reopen, but a parent re-render never resets a choice mid-decision. - Serve `destinationTabs` from the listing show endpoint too, so the picker is available when duplicating from the listing detail page, not just the marketplace index. - Restyle the dialog: vertically stacked tabs with larger category/tab text, a dense TypeBadge variant, an explicit "Duplicating" heading, the ⊘ "arrives unpublished" hint, and explicit cancel/primary colors. - Report a *completed* duplication (the toast fires from pollJob's completion callback, not on submit) and link to where the copy landed via the job's redirectUrl; reword the failure copy to plain language. Widen the shared toast Toaster type to ReactNode so the toast can carry that link (type-only change, no runtime effect).
`marketplace/listings` with no listing id matched no route and 404'd. Add a redirect so it lands on the same page as `marketplace/`.
Add a "Preview" chip beside the title on the read-only listing detail page, so it is never mistaken for the real assessment it mirrors.
LWS49
force-pushed
the
lws49/feat-marketplace-pr5b-misc
branch
from
July 17, 2026 08:14
3bc206d to
909976b
Compare
LWS49
marked this pull request as ready for review
July 17, 2026 08:14
LWS49
force-pushed
the
lws49/feat-marketplace-pr5-preview
branch
2 times, most recently
from
July 29, 2026 10:29
e04d41c to
5751e1b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This rounds out the preview/duplicate flow from the parent PR. The duplicate confirmation dialog now lets the user actively pick the destination category/tab via a new
DestinationTabPicker, instead of just displaying whichever tab they happened to arrive from. Completion feedback is upgraded to report once the duplication job actually finishes, with a link to where the assessment landed, instead of a fire-and-forget "started" toast. The listing preview page is badged so it's never mistaken for the real assessment it mirrors, and a bare/marketplace/listingsnow redirects to the marketplace index instead of 404ing.Design decisions
DuplicateConfirmationnow takes the fulldestinationTabslist and aninitialDestinationTabId, letting the user change the destination tab instead of being locked into the one they arrived from; the initial selection still defaults to thefrom_tabtab when it names a real tab, falling back to the course's first tab otherwise.pollJob's completion callback and links to the duplicated assessment (redirectUrl), since the previous "Duplicating assessment started." toast fired on job submission and gave no way to find the result afterward.[open]as the sole effect dependency), not on every parent re-render, so an in-progress tab choice isn't reset out from under the user while the dialog stays open.Regression prevention
Tests cover:
DestinationTabPicker's category grouping (including tabs arriving non-contiguously) and its selection wiring; the tab-selection reset-on-reopen vs. preserve-while-open behaviour; the completion and failure toast copy and the redirect link; the dialog locking/unlocking around an in-flight job so it can't be double-submitted or abandoned mid-job; thedestinationTabsnow returned from the listing show endpoint; the/marketplace/listingsredirect; and the listing preview page's "Preview" badge.Manual testing covered picking a different destination tab before confirming, the completion toast and its link after a duplication job finishes, a failed duplication leaving the dialog open for retry, and the bare
/marketplace/listingsredirect.