@@ -102,6 +102,12 @@ def parse(cls, block: Union[dict, "Block"]) -> Optional["Block"]:
102102 return TaskCardBlock (** block )
103103 elif type == PlanBlock .type :
104104 return PlanBlock (** block )
105+ elif type == CardBlock .type :
106+ return CardBlock (** block )
107+ elif type == AlertBlock .type :
108+ return AlertBlock (** block )
109+ elif type == CarouselBlock .type :
110+ return CarouselBlock (** block )
105111 else :
106112 cls .logger .warning (f"Unknown block detected and skipped ({ block } )" )
107113 return None
@@ -878,3 +884,152 @@ def __init__(
878884
879885 self .title = title
880886 self .tasks = tasks
887+
888+
889+ class CardBlock (Block ):
890+ type = "card"
891+ title_max_length = 150
892+ subtitle_max_length = 150
893+ body_max_length = 200
894+
895+ @property
896+ def attributes (self ) -> Set [str ]: # type: ignore[override]
897+ return super ().attributes .union (
898+ {
899+ "hero_image" ,
900+ "icon" ,
901+ "title" ,
902+ "subtitle" ,
903+ "body" ,
904+ "actions" ,
905+ }
906+ )
907+
908+ def __init__ (
909+ self ,
910+ * ,
911+ block_id : Optional [str ] = None ,
912+ hero_image : Optional [Union [dict , ImageElement ]] = None ,
913+ icon : Optional [Union [dict , ImageElement ]] = None ,
914+ title : Optional [Union [str , dict , TextObject ]] = None ,
915+ subtitle : Optional [Union [str , dict , TextObject ]] = None ,
916+ body : Optional [Union [str , dict , TextObject ]] = None ,
917+ actions : Optional [Sequence [Union [dict , BlockElement ]]] = None ,
918+ ** others : dict ,
919+ ):
920+ """A rich display block for presenting structured content such as recommendations, results, or work items.
921+ https://docs.slack.dev/reference/block-kit/blocks/card-block
922+
923+ Args:
924+ block_id: A string acting as a unique identifier for a block. If not specified, one will be generated.
925+ Maximum length for this field is 255 characters.
926+ hero_image: A top banner image for the card. An image element with type, image_url, and alt_text.
927+ icon: A small icon next to the title/subtitle. An image element with type, image_url, and alt_text.
928+ title: The title of the card. Supports mrkdwn text. Maximum length is 150 characters.
929+ subtitle: The subtitle of the card. Supports mrkdwn text. Maximum length is 150 characters.
930+ body: The body text of the card. Supports mrkdwn text. Maximum length is 200 characters.
931+ actions: An array of button elements displayed at the bottom of the card.
932+ """
933+ super ().__init__ (type = self .type , block_id = block_id )
934+ show_unknown_key_warning (self , others )
935+
936+ self .hero_image = BlockElement .parse (hero_image ) # type: ignore[arg-type]
937+ self .icon = BlockElement .parse (icon ) # type: ignore[arg-type]
938+ self .title = TextObject .parse (title , default_type = MarkdownTextObject .type ) # type: ignore[arg-type]
939+ self .subtitle = TextObject .parse (subtitle , default_type = MarkdownTextObject .type ) # type: ignore[arg-type]
940+ self .body = TextObject .parse (body , default_type = MarkdownTextObject .type ) # type: ignore[arg-type]
941+ self .actions = BlockElement .parse_all (actions ) if actions else None # type: ignore[arg-type]
942+
943+ @JsonValidator ("At least one of hero_image, title, actions, or body is required" )
944+ def _validate_content (self ):
945+ return self .hero_image is not None or self .title is not None or self .actions is not None or self .body is not None
946+
947+ @JsonValidator (f"title attribute cannot exceed { title_max_length } characters" )
948+ def _validate_title_length (self ):
949+ return self .title is None or self .title .text is None or len (self .title .text ) <= self .title_max_length
950+
951+ @JsonValidator (f"subtitle attribute cannot exceed { subtitle_max_length } characters" )
952+ def _validate_subtitle_length (self ):
953+ return self .subtitle is None or self .subtitle .text is None or len (self .subtitle .text ) <= self .subtitle_max_length
954+
955+ @JsonValidator (f"body attribute cannot exceed { body_max_length } characters" )
956+ def _validate_body_length (self ):
957+ return self .body is None or self .body .text is None or len (self .body .text ) <= self .body_max_length
958+
959+
960+ class AlertBlock (Block ):
961+ type = "alert"
962+ valid_levels = {"default" , "info" , "warning" , "error" , "success" }
963+
964+ @property
965+ def attributes (self ) -> Set [str ]: # type: ignore[override]
966+ return super ().attributes .union ({"text" , "level" })
967+
968+ def __init__ (
969+ self ,
970+ * ,
971+ text : Union [str , dict , TextObject ],
972+ level : Optional [str ] = None ,
973+ block_id : Optional [str ] = None ,
974+ ** others : dict ,
975+ ):
976+ """A prominent notice block for displaying warnings, status updates, or other important information.
977+ https://docs.slack.dev/reference/block-kit/blocks/alert-block
978+
979+ Args:
980+ text (required): The alert message content. Supports plain_text or mrkdwn.
981+ level: The severity level of the alert. One of "default", "info", "warning", "error", "success".
982+ Defaults to "default".
983+ block_id: A string acting as a unique identifier for a block. If not specified, one will be generated.
984+ Maximum length for this field is 255 characters.
985+ """
986+ super ().__init__ (type = self .type , block_id = block_id )
987+ show_unknown_key_warning (self , others )
988+
989+ self .text = TextObject .parse (text ) # type: ignore[arg-type]
990+ self .level = level
991+
992+ @JsonValidator ("text attribute must be specified" )
993+ def _validate_text (self ):
994+ return self .text is not None
995+
996+ @JsonValidator ("level must be a valid value (default, info, warning, error, success)" )
997+ def _validate_level (self ):
998+ return self .level is None or self .level in self .valid_levels
999+
1000+
1001+ class CarouselBlock (Block ):
1002+ type = "carousel"
1003+ elements_max_length = 10
1004+
1005+ @property
1006+ def attributes (self ) -> Set [str ]: # type: ignore[override]
1007+ return super ().attributes .union ({"elements" })
1008+
1009+ def __init__ (
1010+ self ,
1011+ * ,
1012+ elements : Sequence [Union [dict , "CardBlock" ]],
1013+ block_id : Optional [str ] = None ,
1014+ ** others : dict ,
1015+ ):
1016+ """A horizontally scrollable collection of card blocks.
1017+ https://docs.slack.dev/reference/block-kit/blocks/carousel-block
1018+
1019+ Args:
1020+ elements (required): An array of card block objects. Minimum 1, maximum 10 cards.
1021+ block_id: A string acting as a unique identifier for a block. If not specified, one will be generated.
1022+ Maximum length for this field is 255 characters.
1023+ """
1024+ super ().__init__ (type = self .type , block_id = block_id )
1025+ show_unknown_key_warning (self , others )
1026+
1027+ self .elements = Block .parse_all (elements )
1028+
1029+ @JsonValidator ("elements attribute must contain at least 1 card" )
1030+ def _validate_elements_present (self ):
1031+ return self .elements is not None and len (self .elements ) >= 1
1032+
1033+ @JsonValidator (f"elements attribute cannot exceed { elements_max_length } cards" )
1034+ def _validate_elements_length (self ):
1035+ return self .elements is None or len (self .elements ) <= self .elements_max_length
0 commit comments