Skip to content

Grafana: Realms Grant Permission as Business Forms (chooser + button)#4744

Open
lukemelia wants to merge 3 commits intomainfrom
grafana/realms-grant-permission-form
Open

Grafana: Realms Grant Permission as Business Forms (chooser + button)#4744
lukemelia wants to merge 3 commits intomainfrom
grafana/realms-grant-permission-form

Conversation

@lukemelia
Copy link
Copy Markdown
Contributor

Summary

The Grant Permission tile on the Realms dashboard was a stat panel with a Grafana-native action; its entire input UX lived in the top bar as template variables (matrix_username textbox + permission_level radio). Two problems:

  1. The username was a free-text textbox — operators had to remember the exact Matrix ID with no help from existing user data.
  2. Inputs lived in the top bar but the button lived in the panel body — disconnected control surface.

This converts the tile to a volkovlabs-form-panel (the same plugin the Reindex panel already uses on this dashboard), bundling the chooser, permission selector, and button into one self-contained control:

  • Matrix username: select with optionsSource: \"Query\", sourced from `SELECT matrix_user_id FROM users ORDER BY 1`. `allowCustomValue: true` so operators can still type a brand-new Matrix ID for users not yet in the table.
  • Permission level: `radio` with Read / Read+Write.
  • Button: `customCode` pre-validates, browser-confirms with the resolved values, and POSTs to `/_grafana-upsert-realm-user-permission?realm=...&user=...&read=...&write=...` with the CS-10929 bearer header (same auth path the Reindex button uses).

Side effects

  • Dashboard template variables `matrix_username`, `permission_level`, `permission_label`, `read_flag`, `write_flag` are now unused (verified: zero `${var}` references on the dashboard after the conversion). Removed.
  • Grant tile height grows from h=4 to h=8 to fit the form; y positions of the panels below it (Realm Permissions, Indexing status, Reindex form, Recent Errors, Recent Jobs) cascade by +4.

Depends on

  • Staging deploy of cardstack/infra#689 (installs the volkovlabs-form-panel plugin on staging/prod Grafana). Without that, the new panel renders the same plugin-not-found error the existing Reindex panel currently shows on staging.

Test plan

  • Open http://localhost:3001/d/boxelrealms001 (Realms) — Grant Permission renders as a horizontal form: Matrix username dropdown on the left, button on the right
  • The username dropdown lists users from the users table; typing a value not in the list (with `allowCustomValue`) keeps the typed text
  • Click Grant with no username selected → notifyWarning, no fetch
  • Click Grant with a username → browser confirm shows the resolved values; OK fires the POST and surfaces success/error notification
  • Realm Permissions table below scrolls into view at the new y position; nothing overlaps

🤖 Generated with Claude Code

…er + button

The Grant Permission tile on the Realms dashboard was a stat panel
with a Grafana-native action whose entire input UX lived in the
dashboard top bar (matrix_username textbox + permission_level radio
template variables). Two problems:

1. The username was a free-text textbox — operators had to remember
   the exact Matrix ID with no help from existing user data.
2. The control surface was scattered: variables in the top bar, a
   "Grant" button in the panel body. Easy to forget which top-bar
   variable feeds which panel.

Replace with a `volkovlabs-form-panel` (Business Forms — same plugin
the Reindex panel already uses on this dashboard) that bundles
chooser + permission selector + button into one self-contained
control:

- Matrix username: `select` element with `optionsSource: Query`,
  sourced from `SELECT matrix_user_id FROM users ORDER BY 1`.
  `allowCustomValue: true` so operators can still type a brand-new
  Matrix ID for users not yet in the table.
- Permission level: `radio` with Read / Read+Write.
- Button: customCode that pre-validates, browser-confirms with the
  resolved values, and POSTs to the existing
  `/_grafana-upsert-realm-user-permission?...` endpoint with the
  CS-10929 bearer header (same auth path the Reindex button uses).

Side effects:
- Dashboard template variables `matrix_username`, `permission_level`,
  `permission_label`, `read_flag`, `write_flag` are now unused
  (verified: zero `${var}` references after the conversion). Removed.
- Grant tile grows from h=4 to h=8 to fit the form. Cascaded the y
  positions of the panels below it (Realm Permissions table,
  Indexing status, Reindex form, Recent Errors, Recent Jobs).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 9, 2026

Observability diff (vs staging)

No dashboard / folder changes detected against the staging Grafana.

(Run: https://github.com/cardstack/boxel/actions/runs/25613855685)

volkovlabs-form-panel compiles a Custom Button's `customCode` via
`new Function("context", body)` — a regular (non-async) function.
Top-level `await` in the body throws SyntaxError, which the plugin's
wrapper silently catches and turns into a no-op (only a `Code Error`
console log shows the failure). Result: clicking Grant did nothing,
no network request fired.

Fix: wrap the `try { ... await fetch ... } catch (err) {...}` block
in an `(async () => { ... })()` IIFE. The outer Function-built closure
stays sync; the inner IIFE is the async context that legalises await.

Pre-existing buttons on this and other dashboards (Reindex this realm,
Reindex all realms, Add Credit ×4) are broken in exactly the same way.
Those are out of scope for this PR — fixed in a follow-up so the
Grant Permission feature ships working in isolation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`Code Error SyntaxError: Unexpected identifier 's'` shows up when
clicking the Grant button locally. Cause: the local-dev default
`grafana_secret` is `shhh! it's a secret`, and customCode uses the
bare-quote substitution `'Bearer ${grafana_secret}'`. After
`replaceVariables`, the apostrophe in `it's` closes the JS string
early, leaving `s a secret'` as garbage that crashes the parser. The
plugin's `_e` wrapper catches the SyntaxError and turns it into a
no-op — same silent-failure mode as the await bug just fixed.

Fix: use Grafana's `:doublequote` formatter so the substituted value
arrives pre-quoted as a JSON-style double-quoted string with proper
escaping, which is also a valid JS string literal. Drop the
surrounding single quotes (or split-and-concat at variable
boundaries) so the JS source ends up syntactically clean for any
value the SSM secret might hold in staging/prod.

Same root cause as the rest of the operator-action buttons; this PR
only fixes its own btn_grant. The 6 pre-existing broken buttons are
fixed in #4745.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant