CommandBar.showForm never settles if an HTML view invokes a plugin command
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 45/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- javascript
- Lĩnh vực
- developer-experience
Hướng nghiên cứu
Start by reading np.Shared/requiredFiles/pluginToHTMLCommsBridge.js and tracing how DataStore.invokePluginCommandByName interacts with pending CommandBar.showForm calls. Reproduce with the Dashboard timer running while /convert to project awaits the form. Done means HTML view commands no longer leave the form promise pending: calls are queued until dismissal or the form settles if preempted.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Summary
CommandBar.showForm() never settles if an HTML view invokes another plugin command while the form is open. The original command stays suspended, the note is not updated, and there is no error. Closing the HTML window avoids the problem because nothing then calls back into the plugin.
Seen on NotePlan 3.22 (build 1542), macOS, 26 Oct 2026.
Repro
- Open the Dashboard HTML window (
jgclark.Dashboard, custom idjgclark.Dashboard.main) and leave it open. With the Time Block section enabled, the page runssetIntervalevery 54 seconds. - Open a normal note and run the Projects command
/convert to project(jgclark.Reviews/convertToProject). - That command reaches
await CommandBar.showForm(...)and stops. The form does not complete, and the command logs nothing further. Run it again and the same thing happens. - Close Dashboard and run the same command. The form appears, Submit writes the note frontmatter, and the command logs success.
What the plugin is doing
After a couple of checks and getReviewSettings(), the command does only this:
const formResult = await CommandBar.showForm({
title: `Convert '${title}' to a Project`,
submitText: 'Convert',
fields,
})
Every path after that await logs either cancellation, invalid data, a write failure, or success, and the catch logs exceptions. None of those lines appear on the failed runs. The promise from showForm is neither resolved nor rejected.
The same form succeeds when Dashboard is closed, so the field list is not the cause.
What the logs show
Plugin console for a failed run (16:08:32), with nothing after the settings line:
--- 2026-10-26T16:08:32Z 'convert to project' (jgclark.Reviews) ---
Executing function 'convertToProject'
INFO convertToProject :: Starting for note 'Live Translation for services' (...)
INFO getReviewSettings :: Will use Perspective 'Home', and its folder & teamspace settings
One second later, Dashboard runs because the webview posted a bridge message:
[WebView] bridge::runPluginCommand JS file in np.Shared Sending command "onMessageFromHTMLView" to NotePlan: "jgclark.Dashboard"
--- 2026-10-26T16:08:33Z 'onMessageFromHTMLView' (jgclark.Dashboard) ---
Executing function 'onMessageFromHTMLView'
INFO bridgeClickDashboardItem: refreshSomeSections
That refreshSomeSections call is the Time Block timer. It fires about every 54 seconds for as long as the Dashboard window is visible (16:02:37, 16:03:31, 16:04:25, 16:05:20, 16:06:44, 16:07:39, 16:08:33, 16:09:28, ...). Each failed /convert to project was still awaiting showForm when the next tick arrived (16:02:11 then refresh at 16:02:37; 16:03:28 then 16:03:31; 16:08:32 then 16:08:33). None of those awaits ever resumed.
The run that succeeded (16:10:49, frontmatter written at 16:10:57) fell in a gap between those ticks. The same command also succeeds whenever Dashboard is closed, so the timer never posts.
The bridge code in np.Shared/requiredFiles/pluginToHTMLCommsBridge.js is:
const code = '(async function() { await DataStore.invokePluginCommandByName("onMessageFromHTMLView", "jgclark.Dashboard", [type, data]);})()'
window.webkit.messageHandlers.jsBridge.postMessage({ code, onHandle: '', id: '1' })
So while jgclark.Reviews is suspended inside CommandBar.showForm, the webview starts a second plugin command, jgclark.Dashboard.onMessageFromHTMLView, via DataStore.invokePluginCommandByName.
What appears to go wrong in the app
showForm is waiting on the command bar. A jsBridge message then starts another plugin command on the same JavaScript context. That second command runs (refreshSomeSections does its work and returns). The first command's showForm promise is left pending: the form is gone or never committed, and no completion handler runs. The first command cannot log, write, or show an error.
This matches a modal UI promise that is dropped when a new plugin command begins, instead of being resolved with submitted: false or rejected.
The same hole would affect any await CommandBar.showForm / prompt / textPrompt while any HTML view posts invokePluginCommandByName. Dashboard's idle refresh (refreshEnabledSections) and windowResized on hide use that same bridge, so they can trip it too. The 54-second Time Block timer is the one that lined up with these logs.
Expected behavior
While a command-bar form is open, invokePluginCommandByName coming from an HTML view should be queued until the form is dismissed. If a new command must preempt the form, showForm should still settle (submitted: false, or a rejection) so the caller's await resumes. A background refresh must not swallow the form and leave the original command hung.
- Ngôn ngữ chính
- JavaScript
- Star
- 203
- Fork
- 81
- Merge trung bình
- 52 phút
- Pull request đã merge (30 ngày)
- 1
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của NotePlan/plugins
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
-
Task Sorting & Tools: support other line typesCó thể đã có người làm @dwertheimer đã nhận 11 ngày trước. Đang mởenhancement
-
getFoldersMatching adds root "/" even when it is not an inclusionCó thể đã có người làm @jgclark đã nhận 11 ngày trước. Đang mở
-
Dashboard: Task "Comment"Đang mởenhancement question
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 35/100
-
newMeetingNoteFromEventID always opens earliest occurrence for Google Calendar recurring eventsCó thể làm lại được @EduardMe đã nhận 137 ngày trước và không có pull request nào đang mở. Đang mởbug
Tất cả issue của NotePlan/plugins
Issue tương tự
-
Energy flow: add an "Other" row so the consumers add up to the consumption totalCó thể đã có người làm @github-actions đã nhận hôm nay. Đang mởenhancement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 73/100
evcc-io/evcc#35512 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Impact: Medium Level: Easy Type: Bug Value: Users
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
Maintainer thường phản hồi trong vòng 1 ngày
-
bug good first issue
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
NobiResearch/Ovenbird#148 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
enhancement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
glossyio/traffic-monitor#264 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
balance good first issue
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
tobeficv/founders-way#5 ·