Skip to content

feat(marketplace): admin publish control for assessments - #8477

Open
LWS49 wants to merge 1 commit into
lws49/feat-marketplace-pr1-foundationfrom
lws49/feat-marketplace-pr2-publish
Open

feat(marketplace): admin publish control for assessments#8477
LWS49 wants to merge 1 commit into
lws49/feat-marketplace-pr1-foundationfrom
lws49/feat-marketplace-pr2-publish

Conversation

@LWS49

@LWS49 LWS49 commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator
  • 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

@LWS49
LWS49 force-pushed the lws49/feat-marketplace-pr2-publish branch from d548294 to a992507 Compare July 8, 2026 02:48
@LWS49
LWS49 force-pushed the lws49/feat-marketplace-pr1-foundation branch from e89f6b9 to 35884a1 Compare July 8, 2026 02:50
@LWS49
LWS49 force-pushed the lws49/feat-marketplace-pr2-publish branch 3 times, most recently from 03ffa6a to c630a44 Compare July 8, 2026 03:25
@LWS49
LWS49 force-pushed the lws49/feat-marketplace-pr1-foundation branch from 35884a1 to 833d37f Compare July 8, 2026 03:58
@LWS49
LWS49 force-pushed the lws49/feat-marketplace-pr2-publish branch from c630a44 to a1dda4c Compare July 8, 2026 04:00
@LWS49
LWS49 force-pushed the lws49/feat-marketplace-pr1-foundation branch from 833d37f to 9926c90 Compare July 8, 2026 04:05
@LWS49
LWS49 force-pushed the lws49/feat-marketplace-pr2-publish branch 2 times, most recently from cbdd315 to dd68b1c Compare July 8, 2026 04:07
@LWS49
LWS49 force-pushed the lws49/feat-marketplace-pr1-foundation branch from 9926c90 to b34bd1d Compare July 17, 2026 08:06
- 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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/destroy endpoints 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
Comment on lines +80 to +87
<PromptText>
{t(translations.deletingThisAssessment)}
{assessment.isPublishedToMarketplace && (
<PromptText>
{t(marketplaceTranslations.deleteWarning)}
</PromptText>
)}
</PromptText>
Comment on lines +31 to +47
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);
}
};
Comment on lines +5 to +21
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`,
);
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there are more handlers using #urlPrefix in future PRs, this can be safely ignored.

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.

3 participants