feat: complete card message format - #1198
Conversation
📝 WalkthroughWalkthroughThe card converter library now extracts and renders header metadata (subtitle and tags), expands attachment handling to accept decoded JSON objects, enhances element display formatting across multiple converters, introduces attachment-based fallback lookups for person and image rendering, and systematically updates output formats from ChangesCard Converter Element and Metadata Enhancements
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
shortcuts/im/convert_lib/card.go (1)
344-347: ⚡ Quick winUse the element tag, not
id, to decidetype:person.
type:personis currently emitted only when the elementidhappens to contain"person". A normalselect_personlikeid: "assignee"will render without the person annotation in detailed mode.♻️ Suggested fix
-case "select_static", "select_person": - return c.convertSelect(prop, id, false) -case "multi_select_static", "multi_select_person": - return c.convertSelect(prop, id, true) +case "select_static": + return c.convertSelect(prop, id, false, false) +case "select_person": + return c.convertSelect(prop, id, false, true) +case "multi_select_static": + return c.convertSelect(prop, id, true, false) +case "multi_select_person": + return c.convertSelect(prop, id, true, true)-func (c *cardConverter) convertSelect(prop cardObj, id string, isMulti bool) string { +func (c *cardConverter) convertSelect(prop cardObj, id string, isMulti, isPerson bool) string { ... - if c.mode == cardModeDetailed && strings.Contains(id, "person") { + if c.mode == cardModeDetailed && isPerson { attrs = append(attrs, "type:person") }Also applies to: 998-1076
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@shortcuts/im/convert_lib/card.go` around lines 344 - 347, The code is determining type:person based on the element id instead of the element tag; update the select conversion to use the element tag to decide person vs static. In function convertSelect (and all call sites such as the case branches for "select_static"/"select_person" and "multi_select_static"/"multi_select_person") change the boolean/person-detection logic to inspect prop.Tag (or the element tag field on the passed property) for the substring "person" (or exact match) rather than checking id, and propagate that boolean into convertSelect so it emits type:person correctly; apply the same change to the other similar blocks referenced in the review (around the 998-1076 region).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@shortcuts/im/convert_lib/card.go`:
- Around line 889-897: The early return inside the disabled branch causes
disabled buttons to skip URL/confirm rendering; modify the disabled handling so
it marks the label (using buttonText and prop["disabled"]/prop["disabledTips"]
and c.extractTextContent) but does not return early — instead set the result
prefix (e.g., "[%s ✗]") and allow the function to continue to the existing
URL/confirm append logic (the code handling URL/confirm rendering later in the
function) so disabled buttons retain URL and confirm metadata.
- Around line 1457-1487: The function goMapArrayTexts incorrectly stops values
at the first space because it uses strings.IndexAny(after, " ]"); change the
parsing to detect the closing bracket instead (e.g. use strings.IndexByte(after,
']') or similar) so multi-word values like "Premium VIP" are captured intact,
then trim surrounding whitespace/brackets from val before appending; update the
logic that sets end/val/rest (refer to variables after, end, val and the key
constant) to use the ']' delimiter rather than breaking on space.
---
Nitpick comments:
In `@shortcuts/im/convert_lib/card.go`:
- Around line 344-347: The code is determining type:person based on the element
id instead of the element tag; update the select conversion to use the element
tag to decide person vs static. In function convertSelect (and all call sites
such as the case branches for "select_static"/"select_person" and
"multi_select_static"/"multi_select_person") change the boolean/person-detection
logic to inspect prop.Tag (or the element tag field on the passed property) for
the substring "person" (or exact match) rather than checking id, and propagate
that boolean into convertSelect so it emits type:person correctly; apply the
same change to the other similar blocks referenced in the review (around the
998-1076 region).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 76071ed3-36ba-4638-9dff-d46c3b10d65c
📒 Files selected for processing (2)
shortcuts/im/convert_lib/card.goshortcuts/im/convert_lib/card_test.go
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1198 +/- ##
==========================================
+ Coverage 69.20% 69.76% +0.56%
==========================================
Files 634 639 +5
Lines 59517 59940 +423
==========================================
+ Hits 41188 41820 +632
+ Misses 15014 14839 -175
+ Partials 3315 3281 -34 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
🚀 PR Preview Install Guide🧰 CLI updatenpm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@4df120eba1e7c17f159c1c600aa2882e681bcd20🧩 Skill updatenpx skills add 91-enjoy/cli#feat/complete_card_message_format -y -g |
afeaae0 to
fef4d7c
Compare
Change-Id: I422474ab6b7505e48ab5697793900df035be6e29
fef4d7c to
4df120e
Compare
The card message converter (shortcuts/im/convert_lib/card.go) previously rendered a subset of card fields and had several mode-gated behaviors that caused information to be silently dropped in concise mode. This PR audits every element handler and brings the output up to full fidelity: missing header fields are rendered, collapsible panels always expand, rich element metadata (images, audio, video, overflow URLs, person names) is no longer hidden behind cardModeDetailed, and several format bugs are fixed. Change-Id: I422474ab6b7505e48ab5697793900df035be6e29
Change-Id: I422474ab6b7505e48ab5697793900df035be6e29
Summary
The card message converter (
shortcuts/im/convert_lib/card.go) previouslyrendered a subset of card fields and had several mode-gated behaviors that
caused information to be silently dropped in concise mode. This PR audits
every element handler and brings the output up to full fidelity:
missing header fields are rendered, collapsible panels always expand, rich
element metadata (images, audio, video, overflow URLs, person names) is no
longer hidden behind
cardModeDetailed, and several format bugs are fixed.Changes
Header
json_attachmentobject support —json_attachmentat the top level canbe either a JSON string (existing path) or a plain object; both are now
handled, unblocking person-name resolution in this attachment path.
extractHeaderSubtitleextractsheader.property.subtitle(or
header.subtitle) and emits it as asubtitle="…"attribute on the<card>tag.extractHeaderTagsextractstextTagListfromheader.propertyand appends the rendered tags on the line after<card>.Element fixes
divnotation detection — was reading stale top-leveltext_size; nowreads
textStyle.sizeviaextractProperty, matching current API schema.local_datetimefloat milliseconds —millisecondsfield can be a JSONnumber (float64) or string; added type switch so numeric timestamps are no
longer silently dropped.
shouldExpandgate that skipped content in concise mode; content is always rendered with
▼/▶indicator controlled by theexpandedflag alone.disabledTipsrendered in all modes (was concise-only).confirmdialog rendered as(confirm:"title: text")annotation.open_urlactions; otherwise append(value)for traceability.(multi)annotation was gated behind detailedmode; now always emitted.
(type:person)remains detailed-only.to
lookupOptionUserName(resolving fromoption_usersattachment) beforeusing raw value.
(value)and(img_key:…)/(img_token:…)resolved from attachment.Metadata now shown in all modes (removed
cardModeDetailedgates)convertImage— image key/token always appended.convertImgCombination— image keys always appended.convertAudio/convertVideo— file key always appended.getImageToken→getImageKeyAndTokenreturnsboth
origin_keyandtoken;origin_keytakes priority (shown asimg_key:).Person rendering
@prefix fromconvertPerson,convertPersonV1,convertPersonList,convertAvatar— the prefix implied an @-mention butthese are data field values.
convertPersonListnow useslookupPersonNameto resolve display names fromattachment, with
name(open_id:…)format in detailed mode.convertAvatarnow resolves and displays the person name when available.lookupOptionUserNamehelper reads fromattachment.option_users.Chart
(Bar chart)suffix rather thandirect concatenation, preventing
"SalesBar chart"style output.dataspec support:datacan be an array of series objects[{"id":"…","values":[…]}]in addition to the legacy{"values":[…]}map.Table
FormatFloat(v, 'f', 2, 64)to'f', -1, 64to avoid spurious
.00suffix on whole numbers.goMapArrayTextshelper: parses Go-format slice-of-maps strings such as[map[text:VIP] map[text:Premium]](produced by Lark API for array-typecells) into comma-joined values
VIP, Premium.Test Plan
make unit-testpassed (go test -race ./shortcuts/im/...)card_test.go:cells) into comma-joined values
VIP, Premium.Test Plan
make unit-testpassed (go test -race ./shortcuts/im/...)card_test.go:json_attachmentas object, person names resolved (C008)extractHeaderSubtitlewithproperty.subtitle(C002)extractHeaderTagswithtextTagList(C003)convertDivnotation viatextStyle.size(updated existing case)convertCollapsiblePanelconcise+collapsed still renders content (C001)convertButtondisabled +disabledTipsin all modes (C007)convertSelectperson with no option text resolved fromoption_usersconvertSelectImgwith value +imageID→img_keyconvertImageprefersorigin_keyovertokenconvertImgCombinationwithorigin_keyconvertCharttitle format(Bar chart)extractTableCellValueGo-format array string →VIP, PremiumconvertTablefloat cell without trailing zerosconvertPerson/convertPersonV1/convertPersonList/convertAvatarwithout
@prefix, with name lookuppersonelement updatedRelated Issues
N/A
Label: feature
Summary by CodeRabbit
Bug Fixes
Improvements