docs/content/en/project/contributing/ui/notification-center.md
The Notification Center is a dedicated panel in Meshery’s UI that helps you monitor, understand, and respond to events across your system. It acts as a central place where you can see important updates related to your infrastructure, workloads, and Meshery’s internal operations.
Want to understand how users interact with the Notification Center? Learn more here.
The NotificationCenter component of Meshery UI receives events over a Server-Sent Events (SSE) stream and implements robust filtering on top of them. Events are persisted in Meshery Server and state management on the client is done using Redux Toolkit and RTK Query.
Real-time delivery is handled by a native EventSource connection. This replaced the former GraphQL subscribeEvents subscription, so contributors should not expect to find Relay or GraphQL code in this path anymore.
The chain looks like this:
NotificationCenterProvider (index.tsx) spawns the operationsCenterActor state machine using useActorRef.subscribeToEvents from ui/lib/eventsSubscription.ts.subscribeToEvents opens an EventSource against GET /api/system/events/subscribe. Because the stream is same-origin, the browser automatically carries the meshery-provider auth cookie.data: <event-json> and is parsed into the raw event object. This is the same camelCase shape that the REST endpoint /api/system/events returns, so it is consumed as-is by the rest of the UI.pushEvent), invalidates the relevant RTK Query cache tag, and raises a toast through notify.Connection failures are handled inside subscribeToEvents. EventSource reconnects on its own while the connection is merely dropping, so an error is only surfaced to the caller once the browser permanently closes the stream. That notification is additionally delayed by a few seconds, which prevents a persistent failure (an expired session, for example) from turning caller-driven re-subscription into a request storm. The function returns a { dispose } handle, and the state machine restarts the subscription actor when an error is finally reported.
All other operations — listing, filtering, marking read/unread, deleting, and configuration — go through REST endpoints under /api/system/events defined in ui/rtk-query/notificationCenter.ts.
Redux Toolkit and RTK Query.ui/store/slices/events.ts) using an entity adapter.Bulk operations in the Notification Center allow users to perform actions like deleting multiple notifications or changing the status of multiple notifications in a batch. This documentation outlines the key features and functionality of bulk operations, including the restriction of performing only one bulk operation at a time, the disabling of buttons during ongoing operations, and the display of a loading icon to indicate ongoing activity.
This section outlines the essential files and folders that you'll interact with when working on the Notification Center. Every file in this directory has a colocated *.test.tsx file; add or update tests alongside any change you make.
NotificationCenter/ (Root Directory)Path: ui/components/layout/NotificationCenter/
NotificationCenterProvider), the drawer component, the severity chips, the bulk action bar, and the event list. It also spawns the operationsCenterActor that owns the SSE subscription.PropertyFormatters, LinkFormatters, PropertyLinkFormatters, and the internal EventTypeFormatters registry. Contains the FormattedMetadata component which decides how to format the metadata based on event type or specific properties, plus FormattedLinkMetadata for the links rendered in the header of an expanded notification.Share, Error Docs, metadata links, delete, change status), and the expanded detail view. Also exports getErrorCodesFromEvent and canTruncateDescription.SEVERITY, STATUS, SEVERITY_STYLE, the EVENT_TYPE catalog, and the eventDetailFormatterKey helper used to key event specific formatters./api/system/events/types.formatters/ (NotificationCenter/formatters)This directory houses reusable formatter components dedicated to specific types of metadata or event types.
TitleLink, DataToFileLink, and EmptyState.ErrorMetadataFormatter for displaying structured error details.ModelImportMessages, ModelImportedSection).DryRunResponse and SchemaValidationFormatter, which delegate to the design lifecycle components.RelationshipEvaluationEventFormatter, responsible for rendering notifications related to the evaluation of relationships between components in a design.MeshSyncPropertyFormatters for connection and MeshSync deployment fields.AcademyEventsFormatter for quiz evaluation results.metadata.tsx.Two dependencies live outside the Notification Center but are worth knowing about:
ui/components/data-formatter/ provides the generic structured-data renderer (FormatStructuredData) that the Notification Center uses as its fallback, along with the primitives formatters compose with (SectionBody, KeyValue, ArrayFormatter, TextWithLinks, TitleLink helpers, reorderObjectProperties). Changes there affect other parts of Meshery UI, so treat it as a shared library rather than Notification Center code.ui/components/designs/lifecycle/ provides DeploymentSummaryFormatter, FormatDryRunResponse, and ValidationResults, which are reused by design-related notifications.When the server sends an event, it follows a consistent schema that contains metadata intended for user presentation. This metadata typically includes fields such as description, createdAt, userID, systemID, action, category, and the resources involved.
In some cases, the metadata may also contain more detailed information—such as a traceback, a summary, or a complete error log—which is dynamically generated at runtime and encapsulated within the event.
Presenting this structured information in a clear and accessible way is essential, as it provides valuable insights into system behavior and ongoing operations.
To accomplish this task, we employ metadata formatters that transform structured data into visually appealing formats. There are currently two types of formatters in use:
The dynamic formatter is FormatStructuredData, imported from ui/components/data-formatter. It walks the metadata recursively and picks a renderer based on the shape of each value:
SectionBody, which uses TextWithLinks to detect URLs in the string and replace them with link components.ArrayFormatter as a bulletized list, recursing into each item.KeyValue.FormatStructuredData accepts a propertyFormatters map. Whenever a property name matches a key in that map, the mapped function takes over rendering for that property, which is how the Notification Center injects its own formatters into an otherwise generic renderer.
Certain metadata, such as Design deployment summaries and Errors, hold high importance and have dedicated renderers. These dedicated renderers can still utilize the dynamic formatter to format specific parts of the response.
While this system was initially developed for our events and notification center, the components it comprises are highly reusable and can be employed in other contexts where dynamic formatting of structured data is required.
When a notification event is received from the server, it includes a metadata field containing structured, event-specific information. The purpose of formatters is to present this data in a clean, readable, and user-friendly format inside the expanded view of each notification.
The core logic for rendering metadata is handled by the FormattedMetadata component in metadata.tsx, which follows this decision tree:
Event-Specific Formatter Check
If a formatter is registered for the event's action and category combination (under EventTypeFormatters), that dedicated formatter is used and receives the whole event, giving it full control over how the metadata is displayed.
Empty Metadata Check
If the event has no metadata, or the metadata is empty at all depths, EmptyState renders the event description on its own.
Fallback to Property-Based Formatting
Otherwise, FormattedMetadata reorders the metadata into a stable display order, strips out properties that are rendered elsewhere (links, id, kind), and hands the result to FormatStructuredData along with:
PropertyFormatters – for structured or specialized visual formats.PropertyLinkFormatters – consumed separately by the ellipsis menu in notification.tsx to render actionable links (e.g. file downloads, log views).Formatters are keyed by eventDetailFormatterKey, which produces a string in the form `${action}-${category}`. To add a new one:
EVENT_TYPE in constants.tsx with the event's action and category, matching what Meshery Server emits.formatters/. It receives a single event prop.EventTypeFormatters map in metadata.tsx using eventDetailFormatterKey(EVENT_TYPE.YOUR_EVENT).Path: ui/components/layout/NotificationCenter/formatters/common.tsx
The following reusable components standardize how notification links, empty states, and downloadable traces are displayed:
TitleLink: Renders a styled title with an external link icon. Any additional anchor attributes are forwarded, so target="_self" can be used for in-app navigation.
Props:
href (required): URL of the link.children: The link text.EmptyState: Displays the event description when no specific metadata is available for an event. Props:
event (required): The event object; only description is read.DataToFileLink: Converts event data into a downloadable .txt file.
Props:
data (required): Can be a string or a JSON-serializable object.The ErrorMetadataFormatter is used for formatting error-related notifications in the Meshery UI Notification Center. It structures error details, probable causes, and suggested remediations in a readable format. Each entry is rendered as Markdown, so bullets and inline formatting supplied by the server are preserved.
getErrorCodesFromEvent, which looks at both metadata.error and errors nested inside metadata.ModelDetails.Props:
metadata (object): Contains error metadata fields, each an array of strings:
LongDescription: Provides details about the error.ProbableCause: Lists possible reasons for the error.SuggestedRemediation: Suggests solutions to fix the error.event (object, optional): Contains the notification event data. Only description is read.Path: ui/components/layout/NotificationCenter/formatters/error.tsx
Example:
<ErrorMetadataFormatter
metadata={{
LongDescription: ['An unexpected error occurred while deploying the design.'],
ProbableCause: ['Misconfigured Kubernetes cluster.'],
SuggestedRemediation: ['Check your kubeconfig file and retry deployment.'],
}}
event={{ description: 'Design deployment failed' }}
/>
<a href="../images/error-formatter.png"></a>
When to Use:
The ErrorMetadataFormatter is used when dealing with structured error events that follow a pattern (description, cause, remediation). A new formatter should be created only if the error metadata deviates significantly from the ErrorMetadataFormatter metadata structure.
The Model Registration Formatter formats and displays model registration details, including components and relationships, in Meshery UI's Notification Center. It ensures structured representation of imported models and error handling during the import process. It also distinguishes between models and standalone entity files (.yaml, .yml, .json), labelling the heading accordingly and linking successful model imports to the registry.
Path: ui/components/layout/NotificationCenter/formatters/model_registration.tsx
Components:
ModelImportedSection (exported): Displays the details of the imported model along with components, relationships, and any errors that occur.
Props:
modelDetails (object): A map of model name to import details, each containing optional Components, Relationships, and Errors arrays.ModelImportMessages (exported): Renders the import summary line.
Props:
message (node): The summary message supplied by the server.UnsuccessfulEntityWithError (internal): Used by ModelImportedSection to handle error cases during model import. It identifies the type and count of entities that failed to import and delegates the error body to ErrorMetadataFormatter.
Props:
modelName (string): The name of the model or file being imported.error (object): Contains name, entityType, and the nested error details.<a href="../images/model-register-formatter.png"></a>
The Relationship Evaluation Formatter is responsible for rendering notifications related to the evaluation of relationships between components in a design. It provides a detailed breakdown of changes in components and relationships, such as additions, updates, and removals, during the evaluation process.
Path: ui/components/layout/NotificationCenter/formatters/relationship_evaluation.tsx
RelationshipEvaluationTraceFormatter to display detailed traces.Props:
event (object): Contains:
metadata.evaluation_response): The evaluation result, containing:
actions (Array): The list of changes produced by the evaluation.design (Object): The evaluated design, used to resolve components and relationships by ID.RelationshipEvaluationTraceFormatter:
Takes actions and design and derives the displayed categories by filtering actions on their op field:
add_component, delete_component, update_component / update_component_configurationadd_relationship, delete_relationship, update_relationshipEach category is rendered as a collapsible section that shows its item count and is hidden entirely when empty. Deletions read the component or relationship from the action payload itself, while additions and updates are resolved against the design.
<a href="../images/relationship-evaluation-formatter.png"></a>
The Relationship Evaluation Formatter is specifically designed to handle notifications related to changes in components and their relationships during an evaluation process. Use this formatter in the following scenarios:
evaluationResponse object containing the actions and the evaluated design.Evaluation Summary:
The notification starts with a summary of the evaluation process.
Example:
"Relationship evaluation completed for design 'Deploy Meshery using Meshery-X' at version '0.0.11'"
This gives the user context about which design and version were evaluated.
Detailed Changes: The notification breaks down the changes into collapsible categories:
If the evaluation produced no actions at all, an empty state is shown instead.
Component Details: For each component, the notification displays its icon, kind, name, and the model and version it belongs to.
Relationship Details: For each relationship, the notification displays its type, the source and target components involved, and the associated model and version.
The Dry Run Formatter is responsible for rendering notifications related to the dry run validation of a design. A dry run simulates the deployment or undeployment of a design to identify potential errors without actually applying the changes.
Paths:
ui/components/layout/NotificationCenter/formatters/pattern_dryrun.tsx (Notification Center entry points)ui/components/designs/lifecycle/DryRun.tsx and ui/components/designs/lifecycle/ValidateDesign.tsx (rendering)DryRunResponse:
The property formatter registered for the dryRunResponse metadata field. It normalizes the raw response and hands it to FormatDryRunResponse.
Props:
response: The raw dry run response from the server.FormatDryRunResponse: Renders the dry run validation results, including the total number of errors.
Props:
type: The type of error (e.g., RequestError, ComponentError).fieldPath: The specific field in the design where the error occurred.message: A detailed error message.SchemaValidationFormatter:
The event specific formatter registered for design validation events. It reads metadata.validationResult, metadata.design_name, metadata.total_components, and metadata.configurable_components, totals the errors across services, and renders ValidationResults.
Props:
event (object): The notification event.<a href="../images/dry-run-formatter.png"></a>
These formatters are used in the following scenarios:
The Deployment Summary Formatter is responsible for rendering notifications related to the deployment or undeployment of components in a design.
Path: ui/components/designs/lifecycle/DeploymentSummary.tsx
ErrorMetadataFormatter.Props:
deploy, undeploy).The Deployment Summary Formatter should be used in the following scenarios:
event.action is either deploy or undeploy and the event.metadata includes design_name.Path: ui/components/layout/NotificationCenter/formatters/meshsync_events.tsx
This module exports MeshSyncPropertyFormatters, a set of property formatters that are spread into PropertyFormatters in metadata.tsx rather than registered as an event specific formatter. It covers connectionID, k8sContextID, k8sContextName, meshsyncDeploymentMode, operatorStatus, and brokerEndpoint.
Connection-related fields are rendered as clickable chips that deep-link into the connections page with the value pre-filled as a search term. Field names are humanized by humanizeFieldName, which converts camelCase keys into title case (for example, k8sContextName becomes K8s Context Name).
Path: ui/components/layout/NotificationCenter/formatters/academy_events.tsx
AcademyEventsFormatter renders quiz evaluation results from metadata.result, showing the quiz title, attempt time, score against the pass percentage, pass/fail outcome, and a per-question breakdown. It renders an inline message rather than throwing when the event payload is incomplete, which is a useful pattern to follow for formatters that depend on deeply nested metadata.
Purpose:
When an event does not match an entry in EventTypeFormatters, PropertyFormatters are used to format and render specific metadata fields in a structured and visually appealing way. PropertyLinkFormatters are handled separately: notification.tsx maps the event metadata through them to build the actionable links shown in the ellipsis menu.
ErrorMetadataFormatter to display structured error details.MeshSyncPropertyFormatters.Examples of property link formatters include doc (documentation reference), DownloadLink (downloads a file through /api/system/fileDownload), and ViewLink (opens logs through /api/system/fileView).
Use PropertyFormatters and PropertyLinkFormatters in the following scenarios:
EventTypeFormatter defined.