Elyra
Elyra The coding agent eTerm The terminal that knows where each command ends Huskarl AI colleagues on your own Mac Starf An activity monitor for Apple silicon that never invents a number etrans An SSH and SFTP client for macOS Elyra VM Virtual machines for macOS, Linux and Windows on your Mac Litr A small, native web browser for macOS Notr A notebook for macOS e The native code editor Elyra Grove Native local development environment Askr The real server for Laravel & PHP Elyra Framework Rust + Svelte 5 framework for desktop apps Elyra Conductor Local project conductor Refr Local-first PDF workspace for macOS Elyra Workspace A desktop workspace for coding agents Elyra SQL Server MySQL-compatible SQL server in Rust Elyra Félagi Agents as teammates on one board Elyra SQL Client Native desktop SQL workbench Elyra SQL Anywhere Replication-ready SQL engine Elyra Sjá SEO & GEO workspace for macOS Elyra DataGrid Server-driven data grid for Laravel
Release notes
Changelog
Elyra

OutboxDrawer

The outbox, in a drawer. A write saved offline waits there until the backend is back. When Laravel then turns one down, the user has to decide what happens to it. The drawer lists what the server refused, with what it said, and a way out of each. Below that it lists what's still waiting.

The StatusBar opens it when its "3 changes waiting" or "1 change refused" is clicked, so an app with a StatusBar has it already. Put one in yourself to open it from somewhere else: a menu, a banner, a shortcut.

Examples
<script>
  import { Button, OutboxDrawer } from "@elyra/ui";

  let open = $state(false);
</script>

<Button onclick={() => (open = true)}>Show changes</Button>
<OutboxDrawer bind:open />

The writes here are made up. Each button takes one off the list until you reload the page. In an app they come from $outbox.

The ways out

The server said Shown as The user can
409 or 412: the record changed meanwhile Changed meanwhile Keep mine sends it again without its precondition, overwriting what changed. Take theirs drops it, and what read the record runs again, showing the server's version.
422: not valid Not valid, with each field's message beside the field Send again or Discard.
403: not allowed Not allowed Send again or Discard.
404: not there any more Gone Send again or Discard.
Anything else it refused Refused Send again or Discard.

A write that's still waiting can be discarded too. Discarding asks first, in the runtime's dialog, since what was typed is lost. Keep mine and Take theirs don't ask: the button already says what happens.

A refused write shows its fields as they were sent, and a file by its name. A field the server complained about is marked, with its message under it. A message for a field the write didn't have is listed after the fields. Laravel's summary of a 422 ("The email has already been taken. (and 1 more error)") isn't repeated above them.

If a way out fails (the backend is gone again, or the write was dealt with in another window), the drawer says so under that write and leaves the write where it is.

Send again sends the same body. A write that wasn't valid usually needs fixing first: open the record in its form, and save it from there. To send a fixed body from your own screen, call outbox.retry(id, body) from @elyra/runtime (see the outbox).

Naming the writes

By default a write is named by its method and path: "Update /api/customers/42". describe names it the way your users would.

<script>
  import { Button, OutboxDrawer } from "@elyra/ui";

  let open = $state(false);

  // "PUT /api/customers/42" as the user would say it.
  const VERBS = { POST: "New", PUT: "Changed", PATCH: "Changed", DELETE: "Deleted" };
  function describe(write) {
    const [, , kind, id] = write.path.split("/");
    const thing = kind.replace(/s$/, "");
    return `${VERBS[write.method]} ${thing}${id ? ` ${id}` : ""}`;
  }
</script>

<Button onclick={() => (open = true)}>Show changes</Button>
<OutboxDrawer bind:open {describe} title="Not sent yet" />

describe gets the whole write: { id, method, path, body, status, attempts, error, errors, reason, createdAt }.

Accessibility

  • It's a Drawer: a dialog that keeps focus inside and hands it back when it closes. Esc closes it.
  • "Refused" and "Waiting" are regions named by their headings, and each write is a list item named by its description.
  • A way out that fails is a role="alert".

API

OutboxDrawer

Prop Type Default Description
open (bindable) boolean false
side "right" | "left" "right" Where it slides in from.
title string "Changes"
describe (write: OutboxItem) => string — Names a write. Without it: the method as a verb, and the path.
class string ""