Problem Summary
I’m developing a Discourse plugin that adds a toolbar button to open a modal form. I’ve followed the official DModal API migration documentation step-by-step, but I’m still getting module import errors and the “modal needs updating” warning. Need guidance on what I’m missing.
A quick note: I don’t know how to program, this plugin was created entirely with the help of AI.
Current Errors
Error 1 - Module Import:
Uncaught (in promise) Error: Could not find module `discourse/components/modal/lottery-form-modal` imported from `discourse/plugins/discourse-lottery-v3/discourse/initializers/lottery-toolbar`
Error 2 - Legacy Modal Warning:
Error: the 'lottery-form' modal needs updating to work with the latest version of Discourse. See https://meta.discourse.org/t/268057.
Error 3 - Deprecation Notice:
Deprecation notice: Defining modals using a controller is no longer supported. Use the component-based API instead. (modal: lottery-form) [deprecated since Discourse 3.1] [removal in Discourse 3.2]
Official Documentation I’ve Followed
I’ve carefully studied and implemented based on these official resources:
-
Converting modals from legacy controllers to new DModal component API
- URL:
https://meta.discourse.org/t/268057
- Followed all 4 steps: moved files to
/components/modal/
, updated JS to extend Component, updated template to use<DModal>
, updated show calls to usemodal.show()
- URL:
-
Using the DModal API to render Modal windows
- URL:
https://meta.discourse.org/t/268304
- Implemented DModal with proper
@closeModal
,@title
, and named blocks
- URL:
-
Discourse Core Plugin API
- Source:
https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/lib/plugin-api.gjs
- Used
api.onToolbarCreate()
and modal service injection
- Source:
-
Discourse Developer Docs - Converting Modals
- URL:
https://github.com/discourse/discourse-developer-docs/blob/main/docs/03-code-internals/10-converting-modals.md
- Cross-referenced migration steps
- URL:
What I’m Trying to Do
- Add a toolbar button in the composer
- Click button opens a modal form
- User fills form and clicks submit
- Modal closes and inserts content into composer
What I’ve Tried
Approach 1: Dynamic Import + Modal Service (Current)
- Getting module import error
Approach 2: showModal() with Controller
- Getting deprecation warnings about legacy controllers
Approach 3: Static Import
- Also tried static imports but same module resolution issues
File structure:
discourse-lottery-v3/
├── plugin.rb
└── assets/javascripts/discourse/
├── initializers/
│ └── lottery-toolbar.js
└── components/modal/
├── lottery-form-modal.js
└── lottery-form-modal.hbs
Toolbar button code:
// assets/javascripts/discourse/initializers/lottery-toolbar.js
import { withPluginApi } from "discourse/lib/plugin-api";
export default {
name: "lottery-toolbar",
initialize() {
withPluginApi("1.0.0", (api) => {
api.onToolbarCreate((toolbar) => {
toolbar.addButton({
id: "lottery-insert",
group: "extras",
icon: "dice",
title: "Insert Lottery",
perform: () => {
const modal = api.container.lookup("service:modal");
// This line causes the import error:
import("discourse/components/modal/lottery-form-modal").then((module) => {
const LotteryFormModal = module.default;
modal.show(LotteryFormModal, { model: {} });
});
}
});
});
});
}
};
Modal component:
// assets/javascripts/discourse/components/modal/lottery-form-modal.js
import Component from "@ember/component";
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
export default class LotteryFormModal extends Component {
@tracked inputValue = "";
@action
submit() {
// Handle form submission
this.args.closeModal();
}
}
Modal template:
{{! assets/javascripts/discourse/components/modal/lottery-form-modal.hbs }}
<DModal @title="My Modal" @closeModal={{this.args.closeModal}} class="my-modal">
<:body>
<input value={{this.inputValue}} />
</:body>
<:footer>
<button {{on "click" this.submit}}>Submit</button>
</:footer>
</DModal>
Questions
Based on all the code, errors, and background information provided above, how should I modify my code to correctly implement my feature?
Any guidance on the correct implementation approach would be greatly appreciated