Skip to content

[BUG] [alpha] Prompt Editor: dismissing modal (backdrop / X) during Save does not cancel persistence — create/update can still complete after user leaves #38065

@galuis4a

Description

@galuis4a

Project

ide

Description

Plain language

The Prompt Editor modal lets the user close it via the backdrop click or the header X at any time. Those paths do not check whether a Save is in progress (saving is only used to disable the primary Save button). If the user dismisses the modal while updatePrompt / createPrompt is still awaiting storage, the in-flight operation continues and can still write the prompt to disk and update the list. The user reasonably expects “close = discard unsaved work” (or at least “stop what Save was doing”); instead they can get ghost saves or new prompts created after the UI is gone.

This is the same async cancellation / late completion theme as bounty #38008 (API Tokens Cancel vs in-flight Save) but on a different surface (Prompt Library editor), so it is not a duplicate of that ticket—it extends the pattern.

Technical detail

Save pathsetSaving(true), then await promptStore.updatePrompt / createPrompt, then closeEditor() in try:

    setSaving(true);

    try {
      const promptData = {
        title: title().trim(),
        content: content().trim(),
        description: description().trim(),
        category: category(),
        tags: tags(),
        isFavorite: isFavorite(),
      };

      if (isEditing()) {
        await promptStore.updatePrompt(promptStore.state.editingPrompt!.id, promptData);
      } else {
        await promptStore.createPrompt(promptData);
      }

      promptStore.closeEditor();
    } catch (e) {
      setErrors([{ field: "general", message: String(e) }]);
    } finally {
      setSaving(false);
    }

Dismiss paths — no guard on saving(); always call closeEditor():

  const handleClose = () => {
    promptStore.closeEditor();
  };

  return (
    <Show when={isOpen()}>
      <div
        class="fixed inset-0 z-[60] flex items-center justify-center"
        style={{ background: "rgba(0,0,0,0.6)" }}
        onClick={(e) => {
          if (e.target === e.currentTarget) handleClose();
        }}

Header close uses the same handleClose (lines 214–219 in file). Save is the only control that respects disabled={saving()} (see footer ~510).

PromptStoreContext.updatePrompt / createPrompt both await saveToStorage() — there is no cooperative cancellation.

Error Message

Debug Logs

System Information

OS: Windows 11

Screenshots

Image

Steps to Reproduce

  1. Open Prompt Library and start Create (or Edit an existing prompt).
  2. Change fields, click Save Changes / Create Prompt (or equivalent).
  3. Immediately click the backdrop (outside the card) or the X before the save finishes (slow disk or throttle helps).

Expected Behavior

  • Dismissing the modal while save is in-flight either aborts the operation, or ignores completion so no partial/undesired persistence occurs; or dismiss is blocked until save completes (with clear UX).

Actual Behavior

Actual

  • Modal closes (closeEditor()), but updatePrompt / createPrompt can still complete and persist data the user thought they cancelled. For create, a new prompt may appear after dismiss.

Suggested direction (implementation notes)

  • While saving() is true: ignore backdrop/X or show confirm; or use a save generation id / let cancelled = false on open and check after await before applying side effects / second closeEditor().
  • Align behavior with product decision: “Save is atomic and cannot be cancelled” → disable all dismiss affordances until finally runs.

Relation to existing issues

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingideIssues related to IDEinvalidThis doesn't seem right

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions