Skip to content

Commit 5ec85bb

Browse files
haritamarmichrzan
authored andcommitted
fix: address PR review comments for --slack-full-width
- 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
1 parent a611b9f commit 5ec85bb

6 files changed

Lines changed: 70 additions & 16 deletions

File tree

docs/oss/deployment-and-configuration/slack.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,12 @@ The alert format is:
5656

5757
## Full-width alerts
5858

59-
By default, Slack alerts use a narrower layout with some content in attachments. To use the full message width and show test results as a markdown table in the main message body, pass the flag when running the monitor:
59+
By default, Slack alerts use a narrower layout with some content in attachments. To use the full message width and show test results as a Markdown table in the main message body, pass the flag when running the monitor:
6060

6161
```shell
6262
edr monitor --slack-token <your_slack_token> --slack-channel-name <channel> --slack-full-width
6363
```
6464

65-
With `--slack-full-width`, alerts are sent using Slack Block Kit in the main message body instead of attachments, so the full channel width is used and test result samples appear as formatted markdown tables.
65+
With `--slack-full-width`, alerts are sent using Slack Block Kit in the main message body instead of attachments, so the full channel width is used and test result samples appear as formatted Markdown tables.
6666

6767
---

docs/oss/guides/alerts/send-slack-alerts.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Make sure to run the following command after your dbt runs and tests:
2424
edr monitor --slack-token <your_slack_token> --slack-channel-name <slack_channel_to_post_at> --group-by [table | alert]
2525
```
2626

27-
Add `--slack-full-width` to use the full message width and show test results as markdown tables. See [Slack setup - Full-width alerts](/oss/deployment-and-configuration/slack#full-width-alerts).
27+
Add `--slack-full-width` to use the full message width and show test results as Markdown tables. See [Slack setup - Full-width alerts](/oss/deployment-and-configuration/slack#full-width-alerts).
2828

2929
Or just `edr monitor` if you used `config.yml`. Please note that when you specify the --slack-channel-name, it's the
3030
default channel name to which all the alerts will be sent that are not attributed to any custom channel. Therefore,

elementary/monitor/data_monitoring/alerts/integrations/slack/message_builder.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,22 @@ def get_slack_message(
3535
alert_schema: SlackAlertMessageSchema,
3636
) -> SlackMessageSchema:
3737
if self.full_width:
38-
# Empty rich_text block forces Slack to use full message width for following
39-
# blocks instead of the narrower attachment-style layout.
40-
self._add_always_displayed_blocks([{"type": "rich_text", "elements": []}])
38+
# A rich_text block at the start forces Slack to use full message width
39+
# for following blocks instead of the narrower attachment-style layout.
40+
# The elements array must be non-empty per Slack Block Kit API.
41+
self._add_always_displayed_blocks(
42+
[
43+
{
44+
"type": "rich_text",
45+
"elements": [
46+
{
47+
"type": "rich_text_section",
48+
"elements": [{"type": "text", "text": " "}],
49+
}
50+
],
51+
}
52+
]
53+
)
4154
self.add_title_to_slack_alert(alert_schema.title)
4255
self.add_preview_to_slack_alert(alert_schema.preview)
4356
self.add_details_to_slack_alert(alert_schema.details)
@@ -55,10 +68,10 @@ def add_preview_to_slack_alert(
5568
):
5669
if not preview_blocks:
5770
return
71+
validated_preview_blocks = self._validate_preview_blocks(preview_blocks)
5872
if self.full_width:
59-
self._add_always_displayed_blocks(preview_blocks)
73+
self._add_always_displayed_blocks(validated_preview_blocks)
6074
else:
61-
validated_preview_blocks = self._validate_preview_blocks(preview_blocks)
6275
self._add_blocks_as_attachments(validated_preview_blocks)
6376

6477
def add_details_to_slack_alert(

elementary/monitor/data_monitoring/alerts/integrations/slack/slack.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,9 @@ def _get_dbt_test_template(
222222
TEST_RESULTS_SAMPLE_FIELD in (alert.alert_fields or DEFAULT_ALERT_FIELDS)
223223
and alert.test_rows_sample
224224
):
225+
table_max_length = SectionBlock.text_max_length - 6
225226
test_rows_sample_table = list_of_dicts_to_markdown_table(
226-
alert.test_rows_sample
227+
alert.test_rows_sample, max_length=table_max_length
227228
)
228229
result.extend(
229230
[

elementary/utils/json_utils.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,17 @@ def _format_value(value: Any) -> str:
112112
return str(value)
113113

114114

115-
def list_of_dicts_to_markdown_table(data: List[Dict[str, Any]]) -> str:
115+
def list_of_dicts_to_markdown_table(
116+
data: List[Dict[str, Any]], max_length: Optional[int] = None
117+
) -> str:
116118
"""
117119
Convert a list of dictionaries with consistent keys to a markdown table string.
118120
119121
Args:
120122
data: List of dictionaries
123+
max_length: Optional maximum character length for the output. If the full
124+
table exceeds this limit, rows are removed from the end and a
125+
"(truncated)" note is appended to avoid cutting mid-row.
121126
122127
Returns:
123128
A markdown-formatted table string using GitHub table format
@@ -126,6 +131,31 @@ def list_of_dicts_to_markdown_table(data: List[Dict[str, Any]]) -> str:
126131
return ""
127132

128133
processed_data = [{k: _format_value(v) for k, v in row.items()} for row in data]
129-
return tabulate(
134+
full_table = tabulate(
130135
processed_data, headers="keys", tablefmt="github", disable_numparse=True
131136
)
137+
138+
if max_length is None or len(full_table) <= max_length:
139+
return full_table
140+
141+
truncation_note = "\n(truncated)"
142+
effective_max = max_length - len(truncation_note)
143+
for row_count in range(len(processed_data) - 1, 0, -1):
144+
table = tabulate(
145+
processed_data[:row_count],
146+
headers="keys",
147+
tablefmt="github",
148+
disable_numparse=True,
149+
)
150+
if len(table) <= effective_max:
151+
return table + truncation_note
152+
153+
single_row_table = tabulate(
154+
processed_data[:1],
155+
headers="keys",
156+
tablefmt="github",
157+
disable_numparse=True,
158+
)
159+
if effective_max <= 0 or len(single_row_table) <= effective_max:
160+
return single_row_table + truncation_note
161+
return single_row_table[:effective_max].rstrip() + truncation_note

tests/unit/monitor/data_monitoring/alerts/integrations/slack/test_slack_alert_message_builder.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -177,11 +177,11 @@ def test_add_details_to_slack_alert():
177177

178178

179179
def test_full_width_preview_goes_to_blocks_not_attachments():
180-
"""With full_width=True, preview blocks are added to main blocks."""
180+
"""With full_width=True, preview blocks are validated and added to main blocks."""
181181
message_builder = SlackAlertMessageBuilder(full_width=True)
182182
block = message_builder.create_header_block("Preview header")
183183
message_builder.add_preview_to_slack_alert([block])
184-
assert len(message_builder.slack_message["blocks"]) == 1
184+
assert len(message_builder.slack_message["blocks"]) == 5
185185
assert message_builder.slack_message["blocks"][0] == block
186186
assert message_builder.slack_message["attachments"][0]["blocks"] == []
187187

@@ -210,11 +210,21 @@ def test_full_width_get_slack_message_structure():
210210
result = message_builder.get_slack_message(alert_schema=schema)
211211

212212
blocks = result.blocks
213-
assert len(blocks) >= 5
214-
assert blocks[0] == {"type": "rich_text", "elements": []}
213+
valid_rich_text_block = {
214+
"type": "rich_text",
215+
"elements": [
216+
{
217+
"type": "rich_text_section",
218+
"elements": [{"type": "text", "text": " "}],
219+
}
220+
],
221+
}
222+
assert blocks[0] == valid_rich_text_block
215223
assert blocks[1] == title
216224
assert blocks[2]["type"] == "divider"
217225
assert blocks[3] == preview_block
218-
assert blocks[4] == detail_block
226+
# Blocks 4-7 are padding from preview validation
227+
assert blocks[8] == detail_block
228+
assert len(blocks) == 9
219229

220230
assert result.attachments == []

0 commit comments

Comments
 (0)