Skip to content

refactor: rename 'upstream sync' to 'remote sync' / 'Sync from Remote'#80

Merged
damienriehl merged 2 commits into
mainfrom
fix/rename-upstream-to-remote
Apr 6, 2026
Merged

refactor: rename 'upstream sync' to 'remote sync' / 'Sync from Remote'#80
damienriehl merged 2 commits into
mainfrom
fix/rename-upstream-to-remote

Conversation

@JohnRDOrazio
Copy link
Copy Markdown
Member

@JohnRDOrazio JohnRDOrazio commented Apr 5, 2026

Summary

  • Rename all "upstream sync" terminology to "remote sync" throughout the frontend
  • File renames: upstreamSync.tsremoteSync.ts, useUpstreamSync.tsuseRemoteSync.ts, UpstreamSyncIndicator.tsxRemoteSyncIndicator.tsx
  • API paths: /upstream-sync/remote-sync
  • Type/component names: UpstreamSync*RemoteSync*
  • Notification types: upstream_*remote_*
  • User-facing labels use "Sync from Remote" terminology
  • HTML anchors: #upstream-sync#remote-sync

Closes #79

Dependencies

Test plan

  • TypeScript compiles cleanly
  • Remote sync indicator in editor toolbar works
  • Project settings "Sync from Remote" section renders correctly
  • Notification types route to correct URLs

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Refactor
    • Standardized synchronization terminology throughout the application. Updated references from "upstream" to "remote" in sync status indicators, settings pages, configuration sections, and notification messages for improved consistency and clarity.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 5, 2026

Warning

Rate limit exceeded

@damienriehl has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 5 minutes and 16 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 5 minutes and 16 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 40457252-cb06-45ca-bc2f-0e32b1cf89a9

📥 Commits

Reviewing files that changed from the base of the PR and between 9b7503c and 683707b.

📒 Files selected for processing (10)
  • app/projects/[id]/editor/page.tsx
  • app/projects/[id]/settings/page.tsx
  • app/settings/page.tsx
  • components/editor/RemoteSyncIndicator.tsx
  • components/editor/index.ts
  • components/layout/notification-bell.tsx
  • lib/api/client.ts
  • lib/api/notifications.ts
  • lib/api/remoteSync.ts
  • lib/hooks/useRemoteSync.ts
📝 Walkthrough

Walkthrough

This PR systematically renames "upstream sync" terminology to "remote sync" across the frontend codebase, including component names (UpstreamSyncIndicatorRemoteSyncIndicator), API endpoints (/upstream-sync/remote-sync), exported types, hook names, UI labels, and notification types to reflect a clearer conceptual model for remote Git synchronization.

Changes

Cohort / File(s) Summary
Page Components
app/projects/[id]/editor/page.tsx, app/projects/[id]/settings/page.tsx, app/settings/page.tsx
Replaced UpstreamSyncIndicator with RemoteSyncIndicator, updated hook imports from useUpstreamSync to useRemoteSync, renamed section component UpstreamSyncSection to RemoteSyncSection, and updated all user-facing labels, descriptions, and status messages from "upstream" to "remote" terminology.
Component & Export Updates
components/editor/RemoteSyncIndicator.tsx, components/editor/index.ts
Renamed component UpstreamSyncIndicator to RemoteSyncIndicator with updated props interface, changed API dependency from upstreamSyncApi to remoteSyncApi, updated config types from UpstreamSyncConfig to RemoteSyncConfig, and changed fragment anchors from #upstream-sync to #remote-sync.
API Client & Types
lib/api/remoteSync.ts, lib/api/client.ts, lib/api/notifications.ts
Renamed API export upstreamSyncApi to remoteSyncApi, updated endpoint paths from /upstream-sync to /remote-sync, renamed all exported types (UpstreamSyncStatusRemoteSyncStatus, UpstreamSyncConfig*RemoteSyncConfig*), renamed notification type variants from upstream_* to remote_*.
Hook & State Management
lib/hooks/useRemoteSync.ts
Renamed hook from useUpstreamSync to useRemoteSync, updated associated option/return types (UseUpstreamSyncOptions/UseUpstreamSyncReturnUseRemoteSyncOptions/UseRemoteSyncReturn), replaced API calls and type references throughout, updated error messaging from "upstream sync config" to "remote sync config".
Notification Handling
components/layout/notification-bell.tsx
Updated NotificationType icon/color mappings and navigation targets from upstream_* variants to remote_* variants, changed getTargetUrl switch cases to resolve to /settings#remote-sync anchor instead of /upstream-sync.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

Suggested labels

enhancement, UX

Suggested reviewers

  • damienriehl

Poem

🐰 From upstream to remote, the naming takes flight,
No more fork-like confusion, just clarity bright,
A hop through the codebase, each label refined,
Where "remote" now echoes—a term redesigned. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor: rename 'upstream sync' to 'remote sync' / 'Sync from Remote'' accurately describes the primary change: a comprehensive terminology refactor throughout the frontend.
Linked Issues check ✅ Passed The PR fully addresses all coding objectives from issue #79: component renames (UpstreamSyncIndicator→RemoteSyncIndicator), API client updates, endpoint path changes (/upstream-sync→/remote-sync), UI label updates, and type renames throughout the codebase.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the terminology refactor: component/file renames, API client references, endpoint paths, UI text, notification types, and related identifiers, with no unrelated modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/rename-upstream-to-remote

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.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
lib/api/notifications.ts (1)

12-24: ⚠️ Potential issue | 🟠 Major

Fallbacks prevent crash, but verify backend has migrated notification types.

The type narrowing from upstream_* to remote_* will cause graceful UI degradation if the backend still returns legacy values—the notification bell will show a generic Bell icon and gray color instead of specialized icons/routing. While the app won't crash (lines 179–180 of notification-bell.tsx have fallback icons and colors), specialized notification handling will be lost silently.

Before shipping this change, confirm the backend has completed its migration to only emit remote_* notification types, or add normalization at the API boundary in lib/api/notifications.ts to map any lingering upstream_* values to their remote_* equivalents.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/api/notifications.ts` around lines 12 - 24, The NotificationType union
was tightened to remote_* names which will silently degrade the UI if the
backend still emits legacy upstream_* values; add normalization at the API
boundary in lib/api/notifications.ts by implementing a
mapping/normalizeNotificationType function (or run normalization where
notifications are parsed) that converts any upstream_* strings to their
corresponding remote_* equivalents (e.g., upstream_update_applied ->
remote_update_applied, upstream_update_available -> remote_update_available,
upstream_sync_error -> remote_sync_error) and return values typed as
NotificationType so downstream code (e.g., notification-bell rendering) always
sees the new remote_* names.
lib/hooks/useRemoteSync.ts (2)

115-129: ⚠️ Potential issue | 🔴 Critical

"not_found" job status is not treated as terminal, causing endless polling.

Polling stops only for "complete"/"failed". If the API returns "not_found", interval polling continues indefinitely and isChecking can remain stuck.

Suggested diff
-          if (status.status === "complete" || status.status === "failed") {
+          if (
+            status.status === "complete" ||
+            status.status === "failed" ||
+            status.status === "not_found"
+          ) {
             if (pollTimerRef.current) {
               clearInterval(pollTimerRef.current);
               pollTimerRef.current = null;
             }
             jobIdRef.current = null;
             setIsChecking(false);

             if (status.status === "failed" && status.error) {
               setError(status.error);
+            } else if (status.status === "not_found") {
+              setError("Sync job no longer exists");
             }

             // Refresh data after job completes
-            await fetchData();
+            if (status.status !== "not_found") {
+              await fetchData();
+            }
           }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/hooks/useRemoteSync.ts` around lines 115 - 129, The polling loop
currently only treats status.status === "complete" or "failed" as terminal;
update the check in the block that references status.status, pollTimerRef,
jobIdRef, setIsChecking, setError, and fetchData to also handle the "not_found"
status as terminal: when status.status is "not_found" clear and null out
pollTimerRef.current, set jobIdRef.current = null, setIsChecking(false),
optionally setError with a descriptive message if no error is present, and still
await fetchData() so the UI refreshes and polling stops.

44-93: ⚠️ Potential issue | 🟠 Major

Migrate server-state management to React Query.

