Skip to content

feat: add --slack-full-width for full-width Slack alerts with markdown test result tables#2107

Open
michrzan wants to merge 11 commits intoelementary-data:masterfrom
michrzan:slack-rick-text-refactor
Open

feat: add --slack-full-width for full-width Slack alerts with markdown test result tables#2107
michrzan wants to merge 11 commits intoelementary-data:masterfrom
michrzan:slack-rick-text-refactor

Conversation

@michrzan
Copy link
Contributor

@michrzan michrzan commented Feb 10, 2026

Summary

This PR adds a --slack-full-width option that allows Slack alerts to use the full message width by rendering the entire message with Block Kit (no attachments) and displaying test result samples as markdown tables.

This significantly improves readability when test results contain many columns or long values.

Problem

When the Test Results Sample includes multiple columns or long strings, the current Slack alerts become difficult to read due to the narrow attachment layout. In practice, this makes it hard for alert recipients to quickly understand the context and take action.

old

or when there is more columns like this:

old_big

Solution

With the --slack-full-width option enabled, Slack alerts are rendered at full width and test results are consistently shown as markdown tables:

new

or when there is more columns like this:

new_big

Admittedly, it looks better on a wide screen.

Implementation details

This is achieved by:

  • Building the Slack message without attachments and rendering everything using Block Kit blocks
  • Inserting an empty rich text block at the start of the message to force full-width rendering
  • Always rendering test results as markdown tables

Trade-offs

As a result of moving away from attachments, the colored severity indicator (yellow/red pipe on the left) is no longer available. This is a known limitation of the approach.

Notes

This resolves #1079.

This is jsut something I am using internally and wanted to share. Happy to discuss alternatives, trade-offs, or refinements!

Summary by CodeRabbit

  • New Features

    • Added --slack-full-width CLI flag to the monitor command for controlling Slack alert layout width.
  • Improvements

    • Changed table formatting to treat numeric values as text strings instead of parsing them as numbers.
    • Enhanced Slack alert message rendering with improved display of test details, descriptions, and sample results.
    • Added markdown table conversion utility for better data presentation.
  • Tests

    • Added test coverage for full-width Slack alert behavior and markdown table formatting.

@github-actions
Copy link
Contributor

👋 @michrzan
Thank you for raising your pull request.
Please make sure to add tests and document all user-facing changes.
You can do this by editing the docs files in this pull request.

@coderabbitai
Copy link

coderabbitai bot commented Feb 10, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 031c4bf and 5500f28.

📒 Files selected for processing (2)
  • elementary/config/config.py
  • elementary/utils/json_utils.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • elementary/utils/json_utils.py

📝 Walkthrough

Walkthrough

This PR introduces full-width Slack alert support with markdown table formatting for test result samples. It adds a new slack_full_width configuration option wired through the CLI and Config, updates table rendering across multiple formats to disable numeric parsing, creates a utility function for converting dict lists to markdown tables, and modifies Slack message rendering to place blocks in the main message body rather than attachments when full-width is enabled.

Changes

Cohort / File(s) Summary
Configuration & CLI
elementary/config/config.py, elementary/monitor/cli.py
Added slack_full_width optional parameter to Config constructor and new CLI flag --slack-full-width to the monitor command, propagating the option to Config and DataMonitoringAlerts initialization.
Table Formatting
elementary/messages/formats/block_kit.py, elementary/messages/formats/markdown.py, elementary/messages/formats/text.py
All three format modules now pass disable_numparse=True to tabulate calls to prevent automatic numeric parsing of table cells during rendering.
Table Utility Function
elementary/utils/json_utils.py
Added public function list_of_dicts_to_markdown_table() to convert lists of dictionaries to GitHub-flavored markdown tables with optional max_length truncation and special value formatting handling.
Slack Integration Logic
elementary/monitor/data_monitoring/alerts/integrations/integrations.py, elementary/monitor/data_monitoring/alerts/integrations/slack/message_builder.py, elementary/monitor/data_monitoring/alerts/integrations/slack/slack.py
Extended Slack integration selection logic, added full_width parameter to SlackAlertMessageBuilder, modified preview and details rendering to use main blocks instead of attachments when full-width is enabled, and updated Slack alert templates to render test result samples as markdown tables instead of JSON.
Tests
tests/unit/monitor/data_monitoring/alerts/integrations/slack/test_slack_alert_message_builder.py, tests/unit/utils/test_json_utils.py
Added three new tests for full-width Slack message behavior and comprehensive unit tests for the new list_of_dicts_to_markdown_table() function covering edge cases and formatting expectations.

Sequence Diagram

sequenceDiagram
    participant CLI as CLI Monitor Command
    participant Config as Config
    participant Integrations as Integrations
    participant SlackIntegration as SlackIntegration
    participant MessageBuilder as SlackAlertMessageBuilder
    participant SlackMessage as Slack Message

    CLI->>Config: Initialize with slack_full_width flag
    Config->>Config: Store slack_full_width attribute
    CLI->>Integrations: Create with config
    Integrations->>Integrations: Check slack_full_width condition
    Integrations->>SlackIntegration: Instantiate (selected via slack_full_width)
    SlackIntegration->>MessageBuilder: Initialize with config.slack_full_width
    MessageBuilder->>MessageBuilder: Store full_width flag
    MessageBuilder->>SlackMessage: Build message structure
    alt full_width enabled
        MessageBuilder->>SlackMessage: Place preview/details in main blocks
        MessageBuilder->>SlackMessage: Clear attachments
    else full_width disabled
        MessageBuilder->>SlackMessage: Use attachment path (legacy)
    end
    SlackMessage-->>CLI: Formatted Slack alert
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Tables bloom in Slack so wide,
No more JSON to hide,
Full-width alerts in perfect rows,
How the message beauty grows!
Test results dance as markdown streams,
Hopping toward data's dreams. 🌸

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 32.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main feature: adding a --slack-full-width CLI option that enables full-width Slack alert rendering with markdown test result tables.
Linked Issues check ✅ Passed The PR successfully implements the core requirement from #1079 by replacing JSON-formatted test_results_sample with markdown table rendering, improving readability for non-technical consumers.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the --slack-full-width feature and markdown table rendering for test results. Icon/utility refactoring and message block structure changes are necessary for this feature.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@michrzan michrzan temporarily deployed to elementary_test_env February 10, 2026 14:32 — with GitHub Actions Inactive
@michrzan michrzan marked this pull request as ready for review February 10, 2026 14:34
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@docs/oss/deployment-and-configuration/slack.mdx`:
- Around line 56-67: Change the lowercase "markdown" occurrences to the proper
noun "Markdown" in the Slack docs section that describes full-width alerts (the
paragraph referencing `--slack-full-width` and the sentence about test result
samples). Locate the two instances where "markdown table" and "markdown tables"
are used and update them to "Markdown table" and "Markdown tables" respectively
so the term is capitalized consistently.

In `@docs/oss/guides/alerts/send-slack-alerts.mdx`:
- Around line 27-28: Replace the lowercase word "markdown" with capitalized
"Markdown" in the sentence that mentions `--slack-full-width` so the doc reads
"show test results as Markdown tables"; update the phrase near the
`--slack-full-width` reference to use the corrected capitalization.

In `@elementary/monitor/data_monitoring/alerts/integrations/slack/slack.py`:
- Around line 225-234: The markdown table from list_of_dicts_to_markdown_table
can be truncated mid-row by get_limited_markdown_msg causing malformed markdown;
update the Slack message construction in slack.py (the code that calls
create_text_section_block with the code-fenced test_rows_sample) to first check
the full table length/character limit using the same logic as the test-query
branch, and if it exceeds the limit, either (a) render a safe summary by
converting only the first N rows (or columns) and append a clear "(truncated)"
note, or (b) replace the code block with a short text section that says the
table was truncated and provide row/column counts; ensure this uses
list_of_dicts_to_markdown_table for the sampled subset and then pass the safe
string to create_text_section_block/get_limited_markdown_msg so no markdown is
cut mid-structure.
🧹 Nitpick comments (4)
elementary/utils/json_utils.py (1)

101-112: Consider precision loss for very small decimal floats.

The fixed .10f format means values with magnitude smaller than ~1e-10 will be rounded to zero. For example, 0.00000000001 would render as "0.0". If test result data could contain very small non-zero decimals, this might silently hide meaningful values.

If this is acceptable for the display use case, no change needed — just flagging the edge case.

tests/unit/monitor/data_monitoring/alerts/integrations/slack/test_slack_alert_message_builder.py (1)

199-220: Consider using an exact assertion for block count.

Line 213: assert len(blocks) >= 5 — given the schema has exactly one title block, one preview block, and one detail block, the expected count is deterministically 5 (rich_text + title + divider + preview + detail). Using == 5 would make the test stricter and catch unexpected extra blocks.

Proposed fix
-    assert len(blocks) >= 5
+    assert len(blocks) == 5
elementary/monitor/data_monitoring/alerts/integrations/slack/message_builder.py (1)

38-46: The empty rich_text block hack relies on undocumented Slack behavior.

The empty rich_text block to force full-width rendering is a known workaround, but it's not part of the official Slack Block Kit API contract. Slack could change this behavior without notice. The inline comment is helpful — consider also adding a link to any community discussion or internal reference documenting this technique, so future maintainers understand the fragility.

elementary/monitor/data_monitoring/alerts/integrations/slack/slack.py (1)

199-205: Inconsistent description rendering between dbt and elementary test templates.

_get_dbt_test_template now uses a simplified single-block approach (description_text = alert.test_description or "_No description_"), while _get_elementary_test_template (lines 363–378) still uses the old if/else with separate create_text_section_block + create_context_block for descriptions. Consider aligning both templates for consistency — unless the difference is intentional due to rendering requirements.

@haritamar haritamar requested a deployment to elementary_test_env March 1, 2026 09:47 — with GitHub Actions Waiting
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
elementary/monitor/data_monitoring/alerts/integrations/slack/message_builder.py (1)

56-63: Full-width mode bypasses preview validation, allowing unbounded preview blocks.

Line 58-59: When full_width=True, preview blocks bypass _validate_preview_blocks(), so PreviewIsTooLongError is never raised. This was intentional design (blocks go directly to main message instead of attachments), but it removes the safety bound that prevents oversized payloads. Consider adding validation even for full-width mode to maintain consistency and prevent Slack message size issues.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@elementary/monitor/data_monitoring/alerts/integrations/slack/message_builder.py`
around lines 56 - 63, The full-width branch bypasses validation, so modify the
preview handling in the method containing full_width to always run
_validate_preview_blocks(preview_blocks) (or call a new helper that enforces the
same bounds) before passing blocks on; if validation raises
PreviewIsTooLongError, handle it the same way as the non-full-width branch
(e.g., trim/fallback to _add_blocks_as_attachments or log/raise consistently)
and then call _add_always_displayed_blocks(validated_preview_blocks) when
full_width is True, otherwise keep the existing
_add_blocks_as_attachments(validated_preview_blocks) flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@elementary/monitor/data_monitoring/alerts/integrations/slack/message_builder.py`:
- Around line 37-45: The empty rich_text block sent when self.full_width is True
is invalid; instead of calling self._add_always_displayed_blocks([{"type":
"rich_text", "elements": []}]) remove that empty block usage and implement a
valid alternative: either remove attachments early (set
self.slack_message["attachments"] = []) before building blocks or add a valid
non-empty rich_text block (with required nested content) if you must use
rich_text; update places that rely on the sentinel (self.full_width,
add_title_to_slack_alert, add_preview_to_slack_alert,
add_details_to_slack_alert) so they work with the new approach and do not append
an empty elements array to slack_message.

---

Nitpick comments:
In
`@elementary/monitor/data_monitoring/alerts/integrations/slack/message_builder.py`:
- Around line 56-63: The full-width branch bypasses validation, so modify the
preview handling in the method containing full_width to always run
_validate_preview_blocks(preview_blocks) (or call a new helper that enforces the
same bounds) before passing blocks on; if validation raises
PreviewIsTooLongError, handle it the same way as the non-full-width branch
(e.g., trim/fallback to _add_blocks_as_attachments or log/raise consistently)
and then call _add_always_displayed_blocks(validated_preview_blocks) when
full_width is True, otherwise keep the existing
_add_blocks_as_attachments(validated_preview_blocks) flow.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 68ddb44 and 61a99a1.

📒 Files selected for processing (2)
  • elementary/messages/formats/block_kit.py
  • elementary/monitor/data_monitoring/alerts/integrations/slack/message_builder.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • elementary/messages/formats/block_kit.py

- Replace invalid empty rich_text block with valid non-empty structure
  (Slack API rejects empty elements arrays)
- Add max_length param to list_of_dicts_to_markdown_table for graceful
  row-by-row truncation instead of cutting mid-row
- Capitalize "markdown" to "Markdown" in docs (proper noun)
- Run preview validation in full-width mode for consistent safety bounds
- Update tests for valid rich_text block and exact assertions

Made-with: Cursor
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@elementary/utils/json_utils.py`:
- Around line 141-143: The truncation logic can produce outputs longer than
max_length when max_length is smaller than the truncation marker length; update
the code around truncation_note/effective_max/processed_data so effective_max =
max(0, max_length - len(truncation_note)) and ensure any returned string is
trimmed to max_length (for example, if effective_max == 0 return
truncation_note[:max_length]); also ensure the loop that reduces rows (uses
processed_data and row_count) handles the zero-effective_max case and that the
final concatenation always enforces the max_length limit.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 61a99a1 and 031c4bf.

📒 Files selected for processing (6)
  • docs/oss/deployment-and-configuration/slack.mdx
  • docs/oss/guides/alerts/send-slack-alerts.mdx
  • elementary/monitor/data_monitoring/alerts/integrations/slack/message_builder.py
  • elementary/monitor/data_monitoring/alerts/integrations/slack/slack.py
  • elementary/utils/json_utils.py
  • tests/unit/monitor/data_monitoring/alerts/integrations/slack/test_slack_alert_message_builder.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • elementary/monitor/data_monitoring/alerts/integrations/slack/message_builder.py
  • docs/oss/deployment-and-configuration/slack.mdx

@haritamar haritamar requested a deployment to elementary_test_env March 1, 2026 12:10 — with GitHub Actions Waiting
Docs for --slack-full-width are handled in a separate PR targeting
the docs branch.

Made-with: Cursor
@haritamar haritamar requested a deployment to elementary_test_env March 1, 2026 12:11 — with GitHub Actions Waiting
Handle edge cases where max_length is <= 0 or smaller than the
truncation note itself.

Made-with: Cursor
@haritamar haritamar deployed to elementary_test_env March 1, 2026 12:14 — with GitHub Actions Active
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.

Formatting the test_results_sample as a table within the Slack alerts

2 participants