diff --git a/blockkit/core.py b/blockkit/core.py index 99b2dda..09d98f5 100644 --- a/blockkit/core.py +++ b/blockkit/core.py @@ -4,6 +4,7 @@ from abc import ABC, abstractmethod from datetime import date, datetime, time from typing import Any, Final, Literal, Self, TypeAlias, get_args +from urllib import parse from zoneinfo import ZoneInfo from blockkit.utils import is_md @@ -731,6 +732,28 @@ def external_id(self, external_id: str | None) -> Self: ) +class BuilderUrlMixin: + def builder_url(self) -> str: + """ + Returns a URL to preview this message in Slack's Block Kit Builder. + """ + + surface = self.build() + filter_fields = { + Message: ("blocks",), + Modal: ("type", "title", "submit", "close", "blocks"), + Home: ("type", "blocks"), + }.get(type(self), None) + + if filter_fields: + surface = {k: v for k, v in surface.items() if k in filter_fields} + + encoded_json = parse.quote( + json.dumps(surface, ensure_ascii=False, separators=(",", ":")), safe="" + ) + return f"https://app.slack.com/block-kit-builder#{encoded_json}" + + """ Composition objects """ @@ -3092,7 +3115,7 @@ def author_name(self, author_name: str | None) -> Self: ) -class Message(Component): +class Message(Component, BuilderUrlMixin): """ Message surface @@ -3142,7 +3165,12 @@ def mrkdwn(self, mrkdwn: bool | None = True) -> Self: class Modal( - Component, BlocksMixin, PrivateMetadataMixin, CallbackIdMixin, ExternalIdMixin + Component, + BlocksMixin, + PrivateMetadataMixin, + CallbackIdMixin, + ExternalIdMixin, + BuilderUrlMixin, ): """ Modal surface @@ -3220,7 +3248,12 @@ def submit_disabled(self, submit_disabled: bool | None = True) -> Self: class Home( - Component, BlocksMixin, PrivateMetadataMixin, CallbackIdMixin, ExternalIdMixin + Component, + BlocksMixin, + PrivateMetadataMixin, + CallbackIdMixin, + ExternalIdMixin, + BuilderUrlMixin, ): """ App Home surface diff --git a/docs/quickstart.md b/docs/quickstart.md index 90db5d1..0f9e95e 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -28,6 +28,11 @@ message = ( That's it. Real Slack BlockKit JSON. Ready to send. +Wondering what it looks like now in Slack? You can check your exact message in the Slack block kit builder before sending it; +```python +message.get_block_kit_explorer_url() +``` + ## Send it ```python diff --git a/tests/test_core.py b/tests/test_core.py index 6277bb1..00bbe95 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -3544,3 +3544,4 @@ def test_builds(self): .external_id("alice_intro") .build() ) + assert got == want