config and history are fetched server state and should use useQuery rather than manual useState/useEffect orchestration. The repository standard (established across useSemanticSearch, useProjectAnalytics, useEntityHistory, and others) is to use @tanstack/react-query for server state. The polling logic for job status checks is compatible with React Query's refetchInterval or custom polling within queryFn.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/hooks/useRemoteSync.ts` around lines 44 - 93, Replace the manual
fetchData/useEffect + local useState for config and history with
`@tanstack/react-query` useQuery hooks: create a useQuery for the config (key e.g.
['remoteSync','config', projectId]) that calls
remoteSyncApi.getConfig(projectId, accessToken) and sets enabled via the hook's
enabled option; create a separate useQuery for history (key e.g.
['remoteSync','history', projectId]) that calls
remoteSyncApi.getHistory(projectId, 20, accessToken) and depends on the config
query (enabled only if config exists). Remove the local useState management for
config/history and isLoading for those queries and map their loading/error
states to the query results; for job status polling, useQuery with
refetchInterval or the query's refetch to poll using jobIdRef (or a query keyed
by ['remoteSync','job', jobId]) instead of manual setInterval in pollTimerRef;
keep existing error handling by mapping query.error to the error state and
preserve enabled gating with the query's enabled option.
🧹 Nitpick comments (2)
components/editor/RemoteSyncIndicator.tsx (1)

24-35: Prefer a React Query-backed hook here.

config is server state, but this component still loads it via an imperative useEffect, so it bypasses shared caching/invalidation. Reusing useRemoteSync or a slimmer query hook would keep the toolbar indicator aligned with config/check mutations.

As per coding guidelines "Use React Query (@tanstack/react-query) for server state management".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/editor/RemoteSyncIndicator.tsx` around lines 24 - 35, The
component currently fetches server state imperatively in RemoteSyncIndicator via
a useEffect that calls remoteSyncApi.getConfig and setConfig; replace that
effect with a React Query-backed hook (either the existing useRemoteSync or a
slim useQuery) so the indicator uses shared caching/invalidation. Implement a
query such as useQuery(['remoteSync', projectId], () =>
remoteSyncApi.getConfig(projectId, accessToken), { enabled: !!projectId }) or
call useRemoteSync(projectId, accessToken), and map a 404 to null in the query's
onError or queryFn so setConfig/useQuery data reflects null on 404; remove the
useEffect and local imperative fetch to ensure React Query drives the state.
lib/api/remoteSync.ts (1)

107-170: Plan deployment ordering to avoid a temporary 404 window.

This file hard-switches all calls to /remote-sync; if frontend deploys before the backend rename is live, remote sync flows will fail. Ensure coordinated rollout (or temporary dual-path fallback) during release.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/api/remoteSync.ts` around lines 107 - 170, The client currently
hard-switches all remote-sync endpoints which will break if the frontend deploys
before the backend rename; update the API calls (e.g., saveConfig, deleteConfig,
triggerCheck, getJobStatus, getHistory and the initial get) to implement a
dual-path fallback: first attempt the new /remote-sync path and if that request
returns a 404 (or a specific "not found" response) automatically retry the same
request against the legacy path (e.g., the previous /remoteSync or whatever the
old route is), or alternatively read the base remote-sync path from a runtime
config/feature-flag and use that to choose the URL; ensure the retry preserves
method, body and headers (Authorization) and surface the final response/error to
callers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/projects/`[id]/settings/page.tsx:
- Around line 2453-2462: Keep a temporary alias for the old hash by mapping
"#upstream-sync" to the new section id. In the component that returns the
section with id="remote-sync" (the JSX block in page.tsx), either add a hidden
anchor element with id="upstream-sync" next to the section or add a small
client-side effect (e.g., in a useEffect inside the same component) that checks
window.location.hash and, if it equals "#upstream-sync", calls
history.replaceState or scrolls/updates location.hash to "#remote-sync" so old
deep links continue to land on the same UI until you remove the alias.

In `@lib/hooks/useRemoteSync.ts`:
- Around line 10-15: The hook currently imports remoteSyncApi directly from
"@/lib/api/remoteSync"; update the import so remoteSyncApi is imported from
"@/lib/api/client" instead to follow the API boundary (keep other type imports
if needed from RemoteSync types but route the API object via the centralized
client). Locate the import list in useRemoteSync.ts and replace the
remoteSyncApi import source with the client entrypoint (e.g., import {
remoteSyncApi } from "@/lib/api/client"), then ensure any calls use the same
remoteSyncApi symbol and that error handling remains compatible with ApiError
from the client layer.

---

Outside diff comments:
In `@lib/api/notifications.ts`:
- Around line 12-24: The NotificationType union was tightened to remote_* names
which will silently degrade the UI if the backend still emits legacy upstream_*
values; add normalization at the API boundary in lib/api/notifications.ts by
implementing a mapping/normalizeNotificationType function (or run normalization
where notifications are parsed) that converts any upstream_* strings to their
corresponding remote_* equivalents (e.g., upstream_update_applied ->
remote_update_applied, upstream_update_available -> remote_update_available,
upstream_sync_error -> remote_sync_error) and return values typed as
NotificationType so downstream code (e.g., notification-bell rendering) always
sees the new remote_* names.

In `@lib/hooks/useRemoteSync.ts`:
- Around line 115-129: The polling loop currently only treats status.status ===
"complete" or "failed" as terminal; update the check in the block that
references status.status, pollTimerRef, jobIdRef, setIsChecking, setError, and
fetchData to also handle the "not_found" status as terminal: when status.status
is "not_found" clear and null out pollTimerRef.current, set jobIdRef.current =
null, setIsChecking(false), optionally setError with a descriptive message if no
error is present, and still await fetchData() so the UI refreshes and polling
stops.
- Around line 44-93: Replace the manual fetchData/useEffect + local useState for
config and history with `@tanstack/react-query` useQuery hooks: create a useQuery
for the config (key e.g. ['remoteSync','config', projectId]) that calls
remoteSyncApi.getConfig(projectId, accessToken) and sets enabled via the hook's
enabled option; create a separate useQuery for history (key e.g.
['remoteSync','history', projectId]) that calls
remoteSyncApi.getHistory(projectId, 20, accessToken) and depends on the config
query (enabled only if config exists). Remove the local useState management for
config/history and isLoading for those queries and map their loading/error
states to the query results; for job status polling, useQuery with
refetchInterval or the query's refetch to poll using jobIdRef (or a query keyed
by ['remoteSync','job', jobId]) instead of manual setInterval in pollTimerRef;
keep existing error handling by mapping query.error to the error state and
preserve enabled gating with the query's enabled option.

---

Nitpick comments:
In `@components/editor/RemoteSyncIndicator.tsx`:
- Around line 24-35: The component currently fetches server state imperatively
in RemoteSyncIndicator via a useEffect that calls remoteSyncApi.getConfig and
setConfig; replace that effect with a React Query-backed hook (either the
existing useRemoteSync or a slim useQuery) so the indicator uses shared
caching/invalidation. Implement a query such as useQuery(['remoteSync',
projectId], () => remoteSyncApi.getConfig(projectId, accessToken), { enabled:
!!projectId }) or call useRemoteSync(projectId, accessToken), and map a 404 to
null in the query's onError or queryFn so setConfig/useQuery data reflects null
on 404; remove the useEffect and local imperative fetch to ensure React Query
drives the state.

In `@lib/api/remoteSync.ts`:
- Around line 107-170: The client currently hard-switches all remote-sync
endpoints which will break if the frontend deploys before the backend rename;
update the API calls (e.g., saveConfig, deleteConfig, triggerCheck,
getJobStatus, getHistory and the initial get) to implement a dual-path fallback:
first attempt the new /remote-sync path and if that request returns a 404 (or a
specific "not found" response) automatically retry the same request against the
legacy path (e.g., the previous /remoteSync or whatever the old route is), or
alternatively read the base remote-sync path from a runtime config/feature-flag
and use that to choose the URL; ensure the retry preserves method, body and
headers (Authorization) and surface the final response/error to callers.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 66207bc3-2507-49e9-b1bb-1e41569bba9f

📥 Commits

Reviewing files that changed from the base of the PR and between 3491ddf and 9b7503c.

📒 Files selected for processing (10)
  • app/projects/[id]/editor/page.tsx
  • app/projects/[id]/settings/page.tsx
  • app/settings/page.tsx
  • components/editor/RemoteSyncIndicator.tsx
  • components/editor/index.ts
  • components/layout/notification-bell.tsx
  • lib/api/client.ts
  • lib/api/notifications.ts
  • lib/api/remoteSync.ts
  • lib/hooks/useRemoteSync.ts

Comment on lines 2453 to 2462
return (
<section
id="upstream-sync"
id="remote-sync"
className="mb-8 rounded-lg border border-slate-200 bg-white p-6 dark:border-slate-700 dark:bg-slate-800"
>
<div className="mb-4 flex items-center gap-2">
<Download className="h-5 w-5 text-slate-500" />
<h2 className="text-lg font-semibold text-slate-900 dark:text-white">
Upstream Source Tracking
Sync from Remote
</h2>
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Keep a temporary #upstream-sync alias.

Changing this section id breaks existing deep links from old notifications, bookmarks, or docs. A small alias or hash rewrite on load would let /settings#upstream-sync keep landing here while old links drain out.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/projects/`[id]/settings/page.tsx around lines 2453 - 2462, Keep a
temporary alias for the old hash by mapping "#upstream-sync" to the new section
id. In the component that returns the section with id="remote-sync" (the JSX
block in page.tsx), either add a hidden anchor element with id="upstream-sync"
next to the section or add a small client-side effect (e.g., in a useEffect
inside the same component) that checks window.location.hash and, if it equals
"#upstream-sync", calls history.replaceState or scrolls/updates location.hash to
"#remote-sync" so old deep links continue to land on the same UI until you
remove the alias.

Comment on lines +10 to +15
remoteSyncApi,
type RemoteSyncConfig,
type RemoteSyncConfigCreate,
type RemoteSyncConfigUpdate,
type SyncEvent,
} from "@/lib/api/upstreamSync";
} from "@/lib/api/remoteSync";
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Import remoteSyncApi through lib/api/client.ts to follow the API boundary.

This hook currently imports API methods directly from @/lib/api/remoteSync; use the centralized client entrypoint for backend communication consistency.

Suggested diff
 import { useState, useEffect, useCallback, useRef } from "react";
 import {
-  remoteSyncApi,
   type RemoteSyncConfig,
   type RemoteSyncConfigCreate,
   type RemoteSyncConfigUpdate,
   type SyncEvent,
 } from "@/lib/api/remoteSync";
+import { remoteSyncApi } from "@/lib/api/client";

As per coding guidelines, "All backend communication should go through lib/api/client.ts which provides type-safe API methods (api.get, api.post, etc.), domain-specific APIs (ontologyApi, classApi, projectOntologyApi), and automatic query parameter handling with error wrapping via ApiError".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/hooks/useRemoteSync.ts` around lines 10 - 15, The hook currently imports
remoteSyncApi directly from "@/lib/api/remoteSync"; update the import so
remoteSyncApi is imported from "@/lib/api/client" instead to follow the API
boundary (keep other type imports if needed from RemoteSync types but route the
API object via the centralized client). Locate the import list in
useRemoteSync.ts and replace the remoteSyncApi import source with the client
entrypoint (e.g., import { remoteSyncApi } from "@/lib/api/client"), then ensure
any calls use the same remoteSyncApi symbol and that error handling remains
compatible with ApiError from the client layer.

Copy link
Copy Markdown
Contributor

@damienriehl damienriehl left a comment

Choose a reason for hiding this comment

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

Perfectly symmetric rename (+108/-108). All files, notification types, aria-labels, and URL anchors consistently updated.

JohnRDOrazio and others added 2 commits April 6, 2026 09:56
Closes #79

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update section headings, aria-labels, and descriptions to say
"Sync from Remote" instead of "Remote Sync" for clarity.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@damienriehl damienriehl force-pushed the fix/rename-upstream-to-remote branch from 9b7503c to 683707b Compare April 6, 2026 14:57
@damienriehl damienriehl merged commit cb90fec into main Apr 6, 2026
16 checks passed
@damienriehl damienriehl deleted the fix/rename-upstream-to-remote branch April 6, 2026 15:00
Sign up for free to 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.

Rename 'upstream sync' to 'remote sync' / 'Sync from Remote' in UI

2 participants