Hacktoberfest 2026 : les issues que les mainteneurs ont marquées pour octobre, ouvertes et accessibles aux débutants. Parcourir les issues Hacktoberfest

CommandBar.showForm never settles if an HTML view invokes a plugin command

Ouverte
#790 1 commentaire 0 réactions 0 personnes assignées Voir sur GitHub

Personne n'a encore pris cette issue.

Évaluation

Difficulté
4/5
Temps estimé
3-5 jours
Accessibilité débutants
45/100
Type d'issue
Bug
Clarté
Plutôt claire
Activité
Active
Stack technique
javascript

Piste de recherche

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.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

API bug

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

  1. Open the Dashboard HTML window (jgclark.Dashboard, custom id jgclark.Dashboard.main) and leave it open. With the Time Block section enabled, the page runs setInterval every 54 seconds.
  2. Open a normal note and run the Projects command /convert to project (jgclark.Reviews / convertToProject).
  3. 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.
  4. 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.

Langage dominant
JavaScript
Étoiles
203
Forks
81
Merge moyen
52 min
PR mergées (30 j)
1

Préparer son environnement

Ce projet ne fournit ni conteneur de développement, ni Dockerfile, ni guide de contribution : l'installation est à votre charge. Commencez par son README, et consultez notre guide de la première contribution pour les étapes générales.

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de NotePlan/plugins

Toutes les issues de NotePlan/plugins

Issues similaires

Plus d'issues JavaScript

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.