Skip to content

PMM-15212 Migrate Alert Templates to PMM UI#5635

Draft
matejkubinec wants to merge 15 commits into
mainfrom
PMM-15212-migrate-alert-templates
Draft

PMM-15212 Migrate Alert Templates to PMM UI#5635
matejkubinec wants to merge 15 commits into
mainfrom
PMM-15212-migrate-alert-templates

Conversation

@matejkubinec

@matejkubinec matejkubinec commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Ticket number: PMM-15212

Feature build: SUBMODULES-4468

Summary

Migrates the Alert Templates feature out of the Grafana iframe and into the native PMM UI (ui/apps/pmm). All four flows are reimplemented as native React pages: listing, create, edit, and create alert rule from template (plus delete). The Alert templates nav item is repointed from /graph/alerting/alert-rule-templates to the new native routes.

Built with @percona/percona-ui components first, MUI where percona-ui has no equivalent, react-hook-form + zod for all forms, and TanStack Query for server state. Each component is split into .tsx / .types.ts / .schema.ts / .messages.ts / .constants.ts / .utils.ts rather than inlining logic.

Changes

  • Data layertypes/alert-templates.types.ts, api/alert-templates.ts, hooks/api/useAlertTemplates.ts, utils/alert-templates.utils.ts, modeled from api/alerting/v1. Calls /v1/alerting/templates and /v1/alerting/rules.
  • Listing (pages/alerting/templates) — percona-ui Table with source chip, created-at (with time; templates without a creation time show an em dash) and a per-row ⋮ actions menu (Create alert rule / Edit / Delete). Edit/Delete are offered only for USER_API-source templates and PMM admins.
  • Create / Edit / Delete templateDialog-based modals; a shared YAML editor field with .yaml file upload. Create/Edit are YAML-only, matching the backend.
  • Create alert from template (pages/alerting/create-rule) — sectioned form: template select, dynamic float/bool/string param inputs (with min/max validation), severity/duration, folder (via useFolders) with an inline "Create new folder…" option, evaluation group + interval, filters field array, and a read-only expression view. Builds the CreateRule payload; a new folder (if requested) is created on submit, then the rule.
  • Routing / navigationalerting/alert-rule-templates and alerting/new-from-template added to router.tsx; NAV_ALERTS_TEMPLATES repointed to the native routes.
  • Tests — list rendering + row-menu editability gating; create-rule payload/defaults and created-at formatting unit tests.

Screenshots

Captured from a live PMM server (full dev stack, real built-in templates).

Alert templates — add

screenshot-2026-07-13-09-13-00

Row actions ⋮ menu

screenshot-2026-07-13-09-14-19

Create alert rule from template

screenshot-2026-07-13-09-15-24

Verification

Ran against ui/apps/pmm: typecheck, lint and format:check pass; full test suite green (278+ passed, 0 failed). Additionally exercised end-to-end against a live PMM server (make env-up dev container, admin/admin) — the listing renders the 42 real built-in templates and the create-rule form correctly seeds params/severity/duration and the read-only expression from a real template. This run surfaced and fixed a created-at bug (backend sends Go zero-time for built-in templates).

Notes for reviewers

  • Create/Edit templates are intentionally YAML-only (backend CreateTemplate/UpdateTemplate accept a raw YAML string).
  • Folder/group/evaluation-interval inputs are rebuilt natively because Grafana's in-iframe evaluation-behavior components aren't available in the native app. A new folder is created on submit; the evaluation group + interval are created together with the rule. Prefilling the interval from an existing folder's groups would require Grafana's ruler API and is left as a potential follow-up.
  • custom_labels is omitted from the create-rule form (as in the legacy UI), which also avoids axios-case-converter mangling user-defined label map keys.
  • The legacy Grafana-iframe pages are not removed here — suggested as a separate follow-up once this is validated.

API documentation

