rustango 0.60.0

Batteries-included web framework for Rust: ORM + migrations + auto-admin + multi-tenancy + audit log + auth (sessions, JWT, OAuth2/OIDC, HMAC) + APIs (ViewSet, OpenAPI auto-derive, JSON:API) + jobs (in-mem + Postgres) + email + media (S3 / R2 / B2 / MinIO + presigned uploads + collections + tags) + production middleware (CSRF, CSP, rate-limiting, compression, idempotency, etc.).
Documentation
{% extends "op_layout.html" %}
{% block title %}Organizations — {{ brand_name | default(value='Rustango Operator Console') }}{% endblock %}
{% block content %}
<h1>Organizations</h1>

{#- Where a decommission reports back: it removes the tenant, so there
    is no tenant page left to return to. -#}
{% if error %}<div class="alert alert-error">{{ error }}</div>{% endif %}
{% if notice %}<div class="alert alert-notice">{{ notice }}</div>{% endif %}

{#- A div, not a p: `<form>` is not phrasing content, so the HTML parser
    closes an open `<p>` when it meets one — the actions row split in two
    and left stray empty paragraphs on the page. -#}
{#- One row for every action this console can offer. Pre-warming is gated
    on pools and the rest on the provisioner, so the two are separate
    conditions — but they belong in the same row, not stacked with the
    description between them. -#}
{% if provisioning_enabled or edit_enabled %}
<div class="page-actions">
  {% if provisioning_enabled %}
  <a href="/orgs/new" class="btn btn-primary">+ New tenant</a>
  <a href="/orgs/provision" class="btn btn-secondary">Runs</a>
  <form method="post" action="/orgs/migrate" class="inline-form"
        data-confirm="Run migrations for every active tenant?">
    {{ csrf_input | default(value='') | safe }}
    <button type="submit" class="btn btn-secondary">Migrate all tenants</button>
  </form>
  {% endif %}
  {% if edit_enabled %}
  <form method="post" action="/orgs/prewarm" class="inline-form"
        data-confirm="Open a connection for every active database-mode tenant? This can take a moment.">
    {{ csrf_input | default(value='') | safe }}
    <button type="submit" class="btn btn-secondary">Pre-warm pools</button>
  </form>
  {% endif %}
</div>
{% endif %}

{% if provisioning_enabled %}
<p>Tenants the registry knows about. Create one here, or from the CLI
with <code>cargo run -- create-tenant</code>; removal is
<code>cargo run -- drop-tenant</code>.</p>
{% else %}
<p>Tenants the registry knows about. Mutations go through
<code>cargo run -- create-tenant</code> / <code>cargo run -- drop-tenant</code>
(or whatever your project binary is — runs through
<code>rustango::manage::Cli</code>). To create tenants from here, add
<code>.with_tenant_provisioning("migrations")</code> to the
<code>Cli</code> builder.</p>
{% endif %}

{% if orgs | length == 0 %}
  {% if provisioning_enabled %}
  <div class="empty">No tenants yet —
  <a href="/orgs/new">create the first one</a>.</div>
  {% else %}
  <div class="empty">No tenants yet — provision one with
  <code>cargo run -- create-tenant &lt;slug&gt;</code>.</div>
  {% endif %}
{% else %}
<table>
  <thead>
    <tr>
      <th>Slug</th>
      <th>Display name</th>
      <th>Mode</th>
      <th>Host pattern</th>
      <th>Active</th>
      <th>Created</th>
      {% if edit_enabled %}<th class="actions-col">Actions</th>{% endif %}
    </tr>
  </thead>
  <tbody>
    {% for org in orgs %}
    <tr>
      <td><strong>{{ org.slug }}</strong></td>
      <td>{{ org.display_name }}</td>
      <td>{{ org.storage_mode }}</td>
      <td>{% if org.host_pattern %}{{ org.host_pattern }}{% else %}<em class="faint">—</em>{% endif %}</td>
      <td>{% if org.active %}✓{% else %}—{% endif %}</td>
      <td>{{ org.created_at }}</td>
      {% if edit_enabled %}<td class="actions-col"><a class="btn-row-action" href="/orgs/{{ org.slug }}/edit">Edit</a></td>{% endif %}
    </tr>
    {% endfor %}
  </tbody>
</table>
{% endif %}

{% include "_op_pager.html" %}
{% endblock %}