feat(notifications): add label to action types for bulletin button#458
feat(notifications): add label to action types for bulletin button#458
Conversation
|
@blink-claw-bot review |
blink-claw-bot
left a comment
There was a problem hiding this comment.
Review: feat(bulletin): bulletin dismissible and button action
Nice, clean feature addition. The bulletinButton field flows correctly through all layers (GraphQL → TypeScript → protobuf → gRPC → Rust → back to GraphQL). Good test coverage on both the Rust unit tests and BATS integration tests.
✅ What looks good
- Backward compatibility handled well —
#[serde(default)]on the new field, and an explicit deserialization test for old payloads withoutbulletin_button - Protobuf schema uses
optionalcorrectly (field 8, no conflicts) - Rust tests are thorough: serde roundtrip, backward compat, coexistence with action, localization
- BATS tests cover all three scenarios: external URL action, no button, and deep link action
- GraphQL schema additions are consistent with existing patterns (
BulletinButtontype, optional field onStatefulNotification)
Issues
-
bulletinButtonvalidation is missing on the input side — TheBulletinButtonInput.labelisString!(non-null) in GraphQL, which prevents empty-via-null. But an empty string""would pass through. Consider whether an empty label is valid. If not, add validation similar to howopenDeepLink/openExternalUrlinputs are validated inmarketing-notification-trigger.ts. (minor) -
No mutual exclusion between
bulletinButtonand the absence of an action — A button with a label but noaction(noopenDeepLinkoropenExternalUrl) would render a button that does nothing when tapped. Should the API enforce thatbulletinButtonrequires anaction? At minimum, document the expected behavior. (minor — depends on client-side handling) -
PR title mentions "dismissible" but the diff doesn't show dismissible changes — The title says "bulletin dismissible and button action" but I only see button/action additions. Is the dismissible part handled elsewhere, or is it implicit in the existing acknowledge flow? Clarifying the PR description would help. (clarification)
Nits
-
nit:
notifications_pb.jshas a lot of whitespace reformatting (indentation changes intoObjectmethods throughout the file). This is likely from regenerating the protobuf JS code, but it inflates the diff significantly. If there's a way to regenerate only the changed parts, it'd make reviews easier in the future. -
nit: In
notifications_pb.js, theiconfield changed fromjspb.Message.getFieldWithDefault(msg, 7, 0)to(f = jspb.Message.getField(msg, 7)) == null ? undefined : f. Same forDeepLink.screen,DeepLink.action,Action.externalUrl, andNotificationSettings.locale. These semantic changes (default0/""→undefinedwhen unset) are correct for optional proto fields but are unrelated to the bulletin button feature. Worth noting in the PR description that the codegen was re-run.
Verdict
Looks good overall. The core feature is well-implemented with proper test coverage. The issues raised are minor — the empty label and button-without-action cases are worth considering but not blocking.
🤖 Review by Claude Opus 4.6 via Blink-Claw-Bot
@esaugomez31 Have a look. |
| pub body: String, | ||
| pub deep_link: Option<String>, | ||
| pub action: Option<NotificationAction>, | ||
| pub bulletin_button: Option<BulletinButton>, |
There was a problem hiding this comment.
according to answers this should be something more generic. action_label or label if it is part of NotificatioAction structure? @grimen
There was a problem hiding this comment.
@designsats Let's discuss this new action/button design more in detail tomorrow UX/UI call - seems like the introduction of it raises more questions than answers for me currently.
There was a problem hiding this comment.
Pre-existing bugs in bats tests (not introduced by this PR, but worth fixing)
These exist on main already — since this PR extends these test files, it's a good opportunity to fix them and harden the test suite. Other than this, I think the added changes look good.
Bug 1: Undefined variable $n_bulletins (lines 103, 179)
Two tests assign to n_notifications but assert against $n_bulletins which is never defined:
Line 102-103 (test: "list unacknowledged stateful notifications with bulletin enabled"):
n_notifications=$(graphql_output '...unacknowledgedStatefulNotificationsWithBulletinEnabled.nodes | length')
[[ $n_bulletins -eq 0 ]] || exit 1 # ← $n_bulletins is never set, always evaluates as 0Line 178-179 (test: "list stateful notifications without bulletin enabled"):
n_notifications=$(graphql_output '...listStatefulNotificationsWithoutBulletinEnabled.nodes | length')
[[ $n_bulletins -eq 0 ]] || exit 1 # ← same bugIn bash, an unset variable in [[ $n_bulletins -eq 0 ]] evaluates as 0, so the assertion always passes regardless of the actual notification count. The initial empty-state precondition check is completely defeated.
Fix: Replace $n_bulletins with $n_notifications on both lines.
Bug 2: Wrong GraphQL response path (line 178)
Line 178 uses jq path .data.me.listStatefulNotificationsWithoutBulletinEnabled.nodes but the GQL query field (in bats/gql/list-stateful-notifications-without-bulletin-enabled.gql:4) is statefulNotificationsWithoutBulletinEnabled — no list prefix. This means n_notifications is always null.
Note that line 207 in the same test correctly uses .data.me.statefulNotificationsWithoutBulletinEnabled.nodes, so only the initial zero-count check is broken.
Fix: Remove the list prefix:
n_notifications=$(graphql_output '.data.me.statefulNotificationsWithoutBulletinEnabled.nodes | length')1dde28c to
9c622fd
Compare
|
Hi @grimen @dolcalmi, this seems to be a CI issue. In this PR we already addressed a previous CI problem 9c622fd (pinning DOCKER_API_VERSION=1.44), which was resolved following @openoms recommendation based on blinkbitcoin/bria#27. However, this is a different CI error. The integration tests are currently failing, but this doesn't seem to be related to this PR since recent PRs also have failing integration tests:
The tests themselves pass, the issue is on the CI side. This PR doesn't include integration tests, only Rust unit tests and e2e bats tests, and both pass locally: Rust unit tests (cargo test):
E2E bats tests (nix develop -c bats bats/core/notifications/notifications.bats):
|
working on a fix here:
|
9c622fd to
3a278b5
Compare
|
Hi @dolcalmi @grimen, I applied the recommendation and it looks like this: Before
type BulletinButton {
label: String!
}
type StatefulNotification {
action: NotificationAction
bulletinButton: BulletinButton
}{
"openDeepLink": { "screen": "PEOPLE" },
"bulletinButton": { "label": "Learn more" }
}{
"openExternalUrl": { "url": "https://example.com" },
"bulletinButton": { "label": "Learn more" }
}pub struct BulletinButton {
pub label: String,
}After
type OpenDeepLinkAction {
deepLink: String!
label: String
}
type OpenExternalLinkAction {
url: String!
label: String
}{
"openDeepLink": { "screen": "PEOPLE", "label": "Learn more" }
}{
"openExternalUrl": { "url": "https://example.com", "label": "Learn more" }
}pub struct DeepLink {
pub screen: Option<DeepLinkScreen>,
pub action: Option<DeepLinkAction>,
pub label: Option<String>,
}
pub struct ExternalUrl {
url: String,
pub label: Option<String>,
} |
3e45a62 to
451a48b
Compare
core/notifications/src/notification_event/marketing_notification_triggered.rs
Outdated
Show resolved
Hide resolved
…ity" This reverts commit 2a9a3e8.
…es in proto and Rust Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…es in API Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
451a48b to
8d8f10b
Compare


Summary
labelfield toOpenDeepLinkActionandOpenExternalLinkActionacross all layers (proto, Rust, GraphQL, TypeScript)labellives on theActionmessage (outsideoneof) so it applies to both action typesExternalUrl(supports old string format and new struct format)Tests
Rust unit tests
ExternalUrlas string (old format)Somewhen set on deep linkSomewhen set on external URLNonewhen not sete2e BATS
action.labelis returnedaction.labelis returnedaction.labelis null