This PR does not add, remove, or alter API endpoints (it consumes existing /v1/alerting/* and Grafana folder endpoints).

  • API Docs updated (n/a)

Related work

  • Companion branches claude/alert-templates-pmm-migration-bw7vfm exist in percona/grafana and percona/percona-ui but currently carry no changes.

🤖 Generated with Claude Code

https://claude.ai/code/session_01BCjDFAPWc5qPGonYSQ7bhY

claude added 4 commits July 11, 2026 16:49
Phase 1 of migrating the Alert Templates feature from the Grafana
iframe into the native PMM UI.

- types/alert-templates.types.ts: Template, ParamDefinition, ParamValue,
  Filter, CreateRule payload and enums (ParamType, ParamUnit,
  TemplateSource, FilterType, Severity), modeled from api/alerting/v1.
- api/alert-templates.ts: list/create/update/delete templates and
  create-rule-from-template against /v1/alerting/*.
- hooks/api/useAlertTemplates.ts: TanStack Query hooks with list-cache
  invalidation on mutations.
- utils/alert-templates.utils.ts (+ tests): editability, duration and
  param-type helpers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCjDFAPWc5qPGonYSQ7bhY
Phases 2-6 of migrating the Alert Templates feature from the Grafana
iframe into the native PMM UI.

- Listing (pages/alerting/templates): percona-ui Table with source chip,
  created-at, and row actions; edit/delete gated to USER_API templates
  and PMM admins.
- Create/Edit/Delete template modals: react-hook-form + zod, shared
  YAML editor field with .yaml file upload; YAML-only per the backend.
- Create alert from template (pages/alerting/create-rule): sectioned
  react-hook-form page with template select, dynamic float/bool/string
  param inputs, severity/duration, folder (from useFolders) + group +
  interval, and a filters field array; builds the CreateRule payload.
- Routing: alerting/alert-rule-templates and alerting/new-from-template
  wired into router.tsx; NAV_ALERTS_TEMPLATES repointed from the Grafana
  iframe to the native routes.
- Tests: list rendering + editability gating, and payload/defaults units.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCjDFAPWc5qPGonYSQ7bhY
- Row actions moved into a vertical-dots (⋮) menu with Create alert
  rule / Edit / Delete items; edit & delete shown only for editable
  (USER_API) templates.
- "Created at" column now includes the time (formatTimestampWithTime).
- Create-alert-from-template: folder select gains a "+ Create new
  folder…" option that reveals a "New folder name" field; the folder is
  created on submit (via new useCreateFolder hook), then the rule. Group
  and evaluation interval continue to be created with the rule.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCjDFAPWc5qPGonYSQ7bhY
Built-in and SaaS templates carry no creation time; the backend
serializes it as Go's zero time (0001-01-01...) rather than an empty
string, so the created-at column rendered "January 1, 1 at 12:00 AM".
Add formatCreatedAt() which treats empty, zero-time, and invalid
values as an em dash. Verified against a live PMM server.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCjDFAPWc5qPGonYSQ7bhY
claude added 3 commits July 13, 2026 10:34
Remove the material-react-table "Show/Hide columns" toolbar button and
the per-column hide option by passing enableHiding={false}, matching the
pattern used by the RTA sessions table.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCjDFAPWc5qPGonYSQ7bhY
Add a "View" row action (shown for all templates) that opens a
read-only modal displaying the template YAML, mirroring the Edit modal
without a form. Wire it through TemplateRowActions -> columns -> page
state.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCjDFAPWc5qPGonYSQ7bhY
Add a "Copy to clipboard" action (shown for all templates) to the row
actions menu and the View modal, copying the template YAML. Extract a
shared copyToClipboard() util (guards navigator.clipboard /
isSecureContext) reused by both entry points, with notistack feedback.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCjDFAPWc5qPGonYSQ7bhY
matejkubinec and others added 8 commits July 13, 2026 14:33
Change the create-alert-from-template evaluation interval from a raw
seconds number to a Grafana-style Prometheus duration string with
quick-pick presets (10s/30s/1m/5m/10m/15m/30m/1h) and matching
validation (valid duration, >= 10s, multiple of 10s). The interval is
still submitted to the backend as "<seconds>s".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCjDFAPWc5qPGonYSQ7bhY
Match Grafana's evaluation-group behavior in create-alert-from-template:
- Fetch existing evaluation groups for the selected folder from the
  Grafana ruler API (GET /ruler/grafana/api/v1/rules/{folderUid}).
- The group is chosen from a combobox; selecting an existing group
  auto-fills and locks the interval to that group's interval, shown as
  read-only text ("All rules in the selected group are evaluated
  every X").
- The interval is only editable when creating a new group, via a
  "New evaluation group" modal (name + duration-string interval with
  quick-picks and >=10s / multiple-of-10s validation).
- The group control is disabled until a target folder is chosen.

Adds api/alert-rule-groups + useFolderRuleGroups; extracts a shared
getIntervalError validator reused by the form schema and the modal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCjDFAPWc5qPGonYSQ7bhY
- Replace the "create new folder" select option with a dedicated
  "New folder" button next to the folder select, matching Grafana; the
  folder is created immediately via a modal (POST /api/folders) and
  selected. Drops the deferred newFolderTitle / sentinel handling.
- Put "New evaluation group" inline (to the right) of the group select.
- Fix the label/placeholder overlap when no folder/group is selected by
  dropping the custom displayEmpty/renderValue placeholder and relying
  on the field label (MUI standard behavior).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCjDFAPWc5qPGonYSQ7bhY
The folder and evaluation-group selects are laid out in a row with
their action buttons; pass formControlProps={{ fullWidth: true }} so
each select fills the available space instead of collapsing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCjDFAPWc5qPGonYSQ7bhY
- Create-rule folder & evaluation: vertically center the "New folder"
  and "New evaluation group" buttons with their inputs (mt:0), and add
  an "or" separator before the "New folder" button to match the group
  row.
- New folder modal: full-width input, wider (sm) so the form fills the
  content.
- Alert templates list: add a Category dropdown that filters templates
  by technology (MySQL / MongoDB / PostgreSQL / ProxySQL / HAProxy /
  Valkey / PMM), inferred from the template name/summary.
- Move the toolbar action cluster (Category + Add template) to the right
  like the RTA sessions table (muiTopToolbarProps row-reverse).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BCjDFAPWc5qPGonYSQ7bhY
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.

2 participants