feat(marketplace): admin publish control for assessments - #8477
Conversation
LWS49
commented
Jul 8, 2026
- 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
d548294 to
a992507
Compare
e89f6b9 to
35884a1
Compare
03ffa6a to
c630a44
Compare
35884a1 to
833d37f
Compare
c630a44 to
a1dda4c
Compare
833d37f to
9926c90
Compare
cbdd315 to
dd68b1c
Compare
9926c90 to
b34bd1d
Compare
dd68b1c to
c15d911
Compare
There was a problem hiding this comment.
Pull request overview
Adds an admin-only control flow for publishing/removing course assessments to/from the Assessment Marketplace, surfaces marketplace state/permissions in the assessment show payload, and wires this into the assessment header UI with supporting API client, i18n strings, and specs.
Changes:
- Add admin-gated
create/destroyendpoints for an assessment’s marketplace listing and route wiring. - Expose
canPublishToMarketplace, listing state, and listing URL on the assessment show JSON + TypeScript DTO. - Add a Publish/Remove button (with confirmation prompts, toasts, and translations) plus controller/FE tests.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| spec/controllers/course/assessment/marketplace_listings_controller_spec.rb | New controller spec coverage for publish/remove behavior and authorization. |
| spec/controllers/course/assessment/assessments_marketplace_spec.rb | New spec verifying marketplace-related fields on assessment show JSON. |
| config/routes.rb | Adds nested singular marketplace_listing resource under assessments. |
| app/controllers/course/assessment/marketplace_listings_controller.rb | New controller implementing publish/remove listing actions with admin gating. |
| app/views/course/assessment/assessments/show.json.jbuilder | Adds marketplace permission/state/url fields to assessment show DTO. |
| client/app/types/course/assessment/assessments.ts | Extends AssessmentData with marketplace permission/state/url fields. |
| client/app/api/course/Marketplace.ts | New client for publish/remove listing API calls. |
| client/app/api/course/index.js | Registers the new Marketplace API client under CourseAPI.marketplace. |
| client/app/bundles/course/marketplace/translations.ts | New react-intl message definitions for marketplace UI strings. |
| client/locales/en.json | Adds English strings for publish/remove confirmations, toasts, and delete warning. |
| client/locales/zh.json | Adds Chinese strings for publish/remove confirmations, toasts, and delete warning. |
| client/locales/ko.json | Adds Korean strings for publish/remove confirmations, toasts, and delete warning. |
| client/app/bundles/course/marketplace/components/PublishToMarketplaceButton.tsx | New publish/remove button with confirmation prompt and toasts. |
| client/app/bundles/course/marketplace/components/test/PublishToMarketplaceButton.test.tsx | New tests for publish/remove button behavior. |
| client/app/bundles/course/assessment/pages/AssessmentShow/AssessmentShowHeader.tsx | Adds marketplace publish/remove control and delete prompt warning. |
| client/app/bundles/course/assessment/pages/AssessmentShow/test/AssessmentShowHeader.test.tsx | New tests for conditional delete warning when listed. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| listing.published = true | ||
| listing.first_published_at ||= now | ||
| listing.last_published_at = now | ||
| listing.publisher ||= current_user |
There was a problem hiding this comment.
Fixed. Agreed, publisher is meant to be an audit stamp of who did the latest publish, so it should move together with last_published_at. Nothing is lost as creator_id still records whoever first created the row too.
| <PromptText> | ||
| {t(translations.deletingThisAssessment)} | ||
| {assessment.isPublishedToMarketplace && ( | ||
| <PromptText> | ||
| {t(marketplaceTranslations.deleteWarning)} | ||
| </PromptText> | ||
| )} | ||
| </PromptText> |
There was a problem hiding this comment.
Both fixed. The warning is now its own paragraph, and it reads the live state rather than the value the page loaded with.
| const confirm = async (): Promise<void> => { | ||
| setSubmitting(true); | ||
| try { | ||
| if (listed) { | ||
| await CourseAPI.marketplace.removeListing(assessment.id); | ||
| toast.success(t(translations.removed)); | ||
| onChange(false); | ||
| } else { | ||
| await CourseAPI.marketplace.publishListing(assessment.id); | ||
| toast.success(t(translations.published)); | ||
| onChange(true); | ||
| } | ||
| setOpen(false); | ||
| } finally { | ||
| setSubmitting(false); | ||
| } | ||
| }; |
There was a problem hiding this comment.
Fixed. A failed publish/remove now shows an error toast and leaves the dialog open so the user can retry. Added a test for the failure path.
| export default class MarketplaceAPI extends BaseCourseAPI { | ||
| get #urlPrefix(): string { | ||
| return `/courses/${this.courseId}/marketplace`; | ||
| } | ||
|
|
||
| publishListing(assessmentId: number): Promise<AxiosResponse> { | ||
| return this.client.post( | ||
| `/courses/${this.courseId}/assessments/${assessmentId}/marketplace_listing`, | ||
| ); | ||
| } | ||
|
|
||
| removeListing(assessmentId: number): Promise<AxiosResponse> { | ||
| return this.client.delete( | ||
| `/courses/${this.courseId}/assessments/${assessmentId}/marketplace_listing`, | ||
| ); | ||
| } | ||
| } |
There was a problem hiding this comment.
If there are more handlers using #urlPrefix in future PRs, this can be safely ignored.
There was a problem hiding this comment.
there are more handlers using #urlPrefix in future PRs. will ignore this
- 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
c15d911 to
eb92f7b
Compare