Skip to content

[PM-33861] Display organization notification banner on vault list#2798

Open
matt-livefront wants to merge 4 commits into
mainfrom
matt/PM-33861-policy-banner
Open

[PM-33861] Display organization notification banner on vault list#2798
matt-livefront wants to merge 4 commits into
mainfrom
matt/PM-33861-policy-banner

Conversation

@matt-livefront

@matt-livefront matt-livefront commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

🎟️ Tracking

PM-33861

📔 Objective

Add support for the organizationUserNotification organization policy and surface it as a dismissible banner (action card) on the vault list.

Changes:

  • Add the pm-31948-org-user-notification-banner feature flag.
  • Add the organizationUserNotification PolicyType and its associated PolicyOptionType keys (header, description, buttonText, showAfterEveryLogin).
  • Add OrganizationUserNotificationBannerData and PolicyService.getOrganizationUserNotificationBannerData(), which (behind the feature flag) returns the banner data for the earliest-revision policy applying to the user, or nil when no policy applies or the policy has no description.
  • Render the banner as an ActionCard on the vault list (empty and populated states). When the policy supplies both a header and button text, an acknowledgement button is shown; otherwise a standard X dismiss button is shown. Dismissing clears the banner.
  • Extract the vault-list action cards into a dedicated extension and share apolicyWithEarliestRevisionDate helper in PolicyService.

Currently this just dismisses the banner in memory. There's additional logic for persisting the dismissal of the banner coming in a future PR.

📸 Screenshots

Description Only Header + Description Header, Description, Custom Button
Screenshot 2026-06-12 at 11 39 53 AM Screenshot 2026-06-12 at 11 33 24 AM Screenshot 2026-06-12 at 11 38 56 AM

@matt-livefront matt-livefront requested a review from a team as a code owner June 16, 2026 17:40
@matt-livefront matt-livefront added ai-review Request a Claude code review t:feature labels Jun 16, 2026
@github-actions github-actions Bot added app:password-manager Bitwarden Password Manager app context and removed t:feature labels Jun 16, 2026
@github-actions

github-actions Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

🤖 Bitwarden Claude Code Review

Overall Assessment: APPROVE

Reviewed the addition of the organizationUserNotification policy and its dismissible vault-list banner. The feature is cleanly gated behind the pm-31948-org-user-notification-banner flag, the action-card extraction preserves existing behavior, and the new PolicyService logic, processor wiring, and view rendering are well covered by unit and ViewInspector tests. The shared policyWithEarliestRevisionDate helper is a faithful refactor of the prior inline min logic.

Code Review Details
  • ❓ : SDK nil mapping silently disables the banner when policiesInAcceptedState is enabled; the new banner tests only cover the legacy native-filter path
    • BitwardenShared/Core/Vault/Services/PolicyService+SdkMapping.swift:92

@codecov

codecov Bot commented Jun 16, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 70.53571% with 33 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.85%. Comparing base (68caf09) to head (1190195).

Files with missing lines Patch % Lines
...hared/UI/Vault/Vault/VaultList/VaultListView.swift 58.97% 32 Missing ⚠️
...Shared/Core/Platform/Models/Enum/FeatureFlag.swift 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2798      +/-   ##
==========================================
+ Coverage   80.82%   80.85%   +0.02%     
==========================================
  Files        1018     1018              
  Lines       64941    64996      +55     
==========================================
+ Hits        52490    52551      +61     
+ Misses      12451    12445       -6     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment on lines +317 to +325

/// Returns the policy with the earliest revision date from the given list, or `nil` if the list is empty.
///
/// - Parameter policies: The list of policies to search.
/// - Returns: The policy with the earliest revision date.
///
private func policyWithEarliestRevisionDate(from policies: [Policy]) -> Policy? {
policies.min { ($0.revisionDate ?? .distantFuture) < ($1.revisionDate ?? .distantFuture) }
}

@fedemkr fedemkr Jun 17, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ I know this comes from the organization logic, but I'm a bit hesitant as this is getting the policy that has been updated least recently, i.e. the oldest one. Maybe it's correct as is, but I would think the most recently updated policy should prevail instead as it would have the latest changes.
Would this be to display the cards ordered from earliest to latest? Would the shown card policy be removed in a future PR?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In practice, there can only be a single notification banner. This policy requires the "Single organization" policy, so you can't be a member of multiple organizations and you can only specify a single banner policy. Also, once the dismissal logic is implemented, which is based on on revision date, if there were multiple, dismissing an older one would then cause the newer one to be shown.

/// Dismisses the organization user notification banner.
///
private func dismissOrganizationBanner() async {
// TODO: PM-33861 Persist banner dismissal data

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏️ This is referencing the same ticket as this PR. Will this be added as part of this PR?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll have a follow-up PR for this work, as there was already a lot here. The dismissal logic was easy to break off from this work.

@matt-livefront matt-livefront requested a review from fedemkr June 18, 2026 22:04
case .sendOptions: self = .sendOptions
case .twoFactorAuthentication: self = .twoFactorAuthentication
// TODO: PM-39144 Add SDK mapping for `organizationUserNotification` PolicyType
case .organizationUserNotification: return nil

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QUESTION: This nil mapping silently disables the new banner when the policiesInAcceptedState flag is enabled.

Details

getOrganizationUserNotificationBannerData() calls policiesApplyingToUser(.organizationUserNotification). When policiesInAcceptedState is enabled, that routes through sdkFilterPolicies, which returns [] early because BitwardenSdk.PolicyType(.organizationUserNotification) is nil here. The result is that the banner never appears for any user once policiesInAcceptedState rolls out, even though organizationUserNotificationBanner is on.

The getOrganizationUserNotificationBannerData tests only exercise the legacy native-filter path (the policiesInAcceptedState flag defaults to false in the mock), so this interaction isn't covered.

Is the intent that the banner only ships after PM-39144 adds the SDK mapping, or should this be handled before enabling the banner flag? A note tying PM-39144 to the banner rollout (or test coverage for the SDK path) would make the dependency explicit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-review Request a Claude code review app:password-manager Bitwarden Password Manager app context

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants