Skip to content

feat: improve OpenAPI Sync tab UX and fix sync flow bugs#7467

Merged
bijin-bruno merged 11 commits intousebruno:mainfrom
abhishek-bruno:fix/openapi-sync-issues-v2
Mar 13, 2026
Merged

feat: improve OpenAPI Sync tab UX and fix sync flow bugs#7467
bijin-bruno merged 11 commits intousebruno:mainfrom
abhishek-bruno:fix/openapi-sync-issues-v2

Conversation

@abhishek-bruno
Copy link
Copy Markdown
Member

@abhishek-bruno abhishek-bruno commented Mar 13, 2026

Description

  • Fix file deletion on path rename: Reorder sync execution (delete before add) and verify file content matches endpoint before deleting, preventing accidental deletion when renamed paths share the same summary-based filename
  • Fix stale UI after Skip All sync: Spec Updates tab now correctly shows empty state after syncing with all changes skipped, instead of still rendering skipped items
  • Fix badge/content count mismatch: Add security to endpoint hash and filter phantom diffs from comparison normalization differences, ensuring badge count matches review page content
  • Fix stale review decisions: Clear Redux review decisions after sync so next check-for-updates starts fresh
  • Auto-check only on first open: Prevent redundant spec checks on every tab focus by checking Redux state
  • Enhance collection status display: Add loading state, endpoint counting utility, and stored spec metadata persistence
  • Resolve absolute file paths: Display full resolved paths for local spec sources in the header
  • Pretty-print JSON specs: Format JSON content in the API spec viewer for readability
  • Improve error messages: Specify "OpenAPI 3.x" in validation error messages
  • Style improvements: Visual feedback enhancements across the sync tab

Contribution Checklist:

  • I've used AI significantly to create this pull request
  • The pull request only addresses one issue or adds one feature.
  • The pull request does not introduce any breaking changes
  • I have added screenshots or gifs to help explain the change if applicable.
  • I have read the contribution guidelines.
  • Create an issue and link to the pull request.

Note: Keeping the PR small and focused helps make it easier to review and merge. If you have multiple changes you want to make, please consider submitting them as separate pull requests.

Publishing to New Package Managers

Please see here for more information.

Summary by CodeRabbit

  • New Features

    • Persist per-collection spec metadata; expanded loading states and "Checking for updates" feedback across sync screens; local file path resolution for reveal actions.
  • Bug Fixes

    • Verify file contents before deleting endpoints to prevent accidental removals; reduce filename collisions when adding/merging endpoints.
  • Improvements

    • Consistent pretty-printing of JSON specs; clearer "OpenAPI 3.x" validation messages; UI/styling refinements (badges, sticky diff headers, loading indicators).

…alidation

Updated error messages in ConnectSpecForm and ConnectionSettingsModal to clarify that only OpenAPI 3.x specifications are valid. Enhanced useOpenAPISync hook to reflect the same specificity in error handling for invalid URLs.
…c viewer

Implemented a new function to pretty-print JSON content for improved readability in the OpenAPISpecTab component. This enhancement ensures that JSON specifications are displayed in a more user-friendly format while leaving YAML content unchanged.
…local sources

Added functionality to resolve relative file paths to absolute paths for better user experience in the OpenAPISyncHeader component. Implemented state management and side effects to handle path resolution based on the source URL, enhancing the display of local file paths.
…int counting utility

Refactored the CollectionStatusSection to streamline the display of collection drift status, integrating loading states and improved messaging for initial sync scenarios. Introduced a new utility function to count HTTP endpoints in OpenAPI specifications, enhancing the overall functionality of the OpenAPISyncTab. Additionally, updated the OpenAPISyncHeader and OverviewSection to utilize stored specification metadata for better user experience.
- Enhanced the logic for adding new requests by ensuring existing files are verified before removal to prevent accidental deletions.
- Streamlined the process of adding new endpoints, including checks for existing files and merging requests to maintain user customizations.
- Added comments for clarity on the purpose of changes, particularly regarding filename collision prevention and file content verification.
- Changed background color for the 'type-spec-modified' class to a warning color for better distinction.
- Updated text color and background for the SyncReviewPage to enhance readability and visual hierarchy.
- Adjusted default expanded states for endpoint sections to improve user experience during sync reviews.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 13, 2026

Walkthrough

Adds spec pretty-printing, per-collection stored spec metadata and endpoint counting, safer IPC file operations with content verification, broader loading/empty-state handling across OpenAPI sync UI, and several styling and copy adjustments.

Changes

Cohort / File(s) Summary
Spec formatting
packages/bruno-app/src/components/OpenAPISpecTab/index.js
Add internal prettyPrintSpec using fastJsonFormat; apply when setting specContent for remote and local specs.
Sync UI (loading / empty states)
packages/bruno-app/src/components/OpenAPISyncTab/CollectionStatusSection/index.js, packages/bruno-app/src/components/OpenAPISyncTab/SpecStatusSection/index.js, packages/bruno-app/src/components/OpenAPISyncTab/SyncReviewPage/index.js, packages/bruno-app/src/components/OpenAPISyncTab/SpecDiffModal/index.js
Introduce isLoading handling, IconLoader2 loader usage, render guards and adjusted empty-state copy; default review sections expanded.
Header, overview & local path
packages/bruno-app/src/components/OpenAPISyncTab/OpenAPISyncHeader/index.js, packages/bruno-app/src/components/OpenAPISyncTab/OverviewSection/index.js, packages/bruno-app/src/components/OpenAPISyncTab/index.js
Resolve local display path via IPC; use persisted specMeta as fallback for title/version/endpoint counts; always render CollectionStatusSection and pass aggregated isLoading.
Validation & messaging
packages/bruno-app/src/components/OpenAPISyncTab/ConnectSpecForm/index.js, packages/bruno-app/src/components/OpenAPISyncTab/ConnectionSettingsModal/index.js, packages/bruno-app/src/components/OpenAPISyncTab/hooks/useOpenAPISync.js
Replace URL helper with isHttpUrl and update validation copy to reference “OpenAPI 3.x specification”.
State & utilities
packages/bruno-app/src/providers/ReduxStore/slices/openapi-sync.js, packages/bruno-app/src/components/OpenAPISyncTab/hooks/useOpenAPISync.js, packages/bruno-app/src/components/OpenAPISyncTab/utils.js
Add storedSpecMeta state, setStoredSpecMeta action and selectStoredSpecMeta selector; useOpenAPISync persists spec meta via updateStoredSpec; add exported countEndpoints(spec).
IPC: file-safety & endpoint handling
packages/bruno-electron/src/ipc/openapi-sync.js
Reorder add/remove flows to avoid filename collisions; verify file content (parse & match method/path) before deleting local-only endpoints; add try/catch and logging around deletions.
Styling & minor UI tweaks
packages/bruno-app/src/components/OpenAPISyncTab/StyledWrapper.js, packages/bruno-app/src/components/OpenAPISyncTab/DisconnectSyncModal/index.js, .gitignore
Badge/section style updates, overflow → auto, sticky diff header, spinner & disabled styles, change Cancel button color; add .agents, .agent, skills-lock.json to .gitignore.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Renderer
  participant Redux
  participant IPCMain
  participant FS as FileSystem

  Client->>Renderer: Open Sync tab / trigger "Check for updates"
  Renderer->>Redux: dispatch start check (isLoading = true)
  Renderer->>IPCMain: request remote spec / resolve local path
  IPCMain->>FS: read remote/local spec files
  FS-->>IPCMain: return spec bytes / file contents
  IPCMain-->>Renderer: send spec result, diff, metadata
  Renderer->>Redux: dispatch setStoredSpecMeta / updateStoredSpec
  Redux-->>Renderer: storedSpecMeta available
  Renderer->>Client: render UI (specMeta, endpoint counts, or loader)
  Note right of IPCMain: deletions guarded — parse file -> match method/path -> delete if match
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • PR #7408 — Overlaps on OpenAPI sync flow and spec formatting changes (pretty-printing and validation messaging).
  • PR #7392 — Touches OverviewSection, SpecStatusSection and useOpenAPISync hooks similar to this PR.
  • PR #7279 — Modifies OpenAPI sync components/hooks/ipc that interact with these changes.

Suggested reviewers

  • helloanoop
  • lohit-bruno
  • naman-bruno
  • bijin-bruno

Poem

✨ Specs are prettified and stored, counts kept tidy in a row,
Spinners spin while checks run safe, and deletions now are slow,
Headers learn their names again, diffs stick firm and never slip,
Sync hums steady, files verified — a careful, guarded ship. 🚢

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objectives: improving OpenAPI Sync tab UX and fixing sync flow bugs, which aligns with the comprehensive changes across multiple sync components.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

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
Contributor

@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

🧹 Nitpick comments (2)
packages/bruno-app/src/components/OpenAPISyncTab/utils.js (1)

10-13: Harden countEndpoints against malformed paths entries.

Object.keys(path) can throw if a path item is null/non-object. A small guard makes this utility safer for imperfect spec payloads.

♻️ Proposed defensive update
 export const countEndpoints = (spec) => {
   if (!spec?.paths) return null;
   let count = 0;
-  for (const path of Object.values(spec.paths)) {
-    for (const key of Object.keys(path)) {
+  for (const pathItem of Object.values(spec.paths)) {
+    if (!pathItem || typeof pathItem !== 'object') continue;
+    for (const key of Object.keys(pathItem)) {
       if (HTTP_METHODS.includes(key.toLowerCase())) count++;
     }
   }
   return count;
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bruno-app/src/components/OpenAPISyncTab/utils.js` around lines 10 -
13, The loop in countEndpoints can throw when iterating Object.keys(path) if a
path entry is null or not an object; add a guard before using Object.keys to
ensure each path is a plain object (e.g. check path !== null && typeof path ===
"object") and skip non-objects, then proceed to iterate keys and test against
HTTP_METHODS; update countEndpoints to perform that check (referencing the
countEndpoints function and HTTP_METHODS constant) so malformed spec.paths
entries are safely ignored.
packages/bruno-app/src/components/OpenAPISyncTab/SpecStatusSection/index.js (1)

5-6: Unused import: IconLoader2.

IconLoader2 is imported but not used in this file. The loading state appears to be handled by SyncReviewPage which receives the isLoading prop.

🧹 Proposed fix
 import {
   IconCheck,
-  IconRefresh,
-  IconLoader2
+  IconRefresh
 } from '@tabler/icons';
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bruno-app/src/components/OpenAPISyncTab/SpecStatusSection/index.js`
around lines 5 - 6, The import list in SpecStatusSection includes an unused
symbol IconLoader2; remove IconLoader2 from the import statement (the import
that currently lists IconRefresh and IconLoader2) so only IconRefresh is
imported, and ensure no other references to IconLoader2 remain in the file (the
loading UI is already handled via the isLoading prop passed to SyncReviewPage).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/bruno-app/src/components/OpenAPISyncTab/CollectionStatusSection/index.js`:
- Around line 228-239: Fix the double-period typo in the user-facing messages
inside the CollectionStatusSection component: update the conditional message
strings that reference lastSyncDate (the two places rendering 'Last synced spec
is required...' and 'Restore the latest spec from the source to track future
changes..') to end with a single period; check both the top span message and the
<p> message that uses lastSyncDate and remove the extra '.' so each sentence
ends with one period.

In `@packages/bruno-app/src/components/OpenAPISyncTab/SyncReviewPage/index.js`:
- Line 264: The displayed no-update message in the SyncReviewPage component
contains incorrect grammar ("The spec endpoints has not been updated...");
update the string used in the JSX (the paragraph text in SyncReviewPage) to use
correct plural agreement, e.g. change "The spec endpoints has not been updated
since the last sync." to "The spec endpoints have not been updated since the
last sync." so the message reads grammatically correct.

---

Nitpick comments:
In `@packages/bruno-app/src/components/OpenAPISyncTab/SpecStatusSection/index.js`:
- Around line 5-6: The import list in SpecStatusSection includes an unused
symbol IconLoader2; remove IconLoader2 from the import statement (the import
that currently lists IconRefresh and IconLoader2) so only IconRefresh is
imported, and ensure no other references to IconLoader2 remain in the file (the
loading UI is already handled via the isLoading prop passed to SyncReviewPage).

In `@packages/bruno-app/src/components/OpenAPISyncTab/utils.js`:
- Around line 10-13: The loop in countEndpoints can throw when iterating
Object.keys(path) if a path entry is null or not an object; add a guard before
using Object.keys to ensure each path is a plain object (e.g. check path !==
null && typeof path === "object") and skip non-objects, then proceed to iterate
keys and test against HTTP_METHODS; update countEndpoints to perform that check
(referencing the countEndpoints function and HTTP_METHODS constant) so malformed
spec.paths entries are safely ignored.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6d7ef166-6b97-4680-8dc6-ae4ee3a04750

📥 Commits

Reviewing files that changed from the base of the PR and between b25b6f3 and 99e9ce2.

📒 Files selected for processing (14)
  • packages/bruno-app/src/components/OpenAPISpecTab/index.js
  • packages/bruno-app/src/components/OpenAPISyncTab/CollectionStatusSection/index.js
  • packages/bruno-app/src/components/OpenAPISyncTab/ConnectSpecForm/index.js
  • packages/bruno-app/src/components/OpenAPISyncTab/ConnectionSettingsModal/index.js
  • packages/bruno-app/src/components/OpenAPISyncTab/OpenAPISyncHeader/index.js
  • packages/bruno-app/src/components/OpenAPISyncTab/OverviewSection/index.js
  • packages/bruno-app/src/components/OpenAPISyncTab/SpecStatusSection/index.js
  • packages/bruno-app/src/components/OpenAPISyncTab/StyledWrapper.js
  • packages/bruno-app/src/components/OpenAPISyncTab/SyncReviewPage/index.js
  • packages/bruno-app/src/components/OpenAPISyncTab/hooks/useOpenAPISync.js
  • packages/bruno-app/src/components/OpenAPISyncTab/index.js
  • packages/bruno-app/src/components/OpenAPISyncTab/utils.js
  • packages/bruno-app/src/providers/ReduxStore/slices/openapi-sync.js
  • packages/bruno-electron/src/ipc/openapi-sync.js

Comment thread packages/bruno-app/src/components/OpenAPISyncTab/SyncReviewPage/index.js Outdated
- Added new entries to .gitignore for agent-related files and skills-lock.json.
- Modified StyledWrapper to improve overflow handling and added sticky headers for better visibility.
- Introduced loading state in SpecDiffModal with a spinner for improved user feedback during rendering.
…ndering

- Replaced the JSON parsing and stringifying logic with fast-json-format for better performance in pretty-printing API specifications.
- Updated StyledWrapper in OpenAPISyncTab to change background and text colors for enhanced visual consistency.
- Modified DisconnectSyncModal button to include a secondary color for improved visibility during user interactions.
Copy link
Copy Markdown
Contributor

@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: 1

🧹 Nitpick comments (2)
packages/bruno-app/src/components/OpenAPISyncTab/StyledWrapper.js (1)

1740-1747: Consider honoring reduced-motion for spinner animation.

Line 1745-1747 introduces a new spinner animation; adding a reduced-motion fallback would improve accessibility with minimal cost.

♿ Optional tweak
      .spinner-icon {
        animation: spin 1s linear infinite;
      }
+
+      `@media` (prefers-reduced-motion: reduce) {
+        .spinner-icon {
+          animation: none;
+        }
+      }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bruno-app/src/components/OpenAPISyncTab/StyledWrapper.js` around
lines 1740 - 1747, Add a reduced-motion fallback for the spinner by wrapping the
.spinner-icon animation rule in a prefers-reduced-motion media query (or add a
separate `@media` (prefers-reduced-motion: reduce) block) and set animation: none
(or animation-duration: 0s) for .spinner-icon there; update the
spinner/keyframes usage in StyledWrapper (the .spinner-icon rule and any spin
keyframes) so users who prefer reduced motion won’t see the continuous spin.
packages/bruno-app/src/components/OpenAPISyncTab/SpecDiffModal/index.js (1)

20-39: Loading state may not be visible due to synchronous execution.

The setIsRendering(true) → synchronous DOM mutation → setIsRendering(false) sequence runs within a single useEffect callback. Since React batches state updates, the intermediate isRendering=true state may never actually trigger a re-render before it's immediately set back to false.

For fast diffs, this is fine. For large specs where Diff2Html.html() takes noticeable time, the loading indicator still won't appear because the DOM won't repaint until the synchronous work completes. If you want the spinner to be visible for heavy diffs, you'd need to defer the rendering work (e.g., requestAnimationFrame or setTimeout(..., 0)).

That said, this is a minor UX consideration — the current implementation is functional and unlikely to cause issues in practice.

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

In `@packages/bruno-app/src/components/OpenAPISyncTab/SpecDiffModal/index.js`
around lines 20 - 39, The useEffect currently sets setIsRendering(true), runs
the synchronous heavy Diff2Html.html(...) and immediately calls
setIsRendering(false) so the loading state may never render; modify the effect
to defer the expensive work (e.g., wrap the Diff2Html.html(...) call and
diffRef.current.innerHTML assignment in requestAnimationFrame or setTimeout(...,
0)) after calling setIsRendering(true), and ensure setIsRendering(false) runs
after the DOM mutation completes (or in the same deferred callback) so the
spinner can actually appear for large diffs; update the effect that uses
Diff2Html.html, diffRef.current.innerHTML, and setIsRendering accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.gitignore:
- Around line 54-56: The new .gitignore entries (.agents, .agent,
skills-lock.json) look unrelated to the OpenAPI Sync work and need
clarification; either remove them from this PR or document why they belong here:
if they are incidental housekeeping, move them to a separate housekeeping PR,
otherwise update the PR description and commit message to explain their purpose
and scope (mentioning .agents, .agent, skills-lock.json) so reviewers understand
they are intentional and what tooling or artifacts they ignore.

---

Nitpick comments:
In `@packages/bruno-app/src/components/OpenAPISyncTab/SpecDiffModal/index.js`:
- Around line 20-39: The useEffect currently sets setIsRendering(true), runs the
synchronous heavy Diff2Html.html(...) and immediately calls
setIsRendering(false) so the loading state may never render; modify the effect
to defer the expensive work (e.g., wrap the Diff2Html.html(...) call and
diffRef.current.innerHTML assignment in requestAnimationFrame or setTimeout(...,
0)) after calling setIsRendering(true), and ensure setIsRendering(false) runs
after the DOM mutation completes (or in the same deferred callback) so the
spinner can actually appear for large diffs; update the effect that uses
Diff2Html.html, diffRef.current.innerHTML, and setIsRendering accordingly.

In `@packages/bruno-app/src/components/OpenAPISyncTab/StyledWrapper.js`:
- Around line 1740-1747: Add a reduced-motion fallback for the spinner by
wrapping the .spinner-icon animation rule in a prefers-reduced-motion media
query (or add a separate `@media` (prefers-reduced-motion: reduce) block) and set
animation: none (or animation-duration: 0s) for .spinner-icon there; update the
spinner/keyframes usage in StyledWrapper (the .spinner-icon rule and any spin
keyframes) so users who prefer reduced motion won’t see the continuous spin.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 343a2515-e89b-4023-8ffe-29d14b5d1fae

📥 Commits

Reviewing files that changed from the base of the PR and between 99e9ce2 and d6a9469.

📒 Files selected for processing (5)
  • .gitignore
  • packages/bruno-app/src/components/OpenAPISpecTab/index.js
  • packages/bruno-app/src/components/OpenAPISyncTab/DisconnectSyncModal/index.js
  • packages/bruno-app/src/components/OpenAPISyncTab/SpecDiffModal/index.js
  • packages/bruno-app/src/components/OpenAPISyncTab/StyledWrapper.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/bruno-app/src/components/OpenAPISpecTab/index.js

Comment thread .gitignore
…tles

- Removed unnecessary trailing periods in messages related to syncing and restoring specifications across CollectionStatusSection and OverviewSection components.
- Updated SyncReviewPage to correct grammatical error in the description of spec updates.
Copy link
Copy Markdown
Contributor

@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: 1

Caution

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

⚠️ Outside diff range comments (1)
packages/bruno-app/src/components/OpenAPISyncTab/SpecStatusSection/index.js (1)

125-137: ⚠️ Potential issue | 🟠 Major

Hide SyncReviewPage for the explicit error states above.

Line 125 now falls through to SyncReviewPage even for file-not-found, invalid-spec, or comparison-error cases. Since remoteDrift is only populated after a successful compare in packages/bruno-app/src/components/OpenAPISyncTab/hooks/useOpenAPISync.js:168-178, those failures end up showing the "No updates from the spec" empty state under a danger banner.

Suggested fix
-      ) : (
+      ) : fileNotFound || error || specDrift?.isValid === false ? null : (
         <div className="mt-5">
           <SyncReviewPage
             specDrift={specDrift}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bruno-app/src/components/OpenAPISyncTab/SpecStatusSection/index.js`
around lines 125 - 137, The SyncReviewPage is rendered even when explicit error
states (file-not-found, invalid-spec, comparison-error) occurred; update the JSX
so SyncReviewPage only renders when there are no error flags and a successful
compare result exists (e.g., remoteDrift is populated). Concretely, in the
component rendering block that currently renders <SyncReviewPage ... />, guard
it with a combined condition such as "remoteDrift && !fileNotFound &&
!invalidSpec && !comparisonError" (or whatever error boolean names are used in
this file) so that SyncReviewPage (props: specDrift, remoteDrift,
collectionDrift, collectionPath, collectionUid, newSpec, isSyncing, isLoading,
onApplySync/handleApplySync) is hidden for those explicit error states described
in useOpenAPISync.
🧹 Nitpick comments (2)
packages/bruno-app/src/components/OpenAPISyncTab/OverviewSection/index.js (2)

123-123: Minor copy polish for subtitle wording.

Line 123 reads more naturally as “missing in storage” (instead of “missing in the storage”).

✍️ Copy tweak
-        subtitle: 'The last synced spec is missing in the storage. Restore the latest spec from the source to track future changes.',
+        subtitle: 'The last synced spec is missing in storage. Restore the latest spec from the source to track future changes.',
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bruno-app/src/components/OpenAPISyncTab/OverviewSection/index.js` at
line 123, Update the subtitle text in the OverviewSection component so it reads
"missing in storage" instead of "missing in the storage": locate the subtitle
property (key: subtitle) inside the OverviewSection (or the OpenAPISyncTab
OverviewSection component) and change the string to "The last synced spec is
missing in storage. Restore the latest spec from the source to track future
changes." to apply the copy polish.

50-51: Make endpoint fallback explicit when storedSpec is absent.

On Line 51, fallback to specMeta?.endpointCount currently depends on what countEndpoints() returns for missing input. Guarding on storedSpec directly avoids accidental 0 masking fallback metadata.

♻️ Suggested tweak
-  const endpointCount = countEndpoints(storedSpec) ?? specMeta?.endpointCount ?? null;
+  const endpointCount = storedSpec
+    ? countEndpoints(storedSpec)
+    : (specMeta?.endpointCount ?? null);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bruno-app/src/components/OpenAPISyncTab/OverviewSection/index.js`
around lines 50 - 51, The endpoint fallback currently calls
countEndpoints(storedSpec) and then falls back to specMeta?.endpointCount, which
can incorrectly use the fallback when countEndpoints returns 0; update the
endpointCount logic to first check storedSpec presence and only call
countEndpoints when storedSpec exists (so a returned 0 from countEndpoints is
preserved), otherwise use specMeta?.endpointCount; adjust the expression around
endpointCount (referencing storedSpec, countEndpoints, and
specMeta?.endpointCount) so the fallback is explicit when storedSpec is absent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/bruno-app/src/components/OpenAPISyncTab/CollectionStatusSection/index.js`:
- Around line 43-45: The code currently treats a null collectionDrift as "no
stored spec" because hasStoredSpec is computed as collectionDrift &&
!collectionDrift.noStoredSpec; change hasStoredSpec to explicitly check for a
non-null result (e.g., collectionDrift !== null &&
!collectionDrift.noStoredSpec) and update hasDrift to guard similarly (e.g.,
collectionDrift !== null && (collectionDrift.modified?.length > 0 ||
collectionDrift.missing?.length > 0)); ensure any rendering logic that branches
on !hasStoredSpec instead distinguishes between "loading/unknown"
(collectionDrift === null), "noStoredSpec" (collectionDrift?.noStoredSpec ===
true), and "hasStoredSpec" using the new guards so the
initial-loading/failed-to-load state is not rendered as missing-spec.

---

Outside diff comments:
In `@packages/bruno-app/src/components/OpenAPISyncTab/SpecStatusSection/index.js`:
- Around line 125-137: The SyncReviewPage is rendered even when explicit error
states (file-not-found, invalid-spec, comparison-error) occurred; update the JSX
so SyncReviewPage only renders when there are no error flags and a successful
compare result exists (e.g., remoteDrift is populated). Concretely, in the
component rendering block that currently renders <SyncReviewPage ... />, guard
it with a combined condition such as "remoteDrift && !fileNotFound &&
!invalidSpec && !comparisonError" (or whatever error boolean names are used in
this file) so that SyncReviewPage (props: specDrift, remoteDrift,
collectionDrift, collectionPath, collectionUid, newSpec, isSyncing, isLoading,
onApplySync/handleApplySync) is hidden for those explicit error states described
in useOpenAPISync.

---

Nitpick comments:
In `@packages/bruno-app/src/components/OpenAPISyncTab/OverviewSection/index.js`:
- Line 123: Update the subtitle text in the OverviewSection component so it
reads "missing in storage" instead of "missing in the storage": locate the
subtitle property (key: subtitle) inside the OverviewSection (or the
OpenAPISyncTab OverviewSection component) and change the string to "The last
synced spec is missing in storage. Restore the latest spec from the source to
track future changes." to apply the copy polish.
- Around line 50-51: The endpoint fallback currently calls
countEndpoints(storedSpec) and then falls back to specMeta?.endpointCount, which
can incorrectly use the fallback when countEndpoints returns 0; update the
endpointCount logic to first check storedSpec presence and only call
countEndpoints when storedSpec exists (so a returned 0 from countEndpoints is
preserved), otherwise use specMeta?.endpointCount; adjust the expression around
endpointCount (referencing storedSpec, countEndpoints, and
specMeta?.endpointCount) so the fallback is explicit when storedSpec is absent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 26d6f599-e823-4286-87d4-ebfcbf8c49de

📥 Commits

Reviewing files that changed from the base of the PR and between d6a9469 and 25df4cb.

📒 Files selected for processing (4)
  • packages/bruno-app/src/components/OpenAPISyncTab/CollectionStatusSection/index.js
  • packages/bruno-app/src/components/OpenAPISyncTab/OverviewSection/index.js
  • packages/bruno-app/src/components/OpenAPISyncTab/SpecStatusSection/index.js
  • packages/bruno-app/src/components/OpenAPISyncTab/SyncReviewPage/index.js

- Replaced isValidUrl with isHttpUrl in ConnectSpecForm and ConnectionSettingsModal components to ensure only valid HTTP URLs are accepted.
- Updated the logic for enabling the save button based on the new URL validation method.
Copy link
Copy Markdown
Contributor

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/bruno-app/src/components/OpenAPISyncTab/ConnectionSettingsModal/index.js`:
- Line 11: Trim/normalize the incoming sourceUrl once before you infer modal
mode so leading/trailing whitespace won't make a valid HTTP URL be treated as a
file; specifically, introduce a normalizedSourceUrl (e.g., trimmed string or
fallback) and use that when calling isHttpUrl (where isUrl is computed) and
anywhere else you inspect sourceUrl for mode initialization (the same places
referenced around isUrl and the modal mode inference logic) so all checks
operate on the trimmed value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 180f1b7c-9b04-4ebe-b8cf-87f10f6d0569

📥 Commits

Reviewing files that changed from the base of the PR and between 25df4cb and 287bfdf.

📒 Files selected for processing (2)
  • packages/bruno-app/src/components/OpenAPISyncTab/ConnectSpecForm/index.js
  • packages/bruno-app/src/components/OpenAPISyncTab/ConnectionSettingsModal/index.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/bruno-app/src/components/OpenAPISyncTab/ConnectSpecForm/index.js

const ConnectionSettingsModal = ({ collection, sourceUrl, onSave, onDisconnect, onClose }) => {
const openApiSyncConfig = collection?.brunoConfig?.openapi?.[0];
const isUrl = isValidUrl(sourceUrl);
const isUrl = isHttpUrl(sourceUrl);
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.

⚠️ Potential issue | 🟡 Minor

Normalize sourceUrl once before mode inference to avoid whitespace edge cases.

If persisted sourceUrl has leading/trailing spaces, modal mode can initialize as file even for valid HTTP URLs.

💡 Proposed fix
-  const isUrl = isHttpUrl(sourceUrl);
+  const normalizedSourceUrl = (sourceUrl || '').trim();
+  const isUrl = isHttpUrl(normalizedSourceUrl);
   const initialMode = isUrl ? 'url' : 'file';
   const [mode, setMode] = useState(initialMode);
-  const [url, setUrl] = useState(isUrl ? (sourceUrl || '') : '');
+  const [url, setUrl] = useState(isUrl ? normalizedSourceUrl : '');
   const [filePath, setFilePath] = useState(isUrl ? '' : sourceUrl);
@@
-  const effectiveSource = mode === 'file' ? filePath : url.trim();
-  const canSave = mode === 'file' ? !!effectiveSource : isHttpUrl(effectiveSource.trim());
+  const normalizedUrl = url.trim();
+  const effectiveSource = mode === 'file' ? filePath : normalizedUrl;
+  const canSave = mode === 'file' ? !!effectiveSource : isHttpUrl(normalizedUrl);

Also applies to: 24-24

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

In
`@packages/bruno-app/src/components/OpenAPISyncTab/ConnectionSettingsModal/index.js`
at line 11, Trim/normalize the incoming sourceUrl once before you infer modal
mode so leading/trailing whitespace won't make a valid HTTP URL be treated as a
file; specifically, introduce a normalizedSourceUrl (e.g., trimmed string or
fallback) and use that when calling isHttpUrl (where isUrl is computed) and
anywhere else you inspect sourceUrl for mode initialization (the same places
referenced around isUrl and the modal mode inference logic) so all checks
operate on the trimmed value.

- Trimmed the source URL in ConnectionSettingsModal to ensure consistent validation with isHttpUrl.
- Updated state initialization for URL and filePath to use the normalized source URL, improving handling of user input.
@bijin-bruno bijin-bruno merged commit 384bf4f into usebruno:main Mar 13, 2026
8 checks passed
lohit-bruno pushed a commit to lohit-bruno/bruno that referenced this pull request Mar 18, 2026
* fix: specify OpenAPI 3.x in error messages for file uploads and URL validation

Updated error messages in ConnectSpecForm and ConnectionSettingsModal to clarify that only OpenAPI 3.x specifications are valid. Enhanced useOpenAPISync hook to reflect the same specificity in error handling for invalid URLs.

* feat(OpenAPISpecTab): add pretty-printing for JSON content in API spec viewer

Implemented a new function to pretty-print JSON content for improved readability in the OpenAPISpecTab component. This enhancement ensures that JSON specifications are displayed in a more user-friendly format while leaving YAML content unchanged.

* feat(OpenAPISyncHeader): resolve and display absolute file paths for local sources

Added functionality to resolve relative file paths to absolute paths for better user experience in the OpenAPISyncHeader component. Implemented state management and side effects to handle path resolution based on the source URL, enhancing the display of local file paths.

* feat(OpenAPISyncTab): enhance collection status display and add endpoint counting utility

Refactored the CollectionStatusSection to streamline the display of collection drift status, integrating loading states and improved messaging for initial sync scenarios. Introduced a new utility function to count HTTP endpoints in OpenAPI specifications, enhancing the overall functionality of the OpenAPISyncTab. Additionally, updated the OpenAPISyncHeader and OverviewSection to utilize stored specification metadata for better user experience.

* refactor: improve OpenAPI Sync endpoint handling

- Enhanced the logic for adding new requests by ensuring existing files are verified before removal to prevent accidental deletions.
- Streamlined the process of adding new endpoints, including checks for existing files and merging requests to maintain user customizations.
- Added comments for clarity on the purpose of changes, particularly regarding filename collision prevention and file content verification.

* style(OpenAPISyncTab): update styles for improved visual feedback

- Changed background color for the 'type-spec-modified' class to a warning color for better distinction.
- Updated text color and background for the SyncReviewPage to enhance readability and visual hierarchy.
- Adjusted default expanded states for endpoint sections to improve user experience during sync reviews.

* chore: update .gitignore and enhance OpenAPISyncTab components

- Added new entries to .gitignore for agent-related files and skills-lock.json.
- Modified StyledWrapper to improve overflow handling and added sticky headers for better visibility.
- Introduced loading state in SpecDiffModal with a spinner for improved user feedback during rendering.

* feat(OpenAPISpecTab): integrate fast-json-format for improved JSON rendering

- Replaced the JSON parsing and stringifying logic with fast-json-format for better performance in pretty-printing API specifications.
- Updated StyledWrapper in OpenAPISyncTab to change background and text colors for enhanced visual consistency.
- Modified DisconnectSyncModal button to include a secondary color for improved visibility during user interactions.

* fix(OpenAPISyncTab): correct punctuation in status messages and subtitles

- Removed unnecessary trailing periods in messages related to syncing and restoring specifications across CollectionStatusSection and OverviewSection components.
- Updated SyncReviewPage to correct grammatical error in the description of spec updates.

* fix(OpenAPISyncTab): update URL validation to use isHttpUrl

- Replaced isValidUrl with isHttpUrl in ConnectSpecForm and ConnectionSettingsModal components to ensure only valid HTTP URLs are accepted.
- Updated the logic for enabling the save button based on the new URL validation method.

* fix(OpenAPISyncTab): normalize source URL before validation

- Trimmed the source URL in ConnectionSettingsModal to ensure consistent validation with isHttpUrl.
- Updated state initialization for URL and filePath to use the normalized source URL, improving handling of user input.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants