feat(web): Add force resync buttons for repo & connections - #610

Merged
brendan-kellam merged 5 commits into
mainfrom
bkellam/force_resync
Nov 11, 2025
Merged

feat(web): Add force resync buttons for repo & connections#610
brendan-kellam merged 5 commits into
mainfrom
bkellam/force_resync

Conversation

@brendan-kellam

@brendan-kellambrendan-kellam commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

The following adds force re-sync buttons for repo indexing and connection syncing. There are located in the repo details page and connections detail page, respectively.

imageimage

This is accomplished by adding a internal api endpoint in the worker that exposes two endpoints, /api/sync-connection and /api/index-repo. Server actions proxy the requests to the worker endpoint.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added "Trigger sync" buttons for connections and repositories, enabling organization owners to manually trigger synchronization and indexing operations on demand.
    • Integrated loading indicators and success/error notifications to provide real-time feedback during sync operations.
  • Documentation

    • Added documentation for internal worker API utilities.

@github-actions

This comment has been minimized.

@coderabbitai

coderabbitaiBot commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Introduces force resync buttons for connections and repositories via a new backend API server class. The server exposes POST endpoints /api/sync-connection and /api/index-repo that validate input, create indexing jobs through managers, and return job IDs. Frontend components conditionally display sync/index buttons for authorized users with corresponding request handlers and user feedback.

Changes

Cohort / File(s)Summary
API Server Implementation
packages/backend/src/api.ts
New Api class wiring Express app with /metrics and POST endpoints (/api/sync-connection, /api/index-repo); validates input via zod, creates jobs via ConnectionManager/RepoIndexManager, returns jobId; handles errors with 400/404 responses; listens on port 3060
Backend Initialization & Integration
packages/backend/src/index.ts
Added express-async-errors import; created Api instance in startup; wired api.dispose() into cleanup path; removed promClient.dispose() from shutdown
HTTP Server Separation
packages/backend/src/promClient.ts
Removed HTTP metrics server setup (Express app, /metrics route, PORT constant); made registry public; removed dispose method and server lifecycle management
Job Creation API
packages/backend/src/repoIndexManager.ts
Made createJobs method public; added return type Promise<string[]> returning job IDs
Dependencies
packages/backend/package.json
Added express-async-errors ^3.1.1 to devDependencies
Worker API Actions
packages/web/src/features/workerApi/actions.ts
New module exporting syncConnection(connectionId) and indexRepo(repoId); enforces OWNER role; POSTs to http://localhost:3060, validates response with zod, returns jobId
Worker API Documentation
packages/web/src/features/workerApi/README.md
Added README describing utilities to interact with internal worker REST API
Authorization Type Annotation
packages/web/src/withAuthV2.ts
Added explicit return type Promise<T | ServiceError> to withMinimumOrgRole
Repository Index UI
packages/web/src/app/[domain]/repos/[id]/page.tsx
Added role-based retrieval via getCurrentUserRole; conditionally show index button based on OWNER status; inject repoId and isIndexButtonVisible into RepoJobsTable
Repository Jobs Table
packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx
Added repoId and isIndexButtonVisible props; introduced isIndexSubmitting state and onIndexButtonClick handler; replaced single Refresh button with button group including conditional "Trigger sync" LoadingButton; added indexRepo, isServiceError, LoadingButton imports
Connection Sync UI
packages/web/src/app/[domain]/settings/connections/[id]/page.tsx
Added id validation with notFound on NaN; inject connectionId into ConnectionJobsTable; import getConfigSettings
Connection Jobs Table
packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx
Added connectionId prop; introduced isSyncSubmitting state and onSyncButtonClick handler; replaced single Refresh button with button group including conditional "Trigger sync" LoadingButton; added syncConnection, isServiceError, LoadingButton imports
Documentation
CHANGELOG.md
Added entry documenting force resync buttons for connections and repositories

Sequence Diagram

sequenceDiagram
actor User
participant Frontend as Frontend UI
participant ServerAction as Server Action<br/>(withAuthV2)
participant WorkerAPI as Worker API<br/>(Port 3060)
participant Manager as Job Manager
participant DB as Database
User->>Frontend: Click "Trigger sync"<br/>button
Frontend->>Frontend: Set isSubmitting=true
Frontend->>ServerAction: Call syncConnection(id)<br/>or indexRepo(id)
rect rgb(200, 220, 255)
Note over ServerAction: Authorization Check
ServerAction->>ServerAction: Verify OWNER role
alt Role valid
ServerAction->>WorkerAPI: POST /api/sync-connection<br/>or /api/index-repo
else Role invalid
ServerAction-->>Frontend: ServiceError
end
end
rect rgb(200, 235, 200)
Note over WorkerAPI: Validation & Job Creation
WorkerAPI->>WorkerAPI: Validate input (zod)
WorkerAPI->>DB: Fetch connection/repo
alt Resource found
WorkerAPI->>Manager: createJobs()
Manager->>DB: Enqueue job
Manager-->>WorkerAPI: Return jobId[]
WorkerAPI-->>ServerAction: {jobId}
else Not found
WorkerAPI-->>ServerAction: 404 error
end
end
ServerAction->>Frontend: Return jobId
Frontend->>Frontend: Set isSubmitting=false
Frontend->>Frontend: Show success toast
Frontend->>Frontend: router.refresh()
Frontend->>User: Update UI with<br/>new job status
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas requiring attention:
    • Api class endpoint logic and error handling paths (validation, resource lookups, job creation)
    • Role-based authorization integration across frontend server actions
    • State management and async handler patterns in repoJobsTable and connectionJobsTable components (duplication of sync/index patterns)
    • HTTP client calls to localhost:3060 and response validation with zod schemas

Possibly related PRs

Suggested labels

sourcebot-team

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly describes the main change: adding force resync buttons for repositories and connections, which aligns with the primary functionality introduced across the changeset.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@brendan-kellam

Copy link
Copy Markdown
ContributorAuthor

@coderabbitai review

@coderabbitai

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 5

🧹 Nitpick comments (4)
packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (1)

197-215: Consider extracting jobId from success toast message.

The success toast displays the jobId, but this information is included inline in the message string. If you need to make the jobId clickable or copyable in the future, consider storing it separately.

Optional improvement:

 if (!isServiceError(response)) {
const { jobId } = response;
toast({
- description: `✅ Repository sync triggered successfully. Job ID: ${jobId}`,+ description: (+ <div className="flex items-center gap-2">+ <span>✅ Repository sync triggered successfully. Job ID:</span>+ <code className="text-xs">{jobId}</code>+ </div>+ ),
})
packages/web/src/features/workerApi/README.md (1)

1-1: Consider expanding the documentation.

While the current description is accurate, adding examples of the available endpoints (/api/sync-connection, /api/index-repo) and their request/response formats would improve developer experience.

Example enhancement:

# Worker API
This folder contains utilities to interact with the internal worker REST API. See packages/backend/api.ts
## Available Endpoints-`POST /api/sync-connection` - Trigger a connection sync
-`POST /api/index-repo` - Trigger a repository index
## Usage```typescriptimport { syncConnection, indexRepo } from'./actions';
// Sync a connectionconst result =awaitsyncConnection(connectionId);
// Index a repositoryconst result =awaitindexRepo(repoId);

</blockquote></details>
<details>
<summary>packages/web/src/features/workerApi/actions.ts (1)</summary><blockquote>
`11-59`: **Consider extracting common fetch logic.**
Both actions share nearly identical structure (fetch → check response → parse → validate). A helper function could reduce duplication:
```typescript
const callWorkerApi = async <T extends { jobId: string }>(
endpoint: string,
body: Record<string, unknown>,
errorMessage: string
): Promise<T | ServiceError> => {
const response = await fetch(`${WORKER_API_URL}${endpoint}`, {
method: 'POST',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' },
});
if (!response.ok) {
return unexpectedError(errorMessage);
}
const data = await response.json();
const schema = z.object({ jobId: z.string() });
return schema.parse(data) as T;
};
export const syncConnection = async (connectionId: number) => sew(() =>
withAuthV2(({ role }) =>
withMinimumOrgRole(role, OrgRole.OWNER, () =>
callWorkerApi('/api/sync-connection', { connectionId }, 'Failed to sync connection')
)
)
);
packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (1)

195-212: Consider using finally block for loading state cleanup.

The loading state reset should be in a finally block to ensure it's always executed, even if an unexpected error occurs:

 const onSyncButtonClick = React.useCallback(async () => {
setIsSyncSubmitting(true);
- const response = await syncConnection(connectionId);-- if (!isServiceError(response)) {- const { jobId } = response;- toast({- description: `✅ Connection synced successfully. Job ID: ${jobId}`,- })- router.refresh();- } else {- toast({- description: `❌ Failed to sync connection. ${response.message}`,- });+ try {+ const response = await syncConnection(connectionId);++ if (!isServiceError(response)) {+ const { jobId } = response;+ toast({+ description: `✅ Connection synced successfully. Job ID: ${jobId}`,+ })+ router.refresh();+ } else {+ toast({+ description: `❌ Failed to sync connection. ${response.message}`,+ });+ }+ } finally {+ setIsSyncSubmitting(false);
}
-- setIsSyncSubmitting(false);
}, [connectionId, router, toast]);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2dfafda and 5d6f0bf.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (13)
  • CHANGELOG.md (1 hunks)
  • packages/backend/package.json (1 hunks)
  • packages/backend/src/api.ts (1 hunks)
  • packages/backend/src/index.ts (3 hunks)
  • packages/backend/src/promClient.ts (1 hunks)
  • packages/backend/src/repoIndexManager.ts (2 hunks)
  • packages/web/src/app/[domain]/repos/[id]/page.tsx (4 hunks)
  • packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (5 hunks)
  • packages/web/src/app/[domain]/settings/connections/[id]/page.tsx (3 hunks)
  • packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (3 hunks)
  • packages/web/src/features/workerApi/README.md (1 hunks)
  • packages/web/src/features/workerApi/actions.ts (1 hunks)
  • packages/web/src/withAuthV2.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*

📄 CodeRabbit inference engine (.cursor/rules/style.mdc)

Filenames should always be camelCase. Exception: if there are filenames in the same directory with a format other than camelCase, use that format to keep things consistent.

Files:

  • packages/web/src/features/workerApi/README.md
  • CHANGELOG.md
  • packages/web/src/app/[domain]/repos/[id]/page.tsx
  • packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx
  • packages/backend/src/index.ts
  • packages/web/src/withAuthV2.ts
  • packages/backend/src/repoIndexManager.ts
  • packages/backend/src/api.ts
  • packages/web/src/features/workerApi/actions.ts
  • packages/backend/package.json
  • packages/backend/src/promClient.ts
  • packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx
  • packages/web/src/app/[domain]/settings/connections/[id]/page.tsx
🔇 Additional comments (17)
CHANGELOG.md (1)

14-16: LGTM!

The changelog entry correctly documents the new force resync feature and follows the established format.

packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (2)

182-190: LGTM!

The component signature correctly extends the props with repoId and isIndexButtonVisible for conditional button rendering.


281-305: LGTM!

The button group layout and conditional rendering logic are well-structured. The LoadingButton properly shows loading state during async operations.

packages/web/src/app/[domain]/repos/[id]/page.tsx (2)

55-58: LGTM!

The user role retrieval and error handling are correctly implemented. This enables role-based access control for the index button visibility.


181-186: LGTM!

The role-based visibility check (userRole === OrgRole.OWNER) correctly restricts the index button to owners only. This aligns with security best practices for sensitive operations.

packages/backend/src/index.ts (3)

5-5: LGTM!

The import of express-async-errors for side effects is correct. This package automatically wraps Express async handlers to catch rejected promises.


77-82: LGTM!

The Api instance is correctly instantiated with all required dependencies (promClient, prisma, connectionManager, repoIndexManager).


111-111: LGTM!

The Api instance is properly disposed during cleanup, ensuring graceful shutdown of the HTTP server and any associated resources.

packages/backend/src/repoIndexManager.ts (1)

195-226: LGTM!

The method visibility change to public and the addition of the return value (jobs.map(job => job.id)) correctly enable external callers to trigger indexing jobs and receive the created job IDs. This is necessary for the new API endpoints to return job IDs to clients.

packages/web/src/app/[domain]/settings/connections/[id]/page.tsx (2)

28-31: LGTM!

The input validation correctly handles invalid connection IDs by returning notFound() when the parsed ID is NaN. This prevents runtime errors from invalid route parameters.


178-181: LGTM!

The connectionId prop is correctly passed to ConnectionJobsTable, enabling the sync functionality. This change aligns with the corresponding updates to the table component.

packages/web/src/withAuthV2.ts (1)

180-184: LGTM! Explicit return type improves type safety.

The addition of an explicit return type Promise<T | ServiceError> enhances type safety and makes the function signature clearer. This aligns well with the worker API actions that rely on this typing.

packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (1)

264-286: LGTM! Well-structured UI controls.

The button group provides clear actions with appropriate visual feedback. The use of LoadingButton for the sync action ensures good UX during async operations.

packages/backend/src/promClient.ts (1)

3-3: LGTM! Good separation of concerns.

Making registry public enables the Api class to expose metrics via HTTP while keeping metric collection logic in PromClient. This refactor properly separates HTTP server concerns from metrics collection.

packages/backend/src/api.ts (3)

91-92: Verify array destructuring safety.

Same concern as in syncConnection: the destructuring assumes at least one job ID is returned. Verify that RepoIndexManager.createJobs always returns at least one element, or add validation as suggested above.


95-102: LGTM! Proper graceful shutdown.

The dispose method correctly wraps server.close in a Promise for proper async cleanup. This ensures graceful shutdown of the HTTP server.


65-67: No changes required to array destructuring—current usage is safe.

The ConnectionManager.createJobs method (at line 120) returns jobs.map(job => job.id). When called with a single-element array [connection], it reliably creates exactly one job and returns a single-element array. Since the connection is validated at line 60 before being passed to createJobs, the destructuring const [jobId] is safe.

The defensive check suggested in the review would only be necessary if empty arrays were possible inputs in this code path, which they are not.

Comment threadpackages/backend/package.json Outdated
Comment threadpackages/backend/src/api.ts
Comment threadpackages/backend/src/api.ts
Comment threadpackages/web/src/features/workerApi/actions.ts
Comment threadpackages/web/src/features/workerApi/actions.ts
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@brendan-kellam
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all \u003cpre\u003e\u003ccode\u003e blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks"); } } catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); } })(); (function(){ try { var __m = "github.com"; var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(web): Add force resync buttons for repo & connections - #610

Merged
brendan-kellam merged 5 commits into
mainfrom
bkellam/force_resync
Nov 11, 2025
Merged

feat(web): Add force resync buttons for repo & connections#610
brendan-kellam merged 5 commits into
mainfrom
bkellam/force_resync

Conversation

@brendan-kellam

@brendan-kellambrendan-kellam commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

The following adds force re-sync buttons for repo indexing and connection syncing. There are located in the repo details page and connections detail page, respectively.

imageimage

This is accomplished by adding a internal api endpoint in the worker that exposes two endpoints, /api/sync-connection and /api/index-repo. Server actions proxy the requests to the worker endpoint.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added "Trigger sync" buttons for connections and repositories, enabling organization owners to manually trigger synchronization and indexing operations on demand.
    • Integrated loading indicators and success/error notifications to provide real-time feedback during sync operations.
  • Documentation

    • Added documentation for internal worker API utilities.

@github-actions

This comment has been minimized.

@coderabbitai

coderabbitaiBot commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Introduces force resync buttons for connections and repositories via a new backend API server class. The server exposes POST endpoints /api/sync-connection and /api/index-repo that validate input, create indexing jobs through managers, and return job IDs. Frontend components conditionally display sync/index buttons for authorized users with corresponding request handlers and user feedback.

Changes

Cohort / File(s)Summary
API Server Implementation
packages/backend/src/api.ts
New Api class wiring Express app with /metrics and POST endpoints (/api/sync-connection, /api/index-repo); validates input via zod, creates jobs via ConnectionManager/RepoIndexManager, returns jobId; handles errors with 400/404 responses; listens on port 3060
Backend Initialization & Integration
packages/backend/src/index.ts
Added express-async-errors import; created Api instance in startup; wired api.dispose() into cleanup path; removed promClient.dispose() from shutdown
HTTP Server Separation
packages/backend/src/promClient.ts
Removed HTTP metrics server setup (Express app, /metrics route, PORT constant); made registry public; removed dispose method and server lifecycle management
Job Creation API
packages/backend/src/repoIndexManager.ts
Made createJobs method public; added return type Promise<string[]> returning job IDs
Dependencies
packages/backend/package.json
Added express-async-errors ^3.1.1 to devDependencies
Worker API Actions
packages/web/src/features/workerApi/actions.ts
New module exporting syncConnection(connectionId) and indexRepo(repoId); enforces OWNER role; POSTs to http://localhost:3060, validates response with zod, returns jobId
Worker API Documentation
packages/web/src/features/workerApi/README.md
Added README describing utilities to interact with internal worker REST API
Authorization Type Annotation
packages/web/src/withAuthV2.ts
Added explicit return type Promise<T | ServiceError> to withMinimumOrgRole
Repository Index UI
packages/web/src/app/[domain]/repos/[id]/page.tsx
Added role-based retrieval via getCurrentUserRole; conditionally show index button based on OWNER status; inject repoId and isIndexButtonVisible into RepoJobsTable
Repository Jobs Table
packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx
Added repoId and isIndexButtonVisible props; introduced isIndexSubmitting state and onIndexButtonClick handler; replaced single Refresh button with button group including conditional "Trigger sync" LoadingButton; added indexRepo, isServiceError, LoadingButton imports
Connection Sync UI
packages/web/src/app/[domain]/settings/connections/[id]/page.tsx
Added id validation with notFound on NaN; inject connectionId into ConnectionJobsTable; import getConfigSettings
Connection Jobs Table
packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx
Added connectionId prop; introduced isSyncSubmitting state and onSyncButtonClick handler; replaced single Refresh button with button group including conditional "Trigger sync" LoadingButton; added syncConnection, isServiceError, LoadingButton imports
Documentation
CHANGELOG.md
Added entry documenting force resync buttons for connections and repositories

Sequence Diagram

sequenceDiagram
actor User
participant Frontend as Frontend UI
participant ServerAction as Server Action<br/>(withAuthV2)
participant WorkerAPI as Worker API<br/>(Port 3060)
participant Manager as Job Manager
participant DB as Database
User->>Frontend: Click "Trigger sync"<br/>button
Frontend->>Frontend: Set isSubmitting=true
Frontend->>ServerAction: Call syncConnection(id)<br/>or indexRepo(id)
rect rgb(200, 220, 255)
Note over ServerAction: Authorization Check
ServerAction->>ServerAction: Verify OWNER role
alt Role valid
ServerAction->>WorkerAPI: POST /api/sync-connection<br/>or /api/index-repo
else Role invalid
ServerAction-->>Frontend: ServiceError
end
end
rect rgb(200, 235, 200)
Note over WorkerAPI: Validation & Job Creation
WorkerAPI->>WorkerAPI: Validate input (zod)
WorkerAPI->>DB: Fetch connection/repo
alt Resource found
WorkerAPI->>Manager: createJobs()
Manager->>DB: Enqueue job
Manager-->>WorkerAPI: Return jobId[]
WorkerAPI-->>ServerAction: {jobId}
else Not found
WorkerAPI-->>ServerAction: 404 error
end
end
ServerAction->>Frontend: Return jobId
Frontend->>Frontend: Set isSubmitting=false
Frontend->>Frontend: Show success toast
Frontend->>Frontend: router.refresh()
Frontend->>User: Update UI with<br/>new job status
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas requiring attention:
    • Api class endpoint logic and error handling paths (validation, resource lookups, job creation)
    • Role-based authorization integration across frontend server actions
    • State management and async handler patterns in repoJobsTable and connectionJobsTable components (duplication of sync/index patterns)
    • HTTP client calls to localhost:3060 and response validation with zod schemas

Possibly related PRs

Suggested labels

sourcebot-team

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly describes the main change: adding force resync buttons for repositories and connections, which aligns with the primary functionality introduced across the changeset.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@brendan-kellam

Copy link
Copy Markdown
ContributorAuthor

@coderabbitai review

@coderabbitai

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 5

🧹 Nitpick comments (4)
packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (1)

197-215: Consider extracting jobId from success toast message.

The success toast displays the jobId, but this information is included inline in the message string. If you need to make the jobId clickable or copyable in the future, consider storing it separately.

Optional improvement:

 if (!isServiceError(response)) {
const { jobId } = response;
toast({
- description: `✅ Repository sync triggered successfully. Job ID: ${jobId}`,+ description: (+ <div className="flex items-center gap-2">+ <span>✅ Repository sync triggered successfully. Job ID:</span>+ <code className="text-xs">{jobId}</code>+ </div>+ ),
})
packages/web/src/features/workerApi/README.md (1)

1-1: Consider expanding the documentation.

While the current description is accurate, adding examples of the available endpoints (/api/sync-connection, /api/index-repo) and their request/response formats would improve developer experience.

Example enhancement:

# Worker API
This folder contains utilities to interact with the internal worker REST API. See packages/backend/api.ts
## Available Endpoints-`POST /api/sync-connection` - Trigger a connection sync
-`POST /api/index-repo` - Trigger a repository index
## Usage```typescriptimport { syncConnection, indexRepo } from'./actions';
// Sync a connectionconst result =awaitsyncConnection(connectionId);
// Index a repositoryconst result =awaitindexRepo(repoId);

</blockquote></details>
<details>
<summary>packages/web/src/features/workerApi/actions.ts (1)</summary><blockquote>
`11-59`: **Consider extracting common fetch logic.**
Both actions share nearly identical structure (fetch → check response → parse → validate). A helper function could reduce duplication:
```typescript
const callWorkerApi = async <T extends { jobId: string }>(
endpoint: string,
body: Record<string, unknown>,
errorMessage: string
): Promise<T | ServiceError> => {
const response = await fetch(`${WORKER_API_URL}${endpoint}`, {
method: 'POST',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' },
});
if (!response.ok) {
return unexpectedError(errorMessage);
}
const data = await response.json();
const schema = z.object({ jobId: z.string() });
return schema.parse(data) as T;
};
export const syncConnection = async (connectionId: number) => sew(() =>
withAuthV2(({ role }) =>
withMinimumOrgRole(role, OrgRole.OWNER, () =>
callWorkerApi('/api/sync-connection', { connectionId }, 'Failed to sync connection')
)
)
);
packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (1)

195-212: Consider using finally block for loading state cleanup.

The loading state reset should be in a finally block to ensure it's always executed, even if an unexpected error occurs:

 const onSyncButtonClick = React.useCallback(async () => {
setIsSyncSubmitting(true);
- const response = await syncConnection(connectionId);-- if (!isServiceError(response)) {- const { jobId } = response;- toast({- description: `✅ Connection synced successfully. Job ID: ${jobId}`,- })- router.refresh();- } else {- toast({- description: `❌ Failed to sync connection. ${response.message}`,- });+ try {+ const response = await syncConnection(connectionId);++ if (!isServiceError(response)) {+ const { jobId } = response;+ toast({+ description: `✅ Connection synced successfully. Job ID: ${jobId}`,+ })+ router.refresh();+ } else {+ toast({+ description: `❌ Failed to sync connection. ${response.message}`,+ });+ }+ } finally {+ setIsSyncSubmitting(false);
}
-- setIsSyncSubmitting(false);
}, [connectionId, router, toast]);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2dfafda and 5d6f0bf.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (13)
  • CHANGELOG.md (1 hunks)
  • packages/backend/package.json (1 hunks)
  • packages/backend/src/api.ts (1 hunks)
  • packages/backend/src/index.ts (3 hunks)
  • packages/backend/src/promClient.ts (1 hunks)
  • packages/backend/src/repoIndexManager.ts (2 hunks)
  • packages/web/src/app/[domain]/repos/[id]/page.tsx (4 hunks)
  • packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (5 hunks)
  • packages/web/src/app/[domain]/settings/connections/[id]/page.tsx (3 hunks)
  • packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (3 hunks)
  • packages/web/src/features/workerApi/README.md (1 hunks)
  • packages/web/src/features/workerApi/actions.ts (1 hunks)
  • packages/web/src/withAuthV2.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*

📄 CodeRabbit inference engine (.cursor/rules/style.mdc)

Filenames should always be camelCase. Exception: if there are filenames in the same directory with a format other than camelCase, use that format to keep things consistent.

Files:

  • packages/web/src/features/workerApi/README.md
  • CHANGELOG.md
  • packages/web/src/app/[domain]/repos/[id]/page.tsx
  • packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx
  • packages/backend/src/index.ts
  • packages/web/src/withAuthV2.ts
  • packages/backend/src/repoIndexManager.ts
  • packages/backend/src/api.ts
  • packages/web/src/features/workerApi/actions.ts
  • packages/backend/package.json
  • packages/backend/src/promClient.ts
  • packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx
  • packages/web/src/app/[domain]/settings/connections/[id]/page.tsx
🔇 Additional comments (17)
CHANGELOG.md (1)

14-16: LGTM!

The changelog entry correctly documents the new force resync feature and follows the established format.

packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (2)

182-190: LGTM!

The component signature correctly extends the props with repoId and isIndexButtonVisible for conditional button rendering.


281-305: LGTM!

The button group layout and conditional rendering logic are well-structured. The LoadingButton properly shows loading state during async operations.

packages/web/src/app/[domain]/repos/[id]/page.tsx (2)

55-58: LGTM!

The user role retrieval and error handling are correctly implemented. This enables role-based access control for the index button visibility.


181-186: LGTM!

The role-based visibility check (userRole === OrgRole.OWNER) correctly restricts the index button to owners only. This aligns with security best practices for sensitive operations.

packages/backend/src/index.ts (3)

5-5: LGTM!

The import of express-async-errors for side effects is correct. This package automatically wraps Express async handlers to catch rejected promises.


77-82: LGTM!

The Api instance is correctly instantiated with all required dependencies (promClient, prisma, connectionManager, repoIndexManager).


111-111: LGTM!

The Api instance is properly disposed during cleanup, ensuring graceful shutdown of the HTTP server and any associated resources.

packages/backend/src/repoIndexManager.ts (1)

195-226: LGTM!

The method visibility change to public and the addition of the return value (jobs.map(job => job.id)) correctly enable external callers to trigger indexing jobs and receive the created job IDs. This is necessary for the new API endpoints to return job IDs to clients.

packages/web/src/app/[domain]/settings/connections/[id]/page.tsx (2)

28-31: LGTM!

The input validation correctly handles invalid connection IDs by returning notFound() when the parsed ID is NaN. This prevents runtime errors from invalid route parameters.


178-181: LGTM!

The connectionId prop is correctly passed to ConnectionJobsTable, enabling the sync functionality. This change aligns with the corresponding updates to the table component.

packages/web/src/withAuthV2.ts (1)

180-184: LGTM! Explicit return type improves type safety.

The addition of an explicit return type Promise<T | ServiceError> enhances type safety and makes the function signature clearer. This aligns well with the worker API actions that rely on this typing.

packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (1)

264-286: LGTM! Well-structured UI controls.

The button group provides clear actions with appropriate visual feedback. The use of LoadingButton for the sync action ensures good UX during async operations.

packages/backend/src/promClient.ts (1)

3-3: LGTM! Good separation of concerns.

Making registry public enables the Api class to expose metrics via HTTP while keeping metric collection logic in PromClient. This refactor properly separates HTTP server concerns from metrics collection.

packages/backend/src/api.ts (3)

91-92: Verify array destructuring safety.

Same concern as in syncConnection: the destructuring assumes at least one job ID is returned. Verify that RepoIndexManager.createJobs always returns at least one element, or add validation as suggested above.


95-102: LGTM! Proper graceful shutdown.

The dispose method correctly wraps server.close in a Promise for proper async cleanup. This ensures graceful shutdown of the HTTP server.


65-67: No changes required to array destructuring—current usage is safe.

The ConnectionManager.createJobs method (at line 120) returns jobs.map(job => job.id). When called with a single-element array [connection], it reliably creates exactly one job and returns a single-element array. Since the connection is validated at line 60 before being passed to createJobs, the destructuring const [jobId] is safe.

The defensive check suggested in the review would only be necessary if empty arrays were possible inputs in this code path, which they are not.

Comment threadpackages/backend/package.json Outdated
Comment threadpackages/backend/src/api.ts
Comment threadpackages/backend/src/api.ts
Comment threadpackages/web/src/features/workerApi/actions.ts
Comment threadpackages/web/src/features/workerApi/actions.ts
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@brendan-kellam
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(web): Add force resync buttons for repo & connections - #610

Merged
brendan-kellam merged 5 commits into
mainfrom
bkellam/force_resync
Nov 11, 2025
Merged

feat(web): Add force resync buttons for repo & connections#610
brendan-kellam merged 5 commits into
mainfrom
bkellam/force_resync

Conversation

@brendan-kellam

@brendan-kellambrendan-kellam commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

The following adds force re-sync buttons for repo indexing and connection syncing. There are located in the repo details page and connections detail page, respectively.

imageimage

This is accomplished by adding a internal api endpoint in the worker that exposes two endpoints, /api/sync-connection and /api/index-repo. Server actions proxy the requests to the worker endpoint.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added "Trigger sync" buttons for connections and repositories, enabling organization owners to manually trigger synchronization and indexing operations on demand.
    • Integrated loading indicators and success/error notifications to provide real-time feedback during sync operations.
  • Documentation

    • Added documentation for internal worker API utilities.

@github-actions

This comment has been minimized.

@coderabbitai

coderabbitaiBot commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Introduces force resync buttons for connections and repositories via a new backend API server class. The server exposes POST endpoints /api/sync-connection and /api/index-repo that validate input, create indexing jobs through managers, and return job IDs. Frontend components conditionally display sync/index buttons for authorized users with corresponding request handlers and user feedback.

Changes

Cohort / File(s)Summary
API Server Implementation
packages/backend/src/api.ts
New Api class wiring Express app with /metrics and POST endpoints (/api/sync-connection, /api/index-repo); validates input via zod, creates jobs via ConnectionManager/RepoIndexManager, returns jobId; handles errors with 400/404 responses; listens on port 3060
Backend Initialization & Integration
packages/backend/src/index.ts
Added express-async-errors import; created Api instance in startup; wired api.dispose() into cleanup path; removed promClient.dispose() from shutdown
HTTP Server Separation
packages/backend/src/promClient.ts
Removed HTTP metrics server setup (Express app, /metrics route, PORT constant); made registry public; removed dispose method and server lifecycle management
Job Creation API
packages/backend/src/repoIndexManager.ts
Made createJobs method public; added return type Promise<string[]> returning job IDs
Dependencies
packages/backend/package.json
Added express-async-errors ^3.1.1 to devDependencies
Worker API Actions
packages/web/src/features/workerApi/actions.ts
New module exporting syncConnection(connectionId) and indexRepo(repoId); enforces OWNER role; POSTs to http://localhost:3060, validates response with zod, returns jobId
Worker API Documentation
packages/web/src/features/workerApi/README.md
Added README describing utilities to interact with internal worker REST API
Authorization Type Annotation
packages/web/src/withAuthV2.ts
Added explicit return type Promise<T | ServiceError> to withMinimumOrgRole
Repository Index UI
packages/web/src/app/[domain]/repos/[id]/page.tsx
Added role-based retrieval via getCurrentUserRole; conditionally show index button based on OWNER status; inject repoId and isIndexButtonVisible into RepoJobsTable
Repository Jobs Table
packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx
Added repoId and isIndexButtonVisible props; introduced isIndexSubmitting state and onIndexButtonClick handler; replaced single Refresh button with button group including conditional "Trigger sync" LoadingButton; added indexRepo, isServiceError, LoadingButton imports
Connection Sync UI
packages/web/src/app/[domain]/settings/connections/[id]/page.tsx
Added id validation with notFound on NaN; inject connectionId into ConnectionJobsTable; import getConfigSettings
Connection Jobs Table
packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx
Added connectionId prop; introduced isSyncSubmitting state and onSyncButtonClick handler; replaced single Refresh button with button group including conditional "Trigger sync" LoadingButton; added syncConnection, isServiceError, LoadingButton imports
Documentation
CHANGELOG.md
Added entry documenting force resync buttons for connections and repositories

Sequence Diagram

sequenceDiagram
actor User
participant Frontend as Frontend UI
participant ServerAction as Server Action<br/>(withAuthV2)
participant WorkerAPI as Worker API<br/>(Port 3060)
participant Manager as Job Manager
participant DB as Database
User->>Frontend: Click "Trigger sync"<br/>button
Frontend->>Frontend: Set isSubmitting=true
Frontend->>ServerAction: Call syncConnection(id)<br/>or indexRepo(id)
rect rgb(200, 220, 255)
Note over ServerAction: Authorization Check
ServerAction->>ServerAction: Verify OWNER role
alt Role valid
ServerAction->>WorkerAPI: POST /api/sync-connection<br/>or /api/index-repo
else Role invalid
ServerAction-->>Frontend: ServiceError
end
end
rect rgb(200, 235, 200)
Note over WorkerAPI: Validation & Job Creation
WorkerAPI->>WorkerAPI: Validate input (zod)
WorkerAPI->>DB: Fetch connection/repo
alt Resource found
WorkerAPI->>Manager: createJobs()
Manager->>DB: Enqueue job
Manager-->>WorkerAPI: Return jobId[]
WorkerAPI-->>ServerAction: {jobId}
else Not found
WorkerAPI-->>ServerAction: 404 error
end
end
ServerAction->>Frontend: Return jobId
Frontend->>Frontend: Set isSubmitting=false
Frontend->>Frontend: Show success toast
Frontend->>Frontend: router.refresh()
Frontend->>User: Update UI with<br/>new job status
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas requiring attention:
    • Api class endpoint logic and error handling paths (validation, resource lookups, job creation)
    • Role-based authorization integration across frontend server actions
    • State management and async handler patterns in repoJobsTable and connectionJobsTable components (duplication of sync/index patterns)
    • HTTP client calls to localhost:3060 and response validation with zod schemas

Possibly related PRs

Suggested labels

sourcebot-team

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly describes the main change: adding force resync buttons for repositories and connections, which aligns with the primary functionality introduced across the changeset.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@brendan-kellam

Copy link
Copy Markdown
ContributorAuthor

@coderabbitai review

@coderabbitai

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 5

🧹 Nitpick comments (4)
packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (1)

197-215: Consider extracting jobId from success toast message.

The success toast displays the jobId, but this information is included inline in the message string. If you need to make the jobId clickable or copyable in the future, consider storing it separately.

Optional improvement:

 if (!isServiceError(response)) {
const { jobId } = response;
toast({
- description: `✅ Repository sync triggered successfully. Job ID: ${jobId}`,+ description: (+ <div className="flex items-center gap-2">+ <span>✅ Repository sync triggered successfully. Job ID:</span>+ <code className="text-xs">{jobId}</code>+ </div>+ ),
})
packages/web/src/features/workerApi/README.md (1)

1-1: Consider expanding the documentation.

While the current description is accurate, adding examples of the available endpoints (/api/sync-connection, /api/index-repo) and their request/response formats would improve developer experience.

Example enhancement:

# Worker API
This folder contains utilities to interact with the internal worker REST API. See packages/backend/api.ts
## Available Endpoints-`POST /api/sync-connection` - Trigger a connection sync
-`POST /api/index-repo` - Trigger a repository index
## Usage```typescriptimport { syncConnection, indexRepo } from'./actions';
// Sync a connectionconst result =awaitsyncConnection(connectionId);
// Index a repositoryconst result =awaitindexRepo(repoId);

</blockquote></details>
<details>
<summary>packages/web/src/features/workerApi/actions.ts (1)</summary><blockquote>
`11-59`: **Consider extracting common fetch logic.**
Both actions share nearly identical structure (fetch → check response → parse → validate). A helper function could reduce duplication:
```typescript
const callWorkerApi = async <T extends { jobId: string }>(
endpoint: string,
body: Record<string, unknown>,
errorMessage: string
): Promise<T | ServiceError> => {
const response = await fetch(`${WORKER_API_URL}${endpoint}`, {
method: 'POST',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' },
});
if (!response.ok) {
return unexpectedError(errorMessage);
}
const data = await response.json();
const schema = z.object({ jobId: z.string() });
return schema.parse(data) as T;
};
export const syncConnection = async (connectionId: number) => sew(() =>
withAuthV2(({ role }) =>
withMinimumOrgRole(role, OrgRole.OWNER, () =>
callWorkerApi('/api/sync-connection', { connectionId }, 'Failed to sync connection')
)
)
);
packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (1)

195-212: Consider using finally block for loading state cleanup.

The loading state reset should be in a finally block to ensure it's always executed, even if an unexpected error occurs:

 const onSyncButtonClick = React.useCallback(async () => {
setIsSyncSubmitting(true);
- const response = await syncConnection(connectionId);-- if (!isServiceError(response)) {- const { jobId } = response;- toast({- description: `✅ Connection synced successfully. Job ID: ${jobId}`,- })- router.refresh();- } else {- toast({- description: `❌ Failed to sync connection. ${response.message}`,- });+ try {+ const response = await syncConnection(connectionId);++ if (!isServiceError(response)) {+ const { jobId } = response;+ toast({+ description: `✅ Connection synced successfully. Job ID: ${jobId}`,+ })+ router.refresh();+ } else {+ toast({+ description: `❌ Failed to sync connection. ${response.message}`,+ });+ }+ } finally {+ setIsSyncSubmitting(false);
}
-- setIsSyncSubmitting(false);
}, [connectionId, router, toast]);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2dfafda and 5d6f0bf.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (13)
  • CHANGELOG.md (1 hunks)
  • packages/backend/package.json (1 hunks)
  • packages/backend/src/api.ts (1 hunks)
  • packages/backend/src/index.ts (3 hunks)
  • packages/backend/src/promClient.ts (1 hunks)
  • packages/backend/src/repoIndexManager.ts (2 hunks)
  • packages/web/src/app/[domain]/repos/[id]/page.tsx (4 hunks)
  • packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (5 hunks)
  • packages/web/src/app/[domain]/settings/connections/[id]/page.tsx (3 hunks)
  • packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (3 hunks)
  • packages/web/src/features/workerApi/README.md (1 hunks)
  • packages/web/src/features/workerApi/actions.ts (1 hunks)
  • packages/web/src/withAuthV2.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*

📄 CodeRabbit inference engine (.cursor/rules/style.mdc)

Filenames should always be camelCase. Exception: if there are filenames in the same directory with a format other than camelCase, use that format to keep things consistent.

Files:

  • packages/web/src/features/workerApi/README.md
  • CHANGELOG.md
  • packages/web/src/app/[domain]/repos/[id]/page.tsx
  • packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx
  • packages/backend/src/index.ts
  • packages/web/src/withAuthV2.ts
  • packages/backend/src/repoIndexManager.ts
  • packages/backend/src/api.ts
  • packages/web/src/features/workerApi/actions.ts
  • packages/backend/package.json
  • packages/backend/src/promClient.ts
  • packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx
  • packages/web/src/app/[domain]/settings/connections/[id]/page.tsx
🔇 Additional comments (17)
CHANGELOG.md (1)

14-16: LGTM!

The changelog entry correctly documents the new force resync feature and follows the established format.

packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (2)

182-190: LGTM!

The component signature correctly extends the props with repoId and isIndexButtonVisible for conditional button rendering.


281-305: LGTM!

The button group layout and conditional rendering logic are well-structured. The LoadingButton properly shows loading state during async operations.

packages/web/src/app/[domain]/repos/[id]/page.tsx (2)

55-58: LGTM!

The user role retrieval and error handling are correctly implemented. This enables role-based access control for the index button visibility.


181-186: LGTM!

The role-based visibility check (userRole === OrgRole.OWNER) correctly restricts the index button to owners only. This aligns with security best practices for sensitive operations.

packages/backend/src/index.ts (3)

5-5: LGTM!

The import of express-async-errors for side effects is correct. This package automatically wraps Express async handlers to catch rejected promises.


77-82: LGTM!

The Api instance is correctly instantiated with all required dependencies (promClient, prisma, connectionManager, repoIndexManager).


111-111: LGTM!

The Api instance is properly disposed during cleanup, ensuring graceful shutdown of the HTTP server and any associated resources.

packages/backend/src/repoIndexManager.ts (1)

195-226: LGTM!

The method visibility change to public and the addition of the return value (jobs.map(job => job.id)) correctly enable external callers to trigger indexing jobs and receive the created job IDs. This is necessary for the new API endpoints to return job IDs to clients.

packages/web/src/app/[domain]/settings/connections/[id]/page.tsx (2)

28-31: LGTM!

The input validation correctly handles invalid connection IDs by returning notFound() when the parsed ID is NaN. This prevents runtime errors from invalid route parameters.


178-181: LGTM!

The connectionId prop is correctly passed to ConnectionJobsTable, enabling the sync functionality. This change aligns with the corresponding updates to the table component.

packages/web/src/withAuthV2.ts (1)

180-184: LGTM! Explicit return type improves type safety.

The addition of an explicit return type Promise<T | ServiceError> enhances type safety and makes the function signature clearer. This aligns well with the worker API actions that rely on this typing.

packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (1)

264-286: LGTM! Well-structured UI controls.

The button group provides clear actions with appropriate visual feedback. The use of LoadingButton for the sync action ensures good UX during async operations.

packages/backend/src/promClient.ts (1)

3-3: LGTM! Good separation of concerns.

Making registry public enables the Api class to expose metrics via HTTP while keeping metric collection logic in PromClient. This refactor properly separates HTTP server concerns from metrics collection.

packages/backend/src/api.ts (3)

91-92: Verify array destructuring safety.

Same concern as in syncConnection: the destructuring assumes at least one job ID is returned. Verify that RepoIndexManager.createJobs always returns at least one element, or add validation as suggested above.


95-102: LGTM! Proper graceful shutdown.

The dispose method correctly wraps server.close in a Promise for proper async cleanup. This ensures graceful shutdown of the HTTP server.


65-67: No changes required to array destructuring—current usage is safe.

The ConnectionManager.createJobs method (at line 120) returns jobs.map(job => job.id). When called with a single-element array [connection], it reliably creates exactly one job and returns a single-element array. Since the connection is validated at line 60 before being passed to createJobs, the destructuring const [jobId] is safe.

The defensive check suggested in the review would only be necessary if empty arrays were possible inputs in this code path, which they are not.

Comment threadpackages/backend/package.json Outdated
Comment threadpackages/backend/src/api.ts
Comment threadpackages/backend/src/api.ts
Comment threadpackages/web/src/features/workerApi/actions.ts
Comment threadpackages/web/src/features/workerApi/actions.ts
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@brendan-kellam
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length \u003e 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(web): Add force resync buttons for repo & connections - #610

Merged
brendan-kellam merged 5 commits into
mainfrom
bkellam/force_resync
Nov 11, 2025
Merged

feat(web): Add force resync buttons for repo & connections#610
brendan-kellam merged 5 commits into
mainfrom
bkellam/force_resync

Conversation

@brendan-kellam

@brendan-kellambrendan-kellam commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

The following adds force re-sync buttons for repo indexing and connection syncing. There are located in the repo details page and connections detail page, respectively.

imageimage

This is accomplished by adding a internal api endpoint in the worker that exposes two endpoints, /api/sync-connection and /api/index-repo. Server actions proxy the requests to the worker endpoint.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added "Trigger sync" buttons for connections and repositories, enabling organization owners to manually trigger synchronization and indexing operations on demand.
    • Integrated loading indicators and success/error notifications to provide real-time feedback during sync operations.
  • Documentation

    • Added documentation for internal worker API utilities.

@github-actions

This comment has been minimized.

@coderabbitai

coderabbitaiBot commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Introduces force resync buttons for connections and repositories via a new backend API server class. The server exposes POST endpoints /api/sync-connection and /api/index-repo that validate input, create indexing jobs through managers, and return job IDs. Frontend components conditionally display sync/index buttons for authorized users with corresponding request handlers and user feedback.

Changes

Cohort / File(s)Summary
API Server Implementation
packages/backend/src/api.ts
New Api class wiring Express app with /metrics and POST endpoints (/api/sync-connection, /api/index-repo); validates input via zod, creates jobs via ConnectionManager/RepoIndexManager, returns jobId; handles errors with 400/404 responses; listens on port 3060
Backend Initialization & Integration
packages/backend/src/index.ts
Added express-async-errors import; created Api instance in startup; wired api.dispose() into cleanup path; removed promClient.dispose() from shutdown
HTTP Server Separation
packages/backend/src/promClient.ts
Removed HTTP metrics server setup (Express app, /metrics route, PORT constant); made registry public; removed dispose method and server lifecycle management
Job Creation API
packages/backend/src/repoIndexManager.ts
Made createJobs method public; added return type Promise<string[]> returning job IDs
Dependencies
packages/backend/package.json
Added express-async-errors ^3.1.1 to devDependencies
Worker API Actions
packages/web/src/features/workerApi/actions.ts
New module exporting syncConnection(connectionId) and indexRepo(repoId); enforces OWNER role; POSTs to http://localhost:3060, validates response with zod, returns jobId
Worker API Documentation
packages/web/src/features/workerApi/README.md
Added README describing utilities to interact with internal worker REST API
Authorization Type Annotation
packages/web/src/withAuthV2.ts
Added explicit return type Promise<T | ServiceError> to withMinimumOrgRole
Repository Index UI
packages/web/src/app/[domain]/repos/[id]/page.tsx
Added role-based retrieval via getCurrentUserRole; conditionally show index button based on OWNER status; inject repoId and isIndexButtonVisible into RepoJobsTable
Repository Jobs Table
packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx
Added repoId and isIndexButtonVisible props; introduced isIndexSubmitting state and onIndexButtonClick handler; replaced single Refresh button with button group including conditional "Trigger sync" LoadingButton; added indexRepo, isServiceError, LoadingButton imports
Connection Sync UI
packages/web/src/app/[domain]/settings/connections/[id]/page.tsx
Added id validation with notFound on NaN; inject connectionId into ConnectionJobsTable; import getConfigSettings
Connection Jobs Table
packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx
Added connectionId prop; introduced isSyncSubmitting state and onSyncButtonClick handler; replaced single Refresh button with button group including conditional "Trigger sync" LoadingButton; added syncConnection, isServiceError, LoadingButton imports
Documentation
CHANGELOG.md
Added entry documenting force resync buttons for connections and repositories

Sequence Diagram

sequenceDiagram
actor User
participant Frontend as Frontend UI
participant ServerAction as Server Action<br/>(withAuthV2)
participant WorkerAPI as Worker API<br/>(Port 3060)
participant Manager as Job Manager
participant DB as Database
User->>Frontend: Click "Trigger sync"<br/>button
Frontend->>Frontend: Set isSubmitting=true
Frontend->>ServerAction: Call syncConnection(id)<br/>or indexRepo(id)
rect rgb(200, 220, 255)
Note over ServerAction: Authorization Check
ServerAction->>ServerAction: Verify OWNER role
alt Role valid
ServerAction->>WorkerAPI: POST /api/sync-connection<br/>or /api/index-repo
else Role invalid
ServerAction-->>Frontend: ServiceError
end
end
rect rgb(200, 235, 200)
Note over WorkerAPI: Validation & Job Creation
WorkerAPI->>WorkerAPI: Validate input (zod)
WorkerAPI->>DB: Fetch connection/repo
alt Resource found
WorkerAPI->>Manager: createJobs()
Manager->>DB: Enqueue job
Manager-->>WorkerAPI: Return jobId[]
WorkerAPI-->>ServerAction: {jobId}
else Not found
WorkerAPI-->>ServerAction: 404 error
end
end
ServerAction->>Frontend: Return jobId
Frontend->>Frontend: Set isSubmitting=false
Frontend->>Frontend: Show success toast
Frontend->>Frontend: router.refresh()
Frontend->>User: Update UI with<br/>new job status
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas requiring attention:
    • Api class endpoint logic and error handling paths (validation, resource lookups, job creation)
    • Role-based authorization integration across frontend server actions
    • State management and async handler patterns in repoJobsTable and connectionJobsTable components (duplication of sync/index patterns)
    • HTTP client calls to localhost:3060 and response validation with zod schemas

Possibly related PRs

Suggested labels

sourcebot-team

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly describes the main change: adding force resync buttons for repositories and connections, which aligns with the primary functionality introduced across the changeset.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@brendan-kellam

Copy link
Copy Markdown
ContributorAuthor

@coderabbitai review

@coderabbitai

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 5

🧹 Nitpick comments (4)
packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (1)

197-215: Consider extracting jobId from success toast message.

The success toast displays the jobId, but this information is included inline in the message string. If you need to make the jobId clickable or copyable in the future, consider storing it separately.

Optional improvement:

 if (!isServiceError(response)) {
const { jobId } = response;
toast({
- description: `✅ Repository sync triggered successfully. Job ID: ${jobId}`,+ description: (+ <div className="flex items-center gap-2">+ <span>✅ Repository sync triggered successfully. Job ID:</span>+ <code className="text-xs">{jobId}</code>+ </div>+ ),
})
packages/web/src/features/workerApi/README.md (1)

1-1: Consider expanding the documentation.

While the current description is accurate, adding examples of the available endpoints (/api/sync-connection, /api/index-repo) and their request/response formats would improve developer experience.

Example enhancement:

# Worker API
This folder contains utilities to interact with the internal worker REST API. See packages/backend/api.ts
## Available Endpoints-`POST /api/sync-connection` - Trigger a connection sync
-`POST /api/index-repo` - Trigger a repository index
## Usage```typescriptimport { syncConnection, indexRepo } from'./actions';
// Sync a connectionconst result =awaitsyncConnection(connectionId);
// Index a repositoryconst result =awaitindexRepo(repoId);

</blockquote></details>
<details>
<summary>packages/web/src/features/workerApi/actions.ts (1)</summary><blockquote>
`11-59`: **Consider extracting common fetch logic.**
Both actions share nearly identical structure (fetch → check response → parse → validate). A helper function could reduce duplication:
```typescript
const callWorkerApi = async <T extends { jobId: string }>(
endpoint: string,
body: Record<string, unknown>,
errorMessage: string
): Promise<T | ServiceError> => {
const response = await fetch(`${WORKER_API_URL}${endpoint}`, {
method: 'POST',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' },
});
if (!response.ok) {
return unexpectedError(errorMessage);
}
const data = await response.json();
const schema = z.object({ jobId: z.string() });
return schema.parse(data) as T;
};
export const syncConnection = async (connectionId: number) => sew(() =>
withAuthV2(({ role }) =>
withMinimumOrgRole(role, OrgRole.OWNER, () =>
callWorkerApi('/api/sync-connection', { connectionId }, 'Failed to sync connection')
)
)
);
packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (1)

195-212: Consider using finally block for loading state cleanup.

The loading state reset should be in a finally block to ensure it's always executed, even if an unexpected error occurs:

 const onSyncButtonClick = React.useCallback(async () => {
setIsSyncSubmitting(true);
- const response = await syncConnection(connectionId);-- if (!isServiceError(response)) {- const { jobId } = response;- toast({- description: `✅ Connection synced successfully. Job ID: ${jobId}`,- })- router.refresh();- } else {- toast({- description: `❌ Failed to sync connection. ${response.message}`,- });+ try {+ const response = await syncConnection(connectionId);++ if (!isServiceError(response)) {+ const { jobId } = response;+ toast({+ description: `✅ Connection synced successfully. Job ID: ${jobId}`,+ })+ router.refresh();+ } else {+ toast({+ description: `❌ Failed to sync connection. ${response.message}`,+ });+ }+ } finally {+ setIsSyncSubmitting(false);
}
-- setIsSyncSubmitting(false);
}, [connectionId, router, toast]);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2dfafda and 5d6f0bf.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (13)
  • CHANGELOG.md (1 hunks)
  • packages/backend/package.json (1 hunks)
  • packages/backend/src/api.ts (1 hunks)
  • packages/backend/src/index.ts (3 hunks)
  • packages/backend/src/promClient.ts (1 hunks)
  • packages/backend/src/repoIndexManager.ts (2 hunks)
  • packages/web/src/app/[domain]/repos/[id]/page.tsx (4 hunks)
  • packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (5 hunks)
  • packages/web/src/app/[domain]/settings/connections/[id]/page.tsx (3 hunks)
  • packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (3 hunks)
  • packages/web/src/features/workerApi/README.md (1 hunks)
  • packages/web/src/features/workerApi/actions.ts (1 hunks)
  • packages/web/src/withAuthV2.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*

📄 CodeRabbit inference engine (.cursor/rules/style.mdc)

Filenames should always be camelCase. Exception: if there are filenames in the same directory with a format other than camelCase, use that format to keep things consistent.

Files:

  • packages/web/src/features/workerApi/README.md
  • CHANGELOG.md
  • packages/web/src/app/[domain]/repos/[id]/page.tsx
  • packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx
  • packages/backend/src/index.ts
  • packages/web/src/withAuthV2.ts
  • packages/backend/src/repoIndexManager.ts
  • packages/backend/src/api.ts
  • packages/web/src/features/workerApi/actions.ts
  • packages/backend/package.json
  • packages/backend/src/promClient.ts
  • packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx
  • packages/web/src/app/[domain]/settings/connections/[id]/page.tsx
🔇 Additional comments (17)
CHANGELOG.md (1)

14-16: LGTM!

The changelog entry correctly documents the new force resync feature and follows the established format.

packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (2)

182-190: LGTM!

The component signature correctly extends the props with repoId and isIndexButtonVisible for conditional button rendering.


281-305: LGTM!

The button group layout and conditional rendering logic are well-structured. The LoadingButton properly shows loading state during async operations.

packages/web/src/app/[domain]/repos/[id]/page.tsx (2)

55-58: LGTM!

The user role retrieval and error handling are correctly implemented. This enables role-based access control for the index button visibility.


181-186: LGTM!

The role-based visibility check (userRole === OrgRole.OWNER) correctly restricts the index button to owners only. This aligns with security best practices for sensitive operations.

packages/backend/src/index.ts (3)

5-5: LGTM!

The import of express-async-errors for side effects is correct. This package automatically wraps Express async handlers to catch rejected promises.


77-82: LGTM!

The Api instance is correctly instantiated with all required dependencies (promClient, prisma, connectionManager, repoIndexManager).


111-111: LGTM!

The Api instance is properly disposed during cleanup, ensuring graceful shutdown of the HTTP server and any associated resources.

packages/backend/src/repoIndexManager.ts (1)

195-226: LGTM!

The method visibility change to public and the addition of the return value (jobs.map(job => job.id)) correctly enable external callers to trigger indexing jobs and receive the created job IDs. This is necessary for the new API endpoints to return job IDs to clients.

packages/web/src/app/[domain]/settings/connections/[id]/page.tsx (2)

28-31: LGTM!

The input validation correctly handles invalid connection IDs by returning notFound() when the parsed ID is NaN. This prevents runtime errors from invalid route parameters.


178-181: LGTM!

The connectionId prop is correctly passed to ConnectionJobsTable, enabling the sync functionality. This change aligns with the corresponding updates to the table component.

packages/web/src/withAuthV2.ts (1)

180-184: LGTM! Explicit return type improves type safety.

The addition of an explicit return type Promise<T | ServiceError> enhances type safety and makes the function signature clearer. This aligns well with the worker API actions that rely on this typing.

packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (1)

264-286: LGTM! Well-structured UI controls.

The button group provides clear actions with appropriate visual feedback. The use of LoadingButton for the sync action ensures good UX during async operations.

packages/backend/src/promClient.ts (1)

3-3: LGTM! Good separation of concerns.

Making registry public enables the Api class to expose metrics via HTTP while keeping metric collection logic in PromClient. This refactor properly separates HTTP server concerns from metrics collection.

packages/backend/src/api.ts (3)

91-92: Verify array destructuring safety.

Same concern as in syncConnection: the destructuring assumes at least one job ID is returned. Verify that RepoIndexManager.createJobs always returns at least one element, or add validation as suggested above.


95-102: LGTM! Proper graceful shutdown.

The dispose method correctly wraps server.close in a Promise for proper async cleanup. This ensures graceful shutdown of the HTTP server.


65-67: No changes required to array destructuring—current usage is safe.

The ConnectionManager.createJobs method (at line 120) returns jobs.map(job => job.id). When called with a single-element array [connection], it reliably creates exactly one job and returns a single-element array. Since the connection is validated at line 60 before being passed to createJobs, the destructuring const [jobId] is safe.

The defensive check suggested in the review would only be necessary if empty arrays were possible inputs in this code path, which they are not.

Comment threadpackages/backend/package.json Outdated
Comment threadpackages/backend/src/api.ts
Comment threadpackages/backend/src/api.ts
Comment threadpackages/web/src/features/workerApi/actions.ts
Comment threadpackages/web/src/features/workerApi/actions.ts
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@brendan-kellam
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(web): Add force resync buttons for repo & connections - #610

Merged
brendan-kellam merged 5 commits into
mainfrom
bkellam/force_resync
Nov 11, 2025
Merged

feat(web): Add force resync buttons for repo & connections#610
brendan-kellam merged 5 commits into
mainfrom
bkellam/force_resync

Conversation

@brendan-kellam

@brendan-kellambrendan-kellam commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

The following adds force re-sync buttons for repo indexing and connection syncing. There are located in the repo details page and connections detail page, respectively.

imageimage

This is accomplished by adding a internal api endpoint in the worker that exposes two endpoints, /api/sync-connection and /api/index-repo. Server actions proxy the requests to the worker endpoint.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added "Trigger sync" buttons for connections and repositories, enabling organization owners to manually trigger synchronization and indexing operations on demand.
    • Integrated loading indicators and success/error notifications to provide real-time feedback during sync operations.
  • Documentation

    • Added documentation for internal worker API utilities.

@github-actions

This comment has been minimized.

@coderabbitai

coderabbitaiBot commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Introduces force resync buttons for connections and repositories via a new backend API server class. The server exposes POST endpoints /api/sync-connection and /api/index-repo that validate input, create indexing jobs through managers, and return job IDs. Frontend components conditionally display sync/index buttons for authorized users with corresponding request handlers and user feedback.

Changes

Cohort / File(s)Summary
API Server Implementation
packages/backend/src/api.ts
New Api class wiring Express app with /metrics and POST endpoints (/api/sync-connection, /api/index-repo); validates input via zod, creates jobs via ConnectionManager/RepoIndexManager, returns jobId; handles errors with 400/404 responses; listens on port 3060
Backend Initialization & Integration
packages/backend/src/index.ts
Added express-async-errors import; created Api instance in startup; wired api.dispose() into cleanup path; removed promClient.dispose() from shutdown
HTTP Server Separation
packages/backend/src/promClient.ts
Removed HTTP metrics server setup (Express app, /metrics route, PORT constant); made registry public; removed dispose method and server lifecycle management
Job Creation API
packages/backend/src/repoIndexManager.ts
Made createJobs method public; added return type Promise<string[]> returning job IDs
Dependencies
packages/backend/package.json
Added express-async-errors ^3.1.1 to devDependencies
Worker API Actions
packages/web/src/features/workerApi/actions.ts
New module exporting syncConnection(connectionId) and indexRepo(repoId); enforces OWNER role; POSTs to http://localhost:3060, validates response with zod, returns jobId
Worker API Documentation
packages/web/src/features/workerApi/README.md
Added README describing utilities to interact with internal worker REST API
Authorization Type Annotation
packages/web/src/withAuthV2.ts
Added explicit return type Promise<T | ServiceError> to withMinimumOrgRole
Repository Index UI
packages/web/src/app/[domain]/repos/[id]/page.tsx
Added role-based retrieval via getCurrentUserRole; conditionally show index button based on OWNER status; inject repoId and isIndexButtonVisible into RepoJobsTable
Repository Jobs Table
packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx
Added repoId and isIndexButtonVisible props; introduced isIndexSubmitting state and onIndexButtonClick handler; replaced single Refresh button with button group including conditional "Trigger sync" LoadingButton; added indexRepo, isServiceError, LoadingButton imports
Connection Sync UI
packages/web/src/app/[domain]/settings/connections/[id]/page.tsx
Added id validation with notFound on NaN; inject connectionId into ConnectionJobsTable; import getConfigSettings
Connection Jobs Table
packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx
Added connectionId prop; introduced isSyncSubmitting state and onSyncButtonClick handler; replaced single Refresh button with button group including conditional "Trigger sync" LoadingButton; added syncConnection, isServiceError, LoadingButton imports
Documentation
CHANGELOG.md
Added entry documenting force resync buttons for connections and repositories

Sequence Diagram

sequenceDiagram
actor User
participant Frontend as Frontend UI
participant ServerAction as Server Action<br/>(withAuthV2)
participant WorkerAPI as Worker API<br/>(Port 3060)
participant Manager as Job Manager
participant DB as Database
User->>Frontend: Click "Trigger sync"<br/>button
Frontend->>Frontend: Set isSubmitting=true
Frontend->>ServerAction: Call syncConnection(id)<br/>or indexRepo(id)
rect rgb(200, 220, 255)
Note over ServerAction: Authorization Check
ServerAction->>ServerAction: Verify OWNER role
alt Role valid
ServerAction->>WorkerAPI: POST /api/sync-connection<br/>or /api/index-repo
else Role invalid
ServerAction-->>Frontend: ServiceError
end
end
rect rgb(200, 235, 200)
Note over WorkerAPI: Validation & Job Creation
WorkerAPI->>WorkerAPI: Validate input (zod)
WorkerAPI->>DB: Fetch connection/repo
alt Resource found
WorkerAPI->>Manager: createJobs()
Manager->>DB: Enqueue job
Manager-->>WorkerAPI: Return jobId[]
WorkerAPI-->>ServerAction: {jobId}
else Not found
WorkerAPI-->>ServerAction: 404 error
end
end
ServerAction->>Frontend: Return jobId
Frontend->>Frontend: Set isSubmitting=false
Frontend->>Frontend: Show success toast
Frontend->>Frontend: router.refresh()
Frontend->>User: Update UI with<br/>new job status
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas requiring attention:
    • Api class endpoint logic and error handling paths (validation, resource lookups, job creation)
    • Role-based authorization integration across frontend server actions
    • State management and async handler patterns in repoJobsTable and connectionJobsTable components (duplication of sync/index patterns)
    • HTTP client calls to localhost:3060 and response validation with zod schemas

Possibly related PRs

Suggested labels

sourcebot-team

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly describes the main change: adding force resync buttons for repositories and connections, which aligns with the primary functionality introduced across the changeset.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@brendan-kellam

Copy link
Copy Markdown
ContributorAuthor

@coderabbitai review

@coderabbitai

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 5

🧹 Nitpick comments (4)
packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (1)

197-215: Consider extracting jobId from success toast message.

The success toast displays the jobId, but this information is included inline in the message string. If you need to make the jobId clickable or copyable in the future, consider storing it separately.

Optional improvement:

 if (!isServiceError(response)) {
const { jobId } = response;
toast({
- description: `✅ Repository sync triggered successfully. Job ID: ${jobId}`,+ description: (+ <div className="flex items-center gap-2">+ <span>✅ Repository sync triggered successfully. Job ID:</span>+ <code className="text-xs">{jobId}</code>+ </div>+ ),
})
packages/web/src/features/workerApi/README.md (1)

1-1: Consider expanding the documentation.

While the current description is accurate, adding examples of the available endpoints (/api/sync-connection, /api/index-repo) and their request/response formats would improve developer experience.

Example enhancement:

# Worker API
This folder contains utilities to interact with the internal worker REST API. See packages/backend/api.ts
## Available Endpoints-`POST /api/sync-connection` - Trigger a connection sync
-`POST /api/index-repo` - Trigger a repository index
## Usage```typescriptimport { syncConnection, indexRepo } from'./actions';
// Sync a connectionconst result =awaitsyncConnection(connectionId);
// Index a repositoryconst result =awaitindexRepo(repoId);

</blockquote></details>
<details>
<summary>packages/web/src/features/workerApi/actions.ts (1)</summary><blockquote>
`11-59`: **Consider extracting common fetch logic.**
Both actions share nearly identical structure (fetch → check response → parse → validate). A helper function could reduce duplication:
```typescript
const callWorkerApi = async <T extends { jobId: string }>(
endpoint: string,
body: Record<string, unknown>,
errorMessage: string
): Promise<T | ServiceError> => {
const response = await fetch(`${WORKER_API_URL}${endpoint}`, {
method: 'POST',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' },
});
if (!response.ok) {
return unexpectedError(errorMessage);
}
const data = await response.json();
const schema = z.object({ jobId: z.string() });
return schema.parse(data) as T;
};
export const syncConnection = async (connectionId: number) => sew(() =>
withAuthV2(({ role }) =>
withMinimumOrgRole(role, OrgRole.OWNER, () =>
callWorkerApi('/api/sync-connection', { connectionId }, 'Failed to sync connection')
)
)
);
packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (1)

195-212: Consider using finally block for loading state cleanup.

The loading state reset should be in a finally block to ensure it's always executed, even if an unexpected error occurs:

 const onSyncButtonClick = React.useCallback(async () => {
setIsSyncSubmitting(true);
- const response = await syncConnection(connectionId);-- if (!isServiceError(response)) {- const { jobId } = response;- toast({- description: `✅ Connection synced successfully. Job ID: ${jobId}`,- })- router.refresh();- } else {- toast({- description: `❌ Failed to sync connection. ${response.message}`,- });+ try {+ const response = await syncConnection(connectionId);++ if (!isServiceError(response)) {+ const { jobId } = response;+ toast({+ description: `✅ Connection synced successfully. Job ID: ${jobId}`,+ })+ router.refresh();+ } else {+ toast({+ description: `❌ Failed to sync connection. ${response.message}`,+ });+ }+ } finally {+ setIsSyncSubmitting(false);
}
-- setIsSyncSubmitting(false);
}, [connectionId, router, toast]);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2dfafda and 5d6f0bf.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (13)
  • CHANGELOG.md (1 hunks)
  • packages/backend/package.json (1 hunks)
  • packages/backend/src/api.ts (1 hunks)
  • packages/backend/src/index.ts (3 hunks)
  • packages/backend/src/promClient.ts (1 hunks)
  • packages/backend/src/repoIndexManager.ts (2 hunks)
  • packages/web/src/app/[domain]/repos/[id]/page.tsx (4 hunks)
  • packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (5 hunks)
  • packages/web/src/app/[domain]/settings/connections/[id]/page.tsx (3 hunks)
  • packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (3 hunks)
  • packages/web/src/features/workerApi/README.md (1 hunks)
  • packages/web/src/features/workerApi/actions.ts (1 hunks)
  • packages/web/src/withAuthV2.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*

📄 CodeRabbit inference engine (.cursor/rules/style.mdc)

Filenames should always be camelCase. Exception: if there are filenames in the same directory with a format other than camelCase, use that format to keep things consistent.

Files:

  • packages/web/src/features/workerApi/README.md
  • CHANGELOG.md
  • packages/web/src/app/[domain]/repos/[id]/page.tsx
  • packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx
  • packages/backend/src/index.ts
  • packages/web/src/withAuthV2.ts
  • packages/backend/src/repoIndexManager.ts
  • packages/backend/src/api.ts
  • packages/web/src/features/workerApi/actions.ts
  • packages/backend/package.json
  • packages/backend/src/promClient.ts
  • packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx
  • packages/web/src/app/[domain]/settings/connections/[id]/page.tsx
🔇 Additional comments (17)
CHANGELOG.md (1)

14-16: LGTM!

The changelog entry correctly documents the new force resync feature and follows the established format.

packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (2)

182-190: LGTM!

The component signature correctly extends the props with repoId and isIndexButtonVisible for conditional button rendering.


281-305: LGTM!

The button group layout and conditional rendering logic are well-structured. The LoadingButton properly shows loading state during async operations.

packages/web/src/app/[domain]/repos/[id]/page.tsx (2)

55-58: LGTM!

The user role retrieval and error handling are correctly implemented. This enables role-based access control for the index button visibility.


181-186: LGTM!

The role-based visibility check (userRole === OrgRole.OWNER) correctly restricts the index button to owners only. This aligns with security best practices for sensitive operations.

packages/backend/src/index.ts (3)

5-5: LGTM!

The import of express-async-errors for side effects is correct. This package automatically wraps Express async handlers to catch rejected promises.


77-82: LGTM!

The Api instance is correctly instantiated with all required dependencies (promClient, prisma, connectionManager, repoIndexManager).


111-111: LGTM!

The Api instance is properly disposed during cleanup, ensuring graceful shutdown of the HTTP server and any associated resources.

packages/backend/src/repoIndexManager.ts (1)

195-226: LGTM!

The method visibility change to public and the addition of the return value (jobs.map(job => job.id)) correctly enable external callers to trigger indexing jobs and receive the created job IDs. This is necessary for the new API endpoints to return job IDs to clients.

packages/web/src/app/[domain]/settings/connections/[id]/page.tsx (2)

28-31: LGTM!

The input validation correctly handles invalid connection IDs by returning notFound() when the parsed ID is NaN. This prevents runtime errors from invalid route parameters.


178-181: LGTM!

The connectionId prop is correctly passed to ConnectionJobsTable, enabling the sync functionality. This change aligns with the corresponding updates to the table component.

packages/web/src/withAuthV2.ts (1)

180-184: LGTM! Explicit return type improves type safety.

The addition of an explicit return type Promise<T | ServiceError> enhances type safety and makes the function signature clearer. This aligns well with the worker API actions that rely on this typing.

packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (1)

264-286: LGTM! Well-structured UI controls.

The button group provides clear actions with appropriate visual feedback. The use of LoadingButton for the sync action ensures good UX during async operations.

packages/backend/src/promClient.ts (1)

3-3: LGTM! Good separation of concerns.

Making registry public enables the Api class to expose metrics via HTTP while keeping metric collection logic in PromClient. This refactor properly separates HTTP server concerns from metrics collection.

packages/backend/src/api.ts (3)

91-92: Verify array destructuring safety.

Same concern as in syncConnection: the destructuring assumes at least one job ID is returned. Verify that RepoIndexManager.createJobs always returns at least one element, or add validation as suggested above.


95-102: LGTM! Proper graceful shutdown.

The dispose method correctly wraps server.close in a Promise for proper async cleanup. This ensures graceful shutdown of the HTTP server.


65-67: No changes required to array destructuring—current usage is safe.

The ConnectionManager.createJobs method (at line 120) returns jobs.map(job => job.id). When called with a single-element array [connection], it reliably creates exactly one job and returns a single-element array. Since the connection is validated at line 60 before being passed to createJobs, the destructuring const [jobId] is safe.

The defensive check suggested in the review would only be necessary if empty arrays were possible inputs in this code path, which they are not.

Comment threadpackages/backend/package.json Outdated
Comment threadpackages/backend/src/api.ts
Comment threadpackages/backend/src/api.ts
Comment threadpackages/web/src/features/workerApi/actions.ts
Comment threadpackages/web/src/features/workerApi/actions.ts
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@brendan-kellam
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(web): Add force resync buttons for repo & connections - #610

Merged
brendan-kellam merged 5 commits into
mainfrom
bkellam/force_resync
Nov 11, 2025
Merged

feat(web): Add force resync buttons for repo & connections#610
brendan-kellam merged 5 commits into
mainfrom
bkellam/force_resync

Conversation

@brendan-kellam

@brendan-kellambrendan-kellam commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

The following adds force re-sync buttons for repo indexing and connection syncing. There are located in the repo details page and connections detail page, respectively.

imageimage

This is accomplished by adding a internal api endpoint in the worker that exposes two endpoints, /api/sync-connection and /api/index-repo. Server actions proxy the requests to the worker endpoint.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added "Trigger sync" buttons for connections and repositories, enabling organization owners to manually trigger synchronization and indexing operations on demand.
    • Integrated loading indicators and success/error notifications to provide real-time feedback during sync operations.
  • Documentation

    • Added documentation for internal worker API utilities.

@github-actions

This comment has been minimized.

@coderabbitai

coderabbitaiBot commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Introduces force resync buttons for connections and repositories via a new backend API server class. The server exposes POST endpoints /api/sync-connection and /api/index-repo that validate input, create indexing jobs through managers, and return job IDs. Frontend components conditionally display sync/index buttons for authorized users with corresponding request handlers and user feedback.

Changes

Cohort / File(s)Summary
API Server Implementation
packages/backend/src/api.ts
New Api class wiring Express app with /metrics and POST endpoints (/api/sync-connection, /api/index-repo); validates input via zod, creates jobs via ConnectionManager/RepoIndexManager, returns jobId; handles errors with 400/404 responses; listens on port 3060
Backend Initialization & Integration
packages/backend/src/index.ts
Added express-async-errors import; created Api instance in startup; wired api.dispose() into cleanup path; removed promClient.dispose() from shutdown
HTTP Server Separation
packages/backend/src/promClient.ts
Removed HTTP metrics server setup (Express app, /metrics route, PORT constant); made registry public; removed dispose method and server lifecycle management
Job Creation API
packages/backend/src/repoIndexManager.ts
Made createJobs method public; added return type Promise<string[]> returning job IDs
Dependencies
packages/backend/package.json
Added express-async-errors ^3.1.1 to devDependencies
Worker API Actions
packages/web/src/features/workerApi/actions.ts
New module exporting syncConnection(connectionId) and indexRepo(repoId); enforces OWNER role; POSTs to http://localhost:3060, validates response with zod, returns jobId
Worker API Documentation
packages/web/src/features/workerApi/README.md
Added README describing utilities to interact with internal worker REST API
Authorization Type Annotation
packages/web/src/withAuthV2.ts
Added explicit return type Promise<T | ServiceError> to withMinimumOrgRole
Repository Index UI
packages/web/src/app/[domain]/repos/[id]/page.tsx
Added role-based retrieval via getCurrentUserRole; conditionally show index button based on OWNER status; inject repoId and isIndexButtonVisible into RepoJobsTable
Repository Jobs Table
packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx
Added repoId and isIndexButtonVisible props; introduced isIndexSubmitting state and onIndexButtonClick handler; replaced single Refresh button with button group including conditional "Trigger sync" LoadingButton; added indexRepo, isServiceError, LoadingButton imports
Connection Sync UI
packages/web/src/app/[domain]/settings/connections/[id]/page.tsx
Added id validation with notFound on NaN; inject connectionId into ConnectionJobsTable; import getConfigSettings
Connection Jobs Table
packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx
Added connectionId prop; introduced isSyncSubmitting state and onSyncButtonClick handler; replaced single Refresh button with button group including conditional "Trigger sync" LoadingButton; added syncConnection, isServiceError, LoadingButton imports
Documentation
CHANGELOG.md
Added entry documenting force resync buttons for connections and repositories

Sequence Diagram

sequenceDiagram
actor User
participant Frontend as Frontend UI
participant ServerAction as Server Action<br/>(withAuthV2)
participant WorkerAPI as Worker API<br/>(Port 3060)
participant Manager as Job Manager
participant DB as Database
User->>Frontend: Click "Trigger sync"<br/>button
Frontend->>Frontend: Set isSubmitting=true
Frontend->>ServerAction: Call syncConnection(id)<br/>or indexRepo(id)
rect rgb(200, 220, 255)
Note over ServerAction: Authorization Check
ServerAction->>ServerAction: Verify OWNER role
alt Role valid
ServerAction->>WorkerAPI: POST /api/sync-connection<br/>or /api/index-repo
else Role invalid
ServerAction-->>Frontend: ServiceError
end
end
rect rgb(200, 235, 200)
Note over WorkerAPI: Validation & Job Creation
WorkerAPI->>WorkerAPI: Validate input (zod)
WorkerAPI->>DB: Fetch connection/repo
alt Resource found
WorkerAPI->>Manager: createJobs()
Manager->>DB: Enqueue job
Manager-->>WorkerAPI: Return jobId[]
WorkerAPI-->>ServerAction: {jobId}
else Not found
WorkerAPI-->>ServerAction: 404 error
end
end
ServerAction->>Frontend: Return jobId
Frontend->>Frontend: Set isSubmitting=false
Frontend->>Frontend: Show success toast
Frontend->>Frontend: router.refresh()
Frontend->>User: Update UI with<br/>new job status
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas requiring attention:
    • Api class endpoint logic and error handling paths (validation, resource lookups, job creation)
    • Role-based authorization integration across frontend server actions
    • State management and async handler patterns in repoJobsTable and connectionJobsTable components (duplication of sync/index patterns)
    • HTTP client calls to localhost:3060 and response validation with zod schemas

Possibly related PRs

Suggested labels

sourcebot-team

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly describes the main change: adding force resync buttons for repositories and connections, which aligns with the primary functionality introduced across the changeset.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@brendan-kellam

Copy link
Copy Markdown
ContributorAuthor

@coderabbitai review

@coderabbitai

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 5

🧹 Nitpick comments (4)
packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (1)

197-215: Consider extracting jobId from success toast message.

The success toast displays the jobId, but this information is included inline in the message string. If you need to make the jobId clickable or copyable in the future, consider storing it separately.

Optional improvement:

 if (!isServiceError(response)) {
const { jobId } = response;
toast({
- description: `✅ Repository sync triggered successfully. Job ID: ${jobId}`,+ description: (+ <div className="flex items-center gap-2">+ <span>✅ Repository sync triggered successfully. Job ID:</span>+ <code className="text-xs">{jobId}</code>+ </div>+ ),
})
packages/web/src/features/workerApi/README.md (1)

1-1: Consider expanding the documentation.

While the current description is accurate, adding examples of the available endpoints (/api/sync-connection, /api/index-repo) and their request/response formats would improve developer experience.

Example enhancement:

# Worker API
This folder contains utilities to interact with the internal worker REST API. See packages/backend/api.ts
## Available Endpoints-`POST /api/sync-connection` - Trigger a connection sync
-`POST /api/index-repo` - Trigger a repository index
## Usage```typescriptimport { syncConnection, indexRepo } from'./actions';
// Sync a connectionconst result =awaitsyncConnection(connectionId);
// Index a repositoryconst result =awaitindexRepo(repoId);

</blockquote></details>
<details>
<summary>packages/web/src/features/workerApi/actions.ts (1)</summary><blockquote>
`11-59`: **Consider extracting common fetch logic.**
Both actions share nearly identical structure (fetch → check response → parse → validate). A helper function could reduce duplication:
```typescript
const callWorkerApi = async <T extends { jobId: string }>(
endpoint: string,
body: Record<string, unknown>,
errorMessage: string
): Promise<T | ServiceError> => {
const response = await fetch(`${WORKER_API_URL}${endpoint}`, {
method: 'POST',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' },
});
if (!response.ok) {
return unexpectedError(errorMessage);
}
const data = await response.json();
const schema = z.object({ jobId: z.string() });
return schema.parse(data) as T;
};
export const syncConnection = async (connectionId: number) => sew(() =>
withAuthV2(({ role }) =>
withMinimumOrgRole(role, OrgRole.OWNER, () =>
callWorkerApi('/api/sync-connection', { connectionId }, 'Failed to sync connection')
)
)
);
packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (1)

195-212: Consider using finally block for loading state cleanup.

The loading state reset should be in a finally block to ensure it's always executed, even if an unexpected error occurs:

 const onSyncButtonClick = React.useCallback(async () => {
setIsSyncSubmitting(true);
- const response = await syncConnection(connectionId);-- if (!isServiceError(response)) {- const { jobId } = response;- toast({- description: `✅ Connection synced successfully. Job ID: ${jobId}`,- })- router.refresh();- } else {- toast({- description: `❌ Failed to sync connection. ${response.message}`,- });+ try {+ const response = await syncConnection(connectionId);++ if (!isServiceError(response)) {+ const { jobId } = response;+ toast({+ description: `✅ Connection synced successfully. Job ID: ${jobId}`,+ })+ router.refresh();+ } else {+ toast({+ description: `❌ Failed to sync connection. ${response.message}`,+ });+ }+ } finally {+ setIsSyncSubmitting(false);
}
-- setIsSyncSubmitting(false);
}, [connectionId, router, toast]);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2dfafda and 5d6f0bf.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (13)
  • CHANGELOG.md (1 hunks)
  • packages/backend/package.json (1 hunks)
  • packages/backend/src/api.ts (1 hunks)
  • packages/backend/src/index.ts (3 hunks)
  • packages/backend/src/promClient.ts (1 hunks)
  • packages/backend/src/repoIndexManager.ts (2 hunks)
  • packages/web/src/app/[domain]/repos/[id]/page.tsx (4 hunks)
  • packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (5 hunks)
  • packages/web/src/app/[domain]/settings/connections/[id]/page.tsx (3 hunks)
  • packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (3 hunks)
  • packages/web/src/features/workerApi/README.md (1 hunks)
  • packages/web/src/features/workerApi/actions.ts (1 hunks)
  • packages/web/src/withAuthV2.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*

📄 CodeRabbit inference engine (.cursor/rules/style.mdc)

Filenames should always be camelCase. Exception: if there are filenames in the same directory with a format other than camelCase, use that format to keep things consistent.

Files:

  • packages/web/src/features/workerApi/README.md
  • CHANGELOG.md
  • packages/web/src/app/[domain]/repos/[id]/page.tsx
  • packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx
  • packages/backend/src/index.ts
  • packages/web/src/withAuthV2.ts
  • packages/backend/src/repoIndexManager.ts
  • packages/backend/src/api.ts
  • packages/web/src/features/workerApi/actions.ts
  • packages/backend/package.json
  • packages/backend/src/promClient.ts
  • packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx
  • packages/web/src/app/[domain]/settings/connections/[id]/page.tsx
🔇 Additional comments (17)
CHANGELOG.md (1)

14-16: LGTM!

The changelog entry correctly documents the new force resync feature and follows the established format.

packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (2)

182-190: LGTM!

The component signature correctly extends the props with repoId and isIndexButtonVisible for conditional button rendering.


281-305: LGTM!

The button group layout and conditional rendering logic are well-structured. The LoadingButton properly shows loading state during async operations.

packages/web/src/app/[domain]/repos/[id]/page.tsx (2)

55-58: LGTM!

The user role retrieval and error handling are correctly implemented. This enables role-based access control for the index button visibility.


181-186: LGTM!

The role-based visibility check (userRole === OrgRole.OWNER) correctly restricts the index button to owners only. This aligns with security best practices for sensitive operations.

packages/backend/src/index.ts (3)

5-5: LGTM!

The import of express-async-errors for side effects is correct. This package automatically wraps Express async handlers to catch rejected promises.


77-82: LGTM!

The Api instance is correctly instantiated with all required dependencies (promClient, prisma, connectionManager, repoIndexManager).


111-111: LGTM!

The Api instance is properly disposed during cleanup, ensuring graceful shutdown of the HTTP server and any associated resources.

packages/backend/src/repoIndexManager.ts (1)

195-226: LGTM!

The method visibility change to public and the addition of the return value (jobs.map(job => job.id)) correctly enable external callers to trigger indexing jobs and receive the created job IDs. This is necessary for the new API endpoints to return job IDs to clients.

packages/web/src/app/[domain]/settings/connections/[id]/page.tsx (2)

28-31: LGTM!

The input validation correctly handles invalid connection IDs by returning notFound() when the parsed ID is NaN. This prevents runtime errors from invalid route parameters.


178-181: LGTM!

The connectionId prop is correctly passed to ConnectionJobsTable, enabling the sync functionality. This change aligns with the corresponding updates to the table component.

packages/web/src/withAuthV2.ts (1)

180-184: LGTM! Explicit return type improves type safety.

The addition of an explicit return type Promise<T | ServiceError> enhances type safety and makes the function signature clearer. This aligns well with the worker API actions that rely on this typing.

packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (1)

264-286: LGTM! Well-structured UI controls.

The button group provides clear actions with appropriate visual feedback. The use of LoadingButton for the sync action ensures good UX during async operations.

packages/backend/src/promClient.ts (1)

3-3: LGTM! Good separation of concerns.

Making registry public enables the Api class to expose metrics via HTTP while keeping metric collection logic in PromClient. This refactor properly separates HTTP server concerns from metrics collection.

packages/backend/src/api.ts (3)

91-92: Verify array destructuring safety.

Same concern as in syncConnection: the destructuring assumes at least one job ID is returned. Verify that RepoIndexManager.createJobs always returns at least one element, or add validation as suggested above.


95-102: LGTM! Proper graceful shutdown.

The dispose method correctly wraps server.close in a Promise for proper async cleanup. This ensures graceful shutdown of the HTTP server.


65-67: No changes required to array destructuring—current usage is safe.

The ConnectionManager.createJobs method (at line 120) returns jobs.map(job => job.id). When called with a single-element array [connection], it reliably creates exactly one job and returns a single-element array. Since the connection is validated at line 60 before being passed to createJobs, the destructuring const [jobId] is safe.

The defensive check suggested in the review would only be necessary if empty arrays were possible inputs in this code path, which they are not.

Comment threadpackages/backend/package.json Outdated
Comment threadpackages/backend/src/api.ts
Comment threadpackages/backend/src/api.ts
Comment threadpackages/web/src/features/workerApi/actions.ts
Comment threadpackages/web/src/features/workerApi/actions.ts
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@brendan-kellam
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(web): Add force resync buttons for repo & connections - #610

Merged
brendan-kellam merged 5 commits into
mainfrom
bkellam/force_resync
Nov 11, 2025
Merged

feat(web): Add force resync buttons for repo & connections#610
brendan-kellam merged 5 commits into
mainfrom
bkellam/force_resync

Conversation

@brendan-kellam

@brendan-kellambrendan-kellam commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

The following adds force re-sync buttons for repo indexing and connection syncing. There are located in the repo details page and connections detail page, respectively.

imageimage

This is accomplished by adding a internal api endpoint in the worker that exposes two endpoints, /api/sync-connection and /api/index-repo. Server actions proxy the requests to the worker endpoint.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added "Trigger sync" buttons for connections and repositories, enabling organization owners to manually trigger synchronization and indexing operations on demand.
    • Integrated loading indicators and success/error notifications to provide real-time feedback during sync operations.
  • Documentation

    • Added documentation for internal worker API utilities.

@github-actions

This comment has been minimized.

@coderabbitai

coderabbitaiBot commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Introduces force resync buttons for connections and repositories via a new backend API server class. The server exposes POST endpoints /api/sync-connection and /api/index-repo that validate input, create indexing jobs through managers, and return job IDs. Frontend components conditionally display sync/index buttons for authorized users with corresponding request handlers and user feedback.

Changes

Cohort / File(s)Summary
API Server Implementation
packages/backend/src/api.ts
New Api class wiring Express app with /metrics and POST endpoints (/api/sync-connection, /api/index-repo); validates input via zod, creates jobs via ConnectionManager/RepoIndexManager, returns jobId; handles errors with 400/404 responses; listens on port 3060
Backend Initialization & Integration
packages/backend/src/index.ts
Added express-async-errors import; created Api instance in startup; wired api.dispose() into cleanup path; removed promClient.dispose() from shutdown
HTTP Server Separation
packages/backend/src/promClient.ts
Removed HTTP metrics server setup (Express app, /metrics route, PORT constant); made registry public; removed dispose method and server lifecycle management
Job Creation API
packages/backend/src/repoIndexManager.ts
Made createJobs method public; added return type Promise<string[]> returning job IDs
Dependencies
packages/backend/package.json
Added express-async-errors ^3.1.1 to devDependencies
Worker API Actions
packages/web/src/features/workerApi/actions.ts
New module exporting syncConnection(connectionId) and indexRepo(repoId); enforces OWNER role; POSTs to http://localhost:3060, validates response with zod, returns jobId
Worker API Documentation
packages/web/src/features/workerApi/README.md
Added README describing utilities to interact with internal worker REST API
Authorization Type Annotation
packages/web/src/withAuthV2.ts
Added explicit return type Promise<T | ServiceError> to withMinimumOrgRole
Repository Index UI
packages/web/src/app/[domain]/repos/[id]/page.tsx
Added role-based retrieval via getCurrentUserRole; conditionally show index button based on OWNER status; inject repoId and isIndexButtonVisible into RepoJobsTable
Repository Jobs Table
packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx
Added repoId and isIndexButtonVisible props; introduced isIndexSubmitting state and onIndexButtonClick handler; replaced single Refresh button with button group including conditional "Trigger sync" LoadingButton; added indexRepo, isServiceError, LoadingButton imports
Connection Sync UI
packages/web/src/app/[domain]/settings/connections/[id]/page.tsx
Added id validation with notFound on NaN; inject connectionId into ConnectionJobsTable; import getConfigSettings
Connection Jobs Table
packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx
Added connectionId prop; introduced isSyncSubmitting state and onSyncButtonClick handler; replaced single Refresh button with button group including conditional "Trigger sync" LoadingButton; added syncConnection, isServiceError, LoadingButton imports
Documentation
CHANGELOG.md
Added entry documenting force resync buttons for connections and repositories

Sequence Diagram

sequenceDiagram
actor User
participant Frontend as Frontend UI
participant ServerAction as Server Action<br/>(withAuthV2)
participant WorkerAPI as Worker API<br/>(Port 3060)
participant Manager as Job Manager
participant DB as Database
User->>Frontend: Click "Trigger sync"<br/>button
Frontend->>Frontend: Set isSubmitting=true
Frontend->>ServerAction: Call syncConnection(id)<br/>or indexRepo(id)
rect rgb(200, 220, 255)
Note over ServerAction: Authorization Check
ServerAction->>ServerAction: Verify OWNER role
alt Role valid
ServerAction->>WorkerAPI: POST /api/sync-connection<br/>or /api/index-repo
else Role invalid
ServerAction-->>Frontend: ServiceError
end
end
rect rgb(200, 235, 200)
Note over WorkerAPI: Validation & Job Creation
WorkerAPI->>WorkerAPI: Validate input (zod)
WorkerAPI->>DB: Fetch connection/repo
alt Resource found
WorkerAPI->>Manager: createJobs()
Manager->>DB: Enqueue job
Manager-->>WorkerAPI: Return jobId[]
WorkerAPI-->>ServerAction: {jobId}
else Not found
WorkerAPI-->>ServerAction: 404 error
end
end
ServerAction->>Frontend: Return jobId
Frontend->>Frontend: Set isSubmitting=false
Frontend->>Frontend: Show success toast
Frontend->>Frontend: router.refresh()
Frontend->>User: Update UI with<br/>new job status
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas requiring attention:
    • Api class endpoint logic and error handling paths (validation, resource lookups, job creation)
    • Role-based authorization integration across frontend server actions
    • State management and async handler patterns in repoJobsTable and connectionJobsTable components (duplication of sync/index patterns)
    • HTTP client calls to localhost:3060 and response validation with zod schemas

Possibly related PRs

Suggested labels

sourcebot-team

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly describes the main change: adding force resync buttons for repositories and connections, which aligns with the primary functionality introduced across the changeset.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@brendan-kellam

Copy link
Copy Markdown
ContributorAuthor

@coderabbitai review

@coderabbitai

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 5

🧹 Nitpick comments (4)
packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (1)

197-215: Consider extracting jobId from success toast message.

The success toast displays the jobId, but this information is included inline in the message string. If you need to make the jobId clickable or copyable in the future, consider storing it separately.

Optional improvement:

 if (!isServiceError(response)) {
const { jobId } = response;
toast({
- description: `✅ Repository sync triggered successfully. Job ID: ${jobId}`,+ description: (+ <div className="flex items-center gap-2">+ <span>✅ Repository sync triggered successfully. Job ID:</span>+ <code className="text-xs">{jobId}</code>+ </div>+ ),
})
packages/web/src/features/workerApi/README.md (1)

1-1: Consider expanding the documentation.

While the current description is accurate, adding examples of the available endpoints (/api/sync-connection, /api/index-repo) and their request/response formats would improve developer experience.

Example enhancement:

# Worker API
This folder contains utilities to interact with the internal worker REST API. See packages/backend/api.ts
## Available Endpoints-`POST /api/sync-connection` - Trigger a connection sync
-`POST /api/index-repo` - Trigger a repository index
## Usage```typescriptimport { syncConnection, indexRepo } from'./actions';
// Sync a connectionconst result =awaitsyncConnection(connectionId);
// Index a repositoryconst result =awaitindexRepo(repoId);

</blockquote></details>
<details>
<summary>packages/web/src/features/workerApi/actions.ts (1)</summary><blockquote>
`11-59`: **Consider extracting common fetch logic.**
Both actions share nearly identical structure (fetch → check response → parse → validate). A helper function could reduce duplication:
```typescript
const callWorkerApi = async <T extends { jobId: string }>(
endpoint: string,
body: Record<string, unknown>,
errorMessage: string
): Promise<T | ServiceError> => {
const response = await fetch(`${WORKER_API_URL}${endpoint}`, {
method: 'POST',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' },
});
if (!response.ok) {
return unexpectedError(errorMessage);
}
const data = await response.json();
const schema = z.object({ jobId: z.string() });
return schema.parse(data) as T;
};
export const syncConnection = async (connectionId: number) => sew(() =>
withAuthV2(({ role }) =>
withMinimumOrgRole(role, OrgRole.OWNER, () =>
callWorkerApi('/api/sync-connection', { connectionId }, 'Failed to sync connection')
)
)
);
packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (1)

195-212: Consider using finally block for loading state cleanup.

The loading state reset should be in a finally block to ensure it's always executed, even if an unexpected error occurs:

 const onSyncButtonClick = React.useCallback(async () => {
setIsSyncSubmitting(true);
- const response = await syncConnection(connectionId);-- if (!isServiceError(response)) {- const { jobId } = response;- toast({- description: `✅ Connection synced successfully. Job ID: ${jobId}`,- })- router.refresh();- } else {- toast({- description: `❌ Failed to sync connection. ${response.message}`,- });+ try {+ const response = await syncConnection(connectionId);++ if (!isServiceError(response)) {+ const { jobId } = response;+ toast({+ description: `✅ Connection synced successfully. Job ID: ${jobId}`,+ })+ router.refresh();+ } else {+ toast({+ description: `❌ Failed to sync connection. ${response.message}`,+ });+ }+ } finally {+ setIsSyncSubmitting(false);
}
-- setIsSyncSubmitting(false);
}, [connectionId, router, toast]);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2dfafda and 5d6f0bf.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (13)
  • CHANGELOG.md (1 hunks)
  • packages/backend/package.json (1 hunks)
  • packages/backend/src/api.ts (1 hunks)
  • packages/backend/src/index.ts (3 hunks)
  • packages/backend/src/promClient.ts (1 hunks)
  • packages/backend/src/repoIndexManager.ts (2 hunks)
  • packages/web/src/app/[domain]/repos/[id]/page.tsx (4 hunks)
  • packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (5 hunks)
  • packages/web/src/app/[domain]/settings/connections/[id]/page.tsx (3 hunks)
  • packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (3 hunks)
  • packages/web/src/features/workerApi/README.md (1 hunks)
  • packages/web/src/features/workerApi/actions.ts (1 hunks)
  • packages/web/src/withAuthV2.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*

📄 CodeRabbit inference engine (.cursor/rules/style.mdc)

Filenames should always be camelCase. Exception: if there are filenames in the same directory with a format other than camelCase, use that format to keep things consistent.

Files:

  • packages/web/src/features/workerApi/README.md
  • CHANGELOG.md
  • packages/web/src/app/[domain]/repos/[id]/page.tsx
  • packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx
  • packages/backend/src/index.ts
  • packages/web/src/withAuthV2.ts
  • packages/backend/src/repoIndexManager.ts
  • packages/backend/src/api.ts
  • packages/web/src/features/workerApi/actions.ts
  • packages/backend/package.json
  • packages/backend/src/promClient.ts
  • packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx
  • packages/web/src/app/[domain]/settings/connections/[id]/page.tsx
🔇 Additional comments (17)
CHANGELOG.md (1)

14-16: LGTM!

The changelog entry correctly documents the new force resync feature and follows the established format.

packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (2)

182-190: LGTM!

The component signature correctly extends the props with repoId and isIndexButtonVisible for conditional button rendering.


281-305: LGTM!

The button group layout and conditional rendering logic are well-structured. The LoadingButton properly shows loading state during async operations.

packages/web/src/app/[domain]/repos/[id]/page.tsx (2)

55-58: LGTM!

The user role retrieval and error handling are correctly implemented. This enables role-based access control for the index button visibility.


181-186: LGTM!

The role-based visibility check (userRole === OrgRole.OWNER) correctly restricts the index button to owners only. This aligns with security best practices for sensitive operations.

packages/backend/src/index.ts (3)

5-5: LGTM!

The import of express-async-errors for side effects is correct. This package automatically wraps Express async handlers to catch rejected promises.


77-82: LGTM!

The Api instance is correctly instantiated with all required dependencies (promClient, prisma, connectionManager, repoIndexManager).


111-111: LGTM!

The Api instance is properly disposed during cleanup, ensuring graceful shutdown of the HTTP server and any associated resources.

packages/backend/src/repoIndexManager.ts (1)

195-226: LGTM!

The method visibility change to public and the addition of the return value (jobs.map(job => job.id)) correctly enable external callers to trigger indexing jobs and receive the created job IDs. This is necessary for the new API endpoints to return job IDs to clients.

packages/web/src/app/[domain]/settings/connections/[id]/page.tsx (2)

28-31: LGTM!

The input validation correctly handles invalid connection IDs by returning notFound() when the parsed ID is NaN. This prevents runtime errors from invalid route parameters.


178-181: LGTM!

The connectionId prop is correctly passed to ConnectionJobsTable, enabling the sync functionality. This change aligns with the corresponding updates to the table component.

packages/web/src/withAuthV2.ts (1)

180-184: LGTM! Explicit return type improves type safety.

The addition of an explicit return type Promise<T | ServiceError> enhances type safety and makes the function signature clearer. This aligns well with the worker API actions that rely on this typing.

packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (1)

264-286: LGTM! Well-structured UI controls.

The button group provides clear actions with appropriate visual feedback. The use of LoadingButton for the sync action ensures good UX during async operations.

packages/backend/src/promClient.ts (1)

3-3: LGTM! Good separation of concerns.

Making registry public enables the Api class to expose metrics via HTTP while keeping metric collection logic in PromClient. This refactor properly separates HTTP server concerns from metrics collection.

packages/backend/src/api.ts (3)

91-92: Verify array destructuring safety.

Same concern as in syncConnection: the destructuring assumes at least one job ID is returned. Verify that RepoIndexManager.createJobs always returns at least one element, or add validation as suggested above.


95-102: LGTM! Proper graceful shutdown.

The dispose method correctly wraps server.close in a Promise for proper async cleanup. This ensures graceful shutdown of the HTTP server.


65-67: No changes required to array destructuring—current usage is safe.

The ConnectionManager.createJobs method (at line 120) returns jobs.map(job => job.id). When called with a single-element array [connection], it reliably creates exactly one job and returns a single-element array. Since the connection is validated at line 60 before being passed to createJobs, the destructuring const [jobId] is safe.

The defensive check suggested in the review would only be necessary if empty arrays were possible inputs in this code path, which they are not.

Comment threadpackages/backend/package.json Outdated
Comment threadpackages/backend/src/api.ts
Comment threadpackages/backend/src/api.ts
Comment threadpackages/web/src/features/workerApi/actions.ts
Comment threadpackages/web/src/features/workerApi/actions.ts
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@brendan-kellam
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(web): Add force resync buttons for repo & connections - #610

Merged
brendan-kellam merged 5 commits into
mainfrom
bkellam/force_resync
Nov 11, 2025
Merged

feat(web): Add force resync buttons for repo & connections#610
brendan-kellam merged 5 commits into
mainfrom
bkellam/force_resync

Conversation

@brendan-kellam

@brendan-kellambrendan-kellam commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

The following adds force re-sync buttons for repo indexing and connection syncing. There are located in the repo details page and connections detail page, respectively.

imageimage

This is accomplished by adding a internal api endpoint in the worker that exposes two endpoints, /api/sync-connection and /api/index-repo. Server actions proxy the requests to the worker endpoint.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added "Trigger sync" buttons for connections and repositories, enabling organization owners to manually trigger synchronization and indexing operations on demand.
    • Integrated loading indicators and success/error notifications to provide real-time feedback during sync operations.
  • Documentation

    • Added documentation for internal worker API utilities.

@github-actions

This comment has been minimized.

@coderabbitai

coderabbitaiBot commented Nov 11, 2025

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Walkthrough

Introduces force resync buttons for connections and repositories via a new backend API server class. The server exposes POST endpoints /api/sync-connection and /api/index-repo that validate input, create indexing jobs through managers, and return job IDs. Frontend components conditionally display sync/index buttons for authorized users with corresponding request handlers and user feedback.

Changes

Cohort / File(s)Summary
API Server Implementation
packages/backend/src/api.ts
New Api class wiring Express app with /metrics and POST endpoints (/api/sync-connection, /api/index-repo); validates input via zod, creates jobs via ConnectionManager/RepoIndexManager, returns jobId; handles errors with 400/404 responses; listens on port 3060
Backend Initialization & Integration
packages/backend/src/index.ts
Added express-async-errors import; created Api instance in startup; wired api.dispose() into cleanup path; removed promClient.dispose() from shutdown
HTTP Server Separation
packages/backend/src/promClient.ts
Removed HTTP metrics server setup (Express app, /metrics route, PORT constant); made registry public; removed dispose method and server lifecycle management
Job Creation API
packages/backend/src/repoIndexManager.ts
Made createJobs method public; added return type Promise<string[]> returning job IDs
Dependencies
packages/backend/package.json
Added express-async-errors ^3.1.1 to devDependencies
Worker API Actions
packages/web/src/features/workerApi/actions.ts
New module exporting syncConnection(connectionId) and indexRepo(repoId); enforces OWNER role; POSTs to http://localhost:3060, validates response with zod, returns jobId
Worker API Documentation
packages/web/src/features/workerApi/README.md
Added README describing utilities to interact with internal worker REST API
Authorization Type Annotation
packages/web/src/withAuthV2.ts
Added explicit return type Promise<T | ServiceError> to withMinimumOrgRole
Repository Index UI
packages/web/src/app/[domain]/repos/[id]/page.tsx
Added role-based retrieval via getCurrentUserRole; conditionally show index button based on OWNER status; inject repoId and isIndexButtonVisible into RepoJobsTable
Repository Jobs Table
packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx
Added repoId and isIndexButtonVisible props; introduced isIndexSubmitting state and onIndexButtonClick handler; replaced single Refresh button with button group including conditional "Trigger sync" LoadingButton; added indexRepo, isServiceError, LoadingButton imports
Connection Sync UI
packages/web/src/app/[domain]/settings/connections/[id]/page.tsx
Added id validation with notFound on NaN; inject connectionId into ConnectionJobsTable; import getConfigSettings
Connection Jobs Table
packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx
Added connectionId prop; introduced isSyncSubmitting state and onSyncButtonClick handler; replaced single Refresh button with button group including conditional "Trigger sync" LoadingButton; added syncConnection, isServiceError, LoadingButton imports
Documentation
CHANGELOG.md
Added entry documenting force resync buttons for connections and repositories

Sequence Diagram

sequenceDiagram
actor User
participant Frontend as Frontend UI
participant ServerAction as Server Action<br/>(withAuthV2)
participant WorkerAPI as Worker API<br/>(Port 3060)
participant Manager as Job Manager
participant DB as Database
User->>Frontend: Click "Trigger sync"<br/>button
Frontend->>Frontend: Set isSubmitting=true
Frontend->>ServerAction: Call syncConnection(id)<br/>or indexRepo(id)
rect rgb(200, 220, 255)
Note over ServerAction: Authorization Check
ServerAction->>ServerAction: Verify OWNER role
alt Role valid
ServerAction->>WorkerAPI: POST /api/sync-connection<br/>or /api/index-repo
else Role invalid
ServerAction-->>Frontend: ServiceError
end
end
rect rgb(200, 235, 200)
Note over WorkerAPI: Validation & Job Creation
WorkerAPI->>WorkerAPI: Validate input (zod)
WorkerAPI->>DB: Fetch connection/repo
alt Resource found
WorkerAPI->>Manager: createJobs()
Manager->>DB: Enqueue job
Manager-->>WorkerAPI: Return jobId[]
WorkerAPI-->>ServerAction: {jobId}
else Not found
WorkerAPI-->>ServerAction: 404 error
end
end
ServerAction->>Frontend: Return jobId
Frontend->>Frontend: Set isSubmitting=false
Frontend->>Frontend: Show success toast
Frontend->>Frontend: router.refresh()
Frontend->>User: Update UI with<br/>new job status
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas requiring attention:
    • Api class endpoint logic and error handling paths (validation, resource lookups, job creation)
    • Role-based authorization integration across frontend server actions
    • State management and async handler patterns in repoJobsTable and connectionJobsTable components (duplication of sync/index patterns)
    • HTTP client calls to localhost:3060 and response validation with zod schemas

Possibly related PRs

Suggested labels

sourcebot-team

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly describes the main change: adding force resync buttons for repositories and connections, which aligns with the primary functionality introduced across the changeset.

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@brendan-kellam

Copy link
Copy Markdown
ContributorAuthor

@coderabbitai review

@coderabbitai

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitaicoderabbitaiBot left a comment

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.

Actionable comments posted: 5

🧹 Nitpick comments (4)
packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (1)

197-215: Consider extracting jobId from success toast message.

The success toast displays the jobId, but this information is included inline in the message string. If you need to make the jobId clickable or copyable in the future, consider storing it separately.

Optional improvement:

 if (!isServiceError(response)) {
const { jobId } = response;
toast({
- description: `✅ Repository sync triggered successfully. Job ID: ${jobId}`,+ description: (+ <div className="flex items-center gap-2">+ <span>✅ Repository sync triggered successfully. Job ID:</span>+ <code className="text-xs">{jobId}</code>+ </div>+ ),
})
packages/web/src/features/workerApi/README.md (1)

1-1: Consider expanding the documentation.

While the current description is accurate, adding examples of the available endpoints (/api/sync-connection, /api/index-repo) and their request/response formats would improve developer experience.

Example enhancement:

# Worker API
This folder contains utilities to interact with the internal worker REST API. See packages/backend/api.ts
## Available Endpoints-`POST /api/sync-connection` - Trigger a connection sync
-`POST /api/index-repo` - Trigger a repository index
## Usage```typescriptimport { syncConnection, indexRepo } from'./actions';
// Sync a connectionconst result =awaitsyncConnection(connectionId);
// Index a repositoryconst result =awaitindexRepo(repoId);

</blockquote></details>
<details>
<summary>packages/web/src/features/workerApi/actions.ts (1)</summary><blockquote>
`11-59`: **Consider extracting common fetch logic.**
Both actions share nearly identical structure (fetch → check response → parse → validate). A helper function could reduce duplication:
```typescript
const callWorkerApi = async <T extends { jobId: string }>(
endpoint: string,
body: Record<string, unknown>,
errorMessage: string
): Promise<T | ServiceError> => {
const response = await fetch(`${WORKER_API_URL}${endpoint}`, {
method: 'POST',
body: JSON.stringify(body),
headers: { 'Content-Type': 'application/json' },
});
if (!response.ok) {
return unexpectedError(errorMessage);
}
const data = await response.json();
const schema = z.object({ jobId: z.string() });
return schema.parse(data) as T;
};
export const syncConnection = async (connectionId: number) => sew(() =>
withAuthV2(({ role }) =>
withMinimumOrgRole(role, OrgRole.OWNER, () =>
callWorkerApi('/api/sync-connection', { connectionId }, 'Failed to sync connection')
)
)
);
packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (1)

195-212: Consider using finally block for loading state cleanup.

The loading state reset should be in a finally block to ensure it's always executed, even if an unexpected error occurs:

 const onSyncButtonClick = React.useCallback(async () => {
setIsSyncSubmitting(true);
- const response = await syncConnection(connectionId);-- if (!isServiceError(response)) {- const { jobId } = response;- toast({- description: `✅ Connection synced successfully. Job ID: ${jobId}`,- })- router.refresh();- } else {- toast({- description: `❌ Failed to sync connection. ${response.message}`,- });+ try {+ const response = await syncConnection(connectionId);++ if (!isServiceError(response)) {+ const { jobId } = response;+ toast({+ description: `✅ Connection synced successfully. Job ID: ${jobId}`,+ })+ router.refresh();+ } else {+ toast({+ description: `❌ Failed to sync connection. ${response.message}`,+ });+ }+ } finally {+ setIsSyncSubmitting(false);
}
-- setIsSyncSubmitting(false);
}, [connectionId, router, toast]);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2dfafda and 5d6f0bf.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (13)
  • CHANGELOG.md (1 hunks)
  • packages/backend/package.json (1 hunks)
  • packages/backend/src/api.ts (1 hunks)
  • packages/backend/src/index.ts (3 hunks)
  • packages/backend/src/promClient.ts (1 hunks)
  • packages/backend/src/repoIndexManager.ts (2 hunks)
  • packages/web/src/app/[domain]/repos/[id]/page.tsx (4 hunks)
  • packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (5 hunks)
  • packages/web/src/app/[domain]/settings/connections/[id]/page.tsx (3 hunks)
  • packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (3 hunks)
  • packages/web/src/features/workerApi/README.md (1 hunks)
  • packages/web/src/features/workerApi/actions.ts (1 hunks)
  • packages/web/src/withAuthV2.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*

📄 CodeRabbit inference engine (.cursor/rules/style.mdc)

Filenames should always be camelCase. Exception: if there are filenames in the same directory with a format other than camelCase, use that format to keep things consistent.

Files:

  • packages/web/src/features/workerApi/README.md
  • CHANGELOG.md
  • packages/web/src/app/[domain]/repos/[id]/page.tsx
  • packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx
  • packages/backend/src/index.ts
  • packages/web/src/withAuthV2.ts
  • packages/backend/src/repoIndexManager.ts
  • packages/backend/src/api.ts
  • packages/web/src/features/workerApi/actions.ts
  • packages/backend/package.json
  • packages/backend/src/promClient.ts
  • packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx
  • packages/web/src/app/[domain]/settings/connections/[id]/page.tsx
🔇 Additional comments (17)
CHANGELOG.md (1)

14-16: LGTM!

The changelog entry correctly documents the new force resync feature and follows the established format.

packages/web/src/app/[domain]/repos/components/repoJobsTable.tsx (2)

182-190: LGTM!

The component signature correctly extends the props with repoId and isIndexButtonVisible for conditional button rendering.


281-305: LGTM!

The button group layout and conditional rendering logic are well-structured. The LoadingButton properly shows loading state during async operations.

packages/web/src/app/[domain]/repos/[id]/page.tsx (2)

55-58: LGTM!

The user role retrieval and error handling are correctly implemented. This enables role-based access control for the index button visibility.


181-186: LGTM!

The role-based visibility check (userRole === OrgRole.OWNER) correctly restricts the index button to owners only. This aligns with security best practices for sensitive operations.

packages/backend/src/index.ts (3)

5-5: LGTM!

The import of express-async-errors for side effects is correct. This package automatically wraps Express async handlers to catch rejected promises.


77-82: LGTM!

The Api instance is correctly instantiated with all required dependencies (promClient, prisma, connectionManager, repoIndexManager).


111-111: LGTM!

The Api instance is properly disposed during cleanup, ensuring graceful shutdown of the HTTP server and any associated resources.

packages/backend/src/repoIndexManager.ts (1)

195-226: LGTM!

The method visibility change to public and the addition of the return value (jobs.map(job => job.id)) correctly enable external callers to trigger indexing jobs and receive the created job IDs. This is necessary for the new API endpoints to return job IDs to clients.

packages/web/src/app/[domain]/settings/connections/[id]/page.tsx (2)

28-31: LGTM!

The input validation correctly handles invalid connection IDs by returning notFound() when the parsed ID is NaN. This prevents runtime errors from invalid route parameters.


178-181: LGTM!

The connectionId prop is correctly passed to ConnectionJobsTable, enabling the sync functionality. This change aligns with the corresponding updates to the table component.

packages/web/src/withAuthV2.ts (1)

180-184: LGTM! Explicit return type improves type safety.

The addition of an explicit return type Promise<T | ServiceError> enhances type safety and makes the function signature clearer. This aligns well with the worker API actions that rely on this typing.

packages/web/src/app/[domain]/settings/connections/components/connectionJobsTable.tsx (1)

264-286: LGTM! Well-structured UI controls.

The button group provides clear actions with appropriate visual feedback. The use of LoadingButton for the sync action ensures good UX during async operations.

packages/backend/src/promClient.ts (1)

3-3: LGTM! Good separation of concerns.

Making registry public enables the Api class to expose metrics via HTTP while keeping metric collection logic in PromClient. This refactor properly separates HTTP server concerns from metrics collection.

packages/backend/src/api.ts (3)

91-92: Verify array destructuring safety.

Same concern as in syncConnection: the destructuring assumes at least one job ID is returned. Verify that RepoIndexManager.createJobs always returns at least one element, or add validation as suggested above.


95-102: LGTM! Proper graceful shutdown.

The dispose method correctly wraps server.close in a Promise for proper async cleanup. This ensures graceful shutdown of the HTTP server.


65-67: No changes required to array destructuring—current usage is safe.

The ConnectionManager.createJobs method (at line 120) returns jobs.map(job => job.id). When called with a single-element array [connection], it reliably creates exactly one job and returns a single-element array. Since the connection is validated at line 60 before being passed to createJobs, the destructuring const [jobId] is safe.

The defensive check suggested in the review would only be necessary if empty arrays were possible inputs in this code path, which they are not.

Comment threadpackages/backend/package.json Outdated
Comment threadpackages/backend/src/api.ts
Comment threadpackages/backend/src/api.ts
Comment threadpackages/web/src/features/workerApi/actions.ts
Comment threadpackages/web/src/features/workerApi/actions.ts
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@brendan-kellam