Skip to content

[BEEEP] Improve speed performance of Admin Console Collections page#20243

Open
JaredScar wants to merge 10 commits intomainfrom
beeep/improve-collections-page-speeds
Open

[BEEEP] Improve speed performance of Admin Console Collections page#20243
JaredScar wants to merge 10 commits intomainfrom
beeep/improve-collections-page-speeds

Conversation

@JaredScar
Copy link
Copy Markdown
Contributor

@JaredScar JaredScar commented Apr 17, 2026

🎟️ Tracking

N/A

📔 Objective

Optimize performance of vault component and services by running heavy operations outside Angular's zone. Implement chunked decryption for ciphers and collections to prevent UI blocking. Introduce a long-lived Web Worker for managing the Lunr search index, improving search responsiveness and reducing main thread load. Update virtual scrolling cache size in vault items component for better rendering efficiency.

📸 Screenshots

https://vimeo.com/1184239975?share=copy&fl=sv&fe=ci

… operations outside Angular's zone. Implement chunked decryption for ciphers and collections to prevent UI blocking. Introduce a long-lived Web Worker for managing the Lunr search index, improving search responsiveness and reducing main thread load. Update virtual scrolling cache size in vault items component for better rendering efficiency.
@JaredScar JaredScar requested review from BTreston and eliykat April 17, 2026 19:51
@JaredScar JaredScar added the ai-review Request a Claude code review label Apr 17, 2026
@JaredScar JaredScar requested review from a team as code owners April 17, 2026 19:56
@JaredScar JaredScar requested a review from gbubemismith April 17, 2026 19:56
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 17, 2026

🤖 Bitwarden Claude Code Review

Overall Assessment: REQUEST CHANGES

Re-reviewed after the three previously-flagged threads were resolved. The earlier concerns — missing login.username/login.uris extractors in the worker, firstValueFrom dropping upstream re-emissions on collectionAdminViews$, and stale manageableCollectionIds when allCollections changes alone — have all been addressed in the latest commits. One new correctness issue was found in the worker's search error path.

Code Review Details
  • ⚠️ : Worker search errors leave the caller's Promise unresolved; searchCiphers hangs and isCipherSearching$ stays true.
    • libs/common/src/vault/services/search.worker.ts:179-181

Comment thread libs/common/src/vault/services/search.worker.ts
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 17, 2026

Codecov Report

❌ Patch coverage is 6.42857% with 131 lines in your changes missing coverage. Please review.
✅ Project coverage is 46.97%. Comparing base (f73e2be) to head (f659f8c).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
libs/common/src/vault/services/search.worker.ts 0.00% 61 Missing ⚠️
...nsole/organizations/collections/vault.component.ts 0.00% 42 Missing ⚠️
...tions/services/default-collection-admin.service.ts 0.00% 14 Missing ⚠️
libs/common/src/vault/services/cipher.service.ts 10.00% 9 Missing ⚠️
...lt/components/vault-items/vault-items.component.ts 62.50% 1 Missing and 2 partials ⚠️
...ault/services/default-cipher-encryption.service.ts 60.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #20243      +/-   ##
==========================================
- Coverage   47.01%   46.97%   -0.04%     
==========================================
  Files        3912     3913       +1     
  Lines      118440   118554     +114     
  Branches    18117    18130      +13     
==========================================
+ Hits        55681    55688       +7     
- Misses      58571    58674     +103     
- Partials     4188     4192       +4     

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

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 17, 2026

Logo
Checkmarx One – Scan Summary & Details0b1835ea-f7d6-426f-b8c3-82cb932f4e78


New Issues (5) Checkmarx found the following issues in this Pull Request
# Severity Issue Source File / Package Checkmarx Insight
1 HIGH CVE-2026-25639 Npm-axios-1.13.2
detailsRecommended version: 1.15.0
Description: Axios is a promise based HTTP client for the browser and Node.js. Prior to 1.13.5, the mergeConfig function in axios crashes with a TypeError when ...
Attack Vector: NETWORK
Attack Complexity: LOW
Vulnerable Package
2 HIGH CVE-2026-29074 Npm-svgo-3.3.2
detailsRecommended version: 3.3.3
Description: SVGO is a Node.js library and command-line application for optimizing SVG files. Versions 2.1.0 through 2.8.0, 3.0.0 through 3.3.2, and versions pr...
Attack Vector: NETWORK
Attack Complexity: LOW
Vulnerable Package
3 MEDIUM CVE-2025-62718 Npm-axios-1.13.2
detailsRecommended version: 1.15.0
Description: Axios is a promise based HTTP client for the browser and Node.js. Prior to 1.15.0, Axios does not correctly handle hostname normalization when chec...
Attack Vector: NETWORK
Attack Complexity: LOW
Vulnerable Package
4 MEDIUM CVE-2026-40175 Npm-axios-1.13.2
detailsRecommended version: 1.15.0
Description: Axios is a promise-based HTTP client for the browser and Node.js. Prior to 0.31.0 and 1.x prior to 1.15.0, the Axios library is vulnerable to a spe...
Attack Vector: NETWORK
Attack Complexity: HIGH
Vulnerable Package
5 MEDIUM Missing_HSTS_Header apps/browser/src/dirt/phishing-detection/services/phishing-data.service.ts: 304
detailsThe web-application does not define an HSTS header, leaving it vulnerable to attack.
Attack Vector

JaredScar and others added 5 commits April 17, 2026 16:53
… Angular's zone for improved performance. Update VaultItemsComponent to use a getter/setter for allCollections, ensuring proper refresh of items. Enhance search.worker.ts with explicit extractors for login fields to maintain compatibility with nested object structures.
…d of null for login fields, enhancing compatibility with nested object structures.
…or conditional statements in search results processing.
Comment on lines +179 to +181
} catch (e: unknown) {
self.postMessage({ type: "error", error: String(e) });
}
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.

⚠️ IMPORTANT: Search-path error messages hang the caller's Promise indefinitely.

Details and fix

When lunr throws inside the worker's search handler (e.g., user types an invalid query like >(), the worker posts { type: "error", error } without the requestId. On the main thread, getOrCreateWorker's onmessage only resolves pendingSearches entries when msg.type === "searchResults" — the "error" branch is ignored. The entry in pendingSearches is never deleted, so searchInWorker's Promise never settles, searchCiphers awaits forever, and isCipherSearching$ remains true (the searching spinner never clears).

The main-thread fallback path handles this exact case in search.service.ts (wraps index.search(...) in try/catch and logs), so the worker path is now less resilient than the code it replaced for malformed Lunr queries.

Suggested fix: include requestId on the error response and treat it as "empty results" on the main thread. For example in search.worker.ts:

} catch (e: unknown) {
  self.postMessage({ type: "searchResults", requestId, results: [] });
  // Optionally also post a separate diagnostic error message
}

…and/or add an error branch in getOrCreateWorker's onmessage that resolves the matching pendingSearches entry with [].

Copy link
Copy Markdown
Member

@eliykat eliykat left a comment

Choose a reason for hiding this comment

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

Some nice work here and good insights, particularly running work outside of the ngZone. Let's just hold for now while we wait for feedback from Platform on how multithreading is going to be handled with the SDK.

/**
* Long-lived Web Worker that owns the Lunr full-text search index for the entire session.
*
* WHY LONG-LIVED: The previous design built the index in a worker then serialised it and
Copy link
Copy Markdown
Contributor

@quexten quexten Apr 20, 2026

Choose a reason for hiding this comment

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

@JaredScar KM has a concurrent piece of work that eliminates search indexing entirely in most cases, and probably already achieves your goal. It also restructures the search service massively, and conflict with this work. We should sync up on how to proceed

#19251

Unless you actually use lunr search queries, we should never build the search index, which is what the above work implements. Most users do not use lunr.

Two more notes here:

However, a service worker always introduces a lot of complexity, and is probably just not needed with the approach taken in #19251. Could you test if #19251 already solves your issue?

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.

I'll also note that #19251 has been through multiple review rounds at this point, and partially through QA.

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.

Already discussed in Slack, but just for completeness - I agree we want to progress #19251 and rethink reintroducing multithreading per KM Team's advice.

// Promise.all(8K) floods the microtask queue — decrypt in chunks with event-loop
// yields so the browser can paint and handle input between each batch.
const DECRYPT_CHUNK_SIZE = 2_000;
const results: CollectionAdminView[] = [];
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.

Note: Porting state to the SDK will give better speed improvements.

…cipher fetch events. Introduce performance measurement for load duration and log debug messages upon load start and completion, improving observability of data retrieval processes.
@sonarqubecloud
Copy link
Copy Markdown

This change eliminates the unnecessary call to indexCiphers within the search logic, streamlining the process and improving performance. Additionally, the concatMap operator has been imported for potential future use.
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants