Bulk Lock & Unlock
Relevant source files
The following files were used as context for generating this wiki page:
The Bulk Lock & Unlock system in Refined GitHub Projects provides users with the ability to manage conversation states across multiple GitHub Project items simultaneously. This feature addresses the limitation in GitHub Projects V2 where locking or unlocking issue conversations must be performed individually. Users can select multiple issues from the project table view and apply a lock status, optionally specifying a reason such as "off-topic," "resolved," or "spam."
The system is built on a decoupled architecture where the user interface (running in the content script) triggers background handlers that interact with the GitHub GraphQL API. All operations are processed through a sequential background queue to ensure rate-limit safety and maintain technical integrity of the user's Personal Access Token (PAT).
Sources: README.md:58, README.md:231-239, src/components/bulk/bulk-actions-bar.tsx:714-742
System Architecture and Data Flow
The Bulk Lock/Unlock workflow follows the project's standard pattern for bulk operations: UI interaction, message passing, ID resolution, and sequential API execution.
Operation Sequence
The process begins when a user selects items in the GitHub Projects table and selects "Lock Conversations" or "Unpin" from the Bulk Actions Bar. The frontend opens a confirmation modal to collect necessary parameters (like lock reasons) before sending a typed message to the background service worker.
The background worker performs a critical "resolution" step, converting DOM-extracted identifiers (e.g., issue:12345) into real GitHub Node IDs required for GraphQL mutations.
Sources: src/entries/background/handlers/bulk-handlers.ts:327-385, src/entries/background/helpers.ts:1062-1132, src/components/bulk/bulk-actions-bar.tsx:714-725
Component Breakdown
Frontend Components
The user interface for bulk locking is primarily managed by the BulkActionsBar and specific modal components.
| Component | Responsibility |
|---|---|
BulkActionsBar | Monitors row selection and provides the "Actions" menu entry for Locking/Unlocking. |
BulkLockModal | Collects the lock reason from the user and confirms the count of items to be affected. |
BulkUnpinModal | Simple confirmation dialog for removing the pinned status of selected items. |
The BulkActionsBar registers keyboard shortcuts, specifically ⌘⇧L (Mac) or ⌃⇧L (Windows) to trigger the lock workflow.
Sources: src/components/bulk/bulk-actions-bar.tsx:327, src/components/bulk/bulk-actions-bar.tsx:817-848
Background Handlers
The background logic resides in bulk-handlers.ts, which registers listeners for bulkLock, bulkPin, and bulkUnpin messages.
- Concurrency Control: Before starting, handlers check
isBulkFull()and callacquireBulk()to prevent overwhelming the background queue with concurrent bulk operations. - Sequential Execution: Each mutation is followed by an
await sleep(1000)call. This is a non-negotiable safety requirement to prevent 403 Abuse alerts from GitHub.
Sources: src/entries/background/handlers/bulk-handlers.ts:333-339, src/entries/background/handlers/bulk-handlers.ts:358, CONTRIBUTING.md:15-18
Data Models and Mutations
The feature utilizes specific GraphQL mutations defined in the project's library.
GraphQL Mutations
// From src/lib/graphql/mutations
mutation LockIssue($lockableId: ID!, $lockReason: LockReason) {
lockLockable(input: {lockableId: $lockableId, lockReason: $lockReason}) {
lockedRecord {
locked
}
}
}
mutation UnlockIssue($lockableId: ID!) {
unlockLockable(input: {lockableId: $lockableId}) {
unlockedRecord {
locked
}
}
}
Sources: src/entries/background/handlers/bulk-handlers.ts:24-27
Lock Reasons
When locking a conversation, the system supports standard GitHub lock reasons. These are passed as the lockReason parameter in the bulkLock message.
| Reason Code | Display Label |
|---|---|
OFF_TOPIC | Off-topic |
TOO_HEATED | Too heated |
RESOLVED | Resolved |
SPAM | Spam |
null | (No reason specified) |
| Sources: src/components/bulk/bulk-actions-bar.tsx:142-144, src/entries/background/handlers/bulk-handlers.ts:360-363 |
Technical Implementation Details
ID Resolution Logic
Because the extension scrapes item IDs from the GitHub DOM, the background script must map these to GitHub's internal GraphQL Node IDs before performing mutations.
The resolveProjectItemIds function paginates through project items, matching the databaseId of the item content against the IDs extracted from the page.
Sources: src/entries/background/helpers.ts:1072-1132
Rate Limit Handling
All lock/unlock tasks are wrapped in a withRateLimitRetry helper. If GitHub returns a 403 or 429 status code, the background queue pauses, broadcasts a "Paused" state to the UI (showing a countdown to the user), and automatically retries after the period specified in the Retry-After header.
Sources: src/entries/background/helpers.ts:1218-1240
Conclusion
The Bulk Lock & Unlock feature leverages a robust background messaging and queueing architecture to bring administrative superpowers to GitHub Projects V2. By combining a native-feeling UI with strict sequential execution and rate-limit awareness, the system ensures that large-scale status changes can be performed safely and efficiently without risk to the user's GitHub account or Personal Access Token.