Skip to content

fix: include overview docs in html documentation export (#7774)#7790

Open
eeshm wants to merge 1 commit intousebruno:mainfrom
eeshm:fix/7774-overview-docs-html-export
Open

fix: include overview docs in html documentation export (#7774)#7790
eeshm wants to merge 1 commit intousebruno:mainfrom
eeshm:fix/7774-overview-docs-html-export

Conversation

@eeshm
Copy link
Copy Markdown

@eeshm eeshm commented Apr 17, 2026

Description

fixes: #7774

This fixes an issue where content written in the Overview tab (especially at the collection level) was missing from generated docs.html.

Root cause

The HTML docs export had two gaps:

  1. It exported docs from saved roots only (root) and could miss unsaved Overview edits in draft.
  2. Collection-level docs were present in openCollection.docs, but the docs UI rendering path reliably displays docs attached to items/folders. As a result, collection Overview content was not consistently visible in exported HTML.

What changed

  • Export transformation now prefers draft state over saved state:
    • collection: collection.draft.root || collection.root
    • folder: folder.draft || folder.root
  • Added HTML docs normalization for export:
    • collection-level docs are converted into a top-level Overview folder item with markdown docs
    • avoids duplicate insertion if an Overview folder with docs already exists
    • skips insertion for empty/missing docs
  • Wired the normalization step into GenerateDocumentation before YAML is embedded into docs.html.

Behavior after fix

  • Collection/folder Overview markdown is included in exported docs.html
  • Empty/missing Overview content is handled safely

Screenshot:
image

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.

Summary by CodeRabbit

  • Bug Fixes

    • Improved HTML documentation generation to properly include collection-level documentation in exports.
    • Fixed handling of draft documentation during collection export to ensure no data loss.
  • Tests

    • Added comprehensive test coverage for documentation export and HTML documentation generation workflows.

Copilot AI review requested due to automatic review settings April 17, 2026 10:30
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 17, 2026

Walkthrough

The pull request fixes collection-level documentation export by introducing a new utility to auto-generate an Overview folder from collection docs, preferring draft data when available, and wiring this resolution into the HTML documentation export pipeline.

Changes

Cohort / File(s) Summary
HTML Documentation Generation
packages/bruno-app/src/components/Sidebar/Collections/.../GenerateDocumentation/index.js
Integrated resolveCollectionForHtmlDocumentation() into the export pipeline to post-process the OpenCollection object before YAML serialization.
Collection Transformation Utilities
packages/bruno-app/src/utils/collections/index.js
Updated transformCollectionToSaveToExportAsFile() to consistently prefer draft-sourced data (draft.root, draft.docs) over saved data when available for both collection and folder levels.
New HTML Documentation Resolver
packages/bruno-app/src/utils/exporters/html-documentation.js
Added new module exporting resolveCollectionForHtmlDocumentation() to detect collection docs and auto-create a top-level Overview folder item when needed, avoiding duplicates.
Test Coverage
packages/bruno-app/src/utils/tests/collections/examples-export-import.spec.js
Added comprehensive test suites validating draft docs handling in transformations and Overview folder creation logic in HTML documentation resolution.

Sequence Diagram

sequenceDiagram
    participant GD as GenerateDocumentation
    participant TC as transformCollectionToSaveToExportAsFile
    participant BC as brunoToOpenCollection
    participant RH as resolveCollectionForHtmlDocumentation
    participant YAML as jsyaml.dump

    GD->>TC: transformedCollection
    TC->>TC: Extract from draft.root/draft.docs<br/>(fallback to saved root/docs)
    TC-->>GD: transformed collection
    
    GD->>BC: transformed collection
    BC-->>GD: openCollection
    
    GD->>RH: openCollection with docs
    RH->>RH: Check for existing Overview
    RH->>RH: Create Overview folder from docs
    RH->>RH: Clear openCollection.docs
    RH-->>GD: resolved openCollection
    
    GD->>YAML: resolved openCollection
    YAML-->>GD: YAML serialized content
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • PR #6444 - Modifies transformCollectionToSaveToExportAsFile for filename normalization; same function modified in this PR for draft data sourcing.
  • PR #7016 - Calls transformCollectionToSaveToExportAsFile and exportOpenCollection in its YAML export flow; directly affected by transformation logic changes.
  • PR #6583 - Added the original GenerateDocumentation export flow; this PR extends it with the new HTML documentation resolution layer.

Suggested labels

size/M

Suggested reviewers

  • helloanoop
  • lohit-bruno
  • bijin-bruno

Poem

📚 Overview docs now shine so bright,
From draft to export, pure delight,
No more hidden collection prose,
In HTML docs the wisdom flows, 🎉
Your API tales, at last, exposed!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: fixing the inclusion of Overview documentation in HTML exports.
Linked Issues check ✅ Passed The PR implementation fully addresses issue #7774 by capturing draft state Overview docs, normalizing them into Overview folder items, and ensuring they appear in exported HTML.
Out of Scope Changes check ✅ Passed All changes align with fixing the Overview docs export issue. No unrelated modifications detected.
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

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

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes HTML documentation export so Overview tab markdown (especially at the collection/folder level) is included in generated docs.html, including unsaved edits that exist only in draft state.

Changes:

  • Update export transformation to prefer draft state over saved state for collection and folder roots.
  • Add an HTML-docs-specific normalization step that converts collection-level docs into a top-level Overview folder item (while avoiding duplicates / empty docs).
  • Wire the normalization into the GenerateDocumentation flow before YAML is embedded into docs.html, and add unit tests.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.

File Description
packages/bruno-app/src/utils/tests/collections/examples-export-import.spec.js Adds tests for draft-preferred export behavior and resolveCollectionForHtmlDocumentation normalization.
packages/bruno-app/src/utils/exporters/html-documentation.js Introduces resolveCollectionForHtmlDocumentation to move collection-level docs into an Overview folder item for HTML export.
packages/bruno-app/src/utils/collections/index.js Changes export transform to prefer draft roots for collection/folder docs (and omit empty draft docs).
packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/index.js Applies the normalization before dumping YAML for docs.html.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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/utils/exporters/html-documentation.js (1)

20-22: Case sensitivity on folder name match.

item?.info?.name !== OVERVIEW_FOLDER_NAME is strict case-sensitive, so a user-created folder named overview or OVERVIEW will be treated as unrelated and you'll end up with both folders in the sidebar. If that's acceptable (since this helper auto-generates the folder for export only), leave it — otherwise a .toLowerCase() compare is cheap insurance.

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

In `@packages/bruno-app/src/utils/exporters/html-documentation.js` around lines 20
- 22, The current check inside the items.some callback uses a case-sensitive
comparison (item?.info?.name !== OVERVIEW_FOLDER_NAME), which will miss user
folders named with different casing; update the comparison in the callback used
by items.some to compare names case-insensitively (e.g., normalize both
item?.info?.name and OVERVIEW_FOLDER_NAME with toLowerCase() or a
locale-insensitive compare) so the helper reliably detects the overview folder;
ensure you guard null/undefined before calling toLowerCase() on
item?.info?.name.
packages/bruno-app/src/utils/tests/collections/examples-export-import.spec.js (1)

394-416: Consider an additional case: existing Overview folder with empty docs.

hasTopLevelOverviewFolderWithDocs only matches folders whose docs have non-empty content, so an existing empty Overview folder would cause a second one to be prepended. Worth a test to lock in whatever behavior you want here (dedupe by name, or allow the duplicate).

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

In
`@packages/bruno-app/src/utils/tests/collections/examples-export-import.spec.js`
around lines 394 - 416, Add a test covering an existing top-level "Overview"
folder whose docs are empty: create a collection like openCollection but with
items[0].info.name === 'Overview' and items[0].docs.content === '' (or null) and
call resolveCollectionForHtmlDocumentation; assert either that no duplicate
Overview is added (expect result.items toHaveLength(1) and result
toBe(openCollection)) if you want dedupe-by-name, or assert a second Overview is
prepended (expect length 2) if you allow duplicates; to enforce dedupe-by-name
instead of docs-content matching, update hasTopLevelOverviewFolderWithDocs to
check for a folder with info.name === 'Overview' regardless of docs.content and
use that in resolveCollectionForHtmlDocumentation.
🤖 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/utils/exporters/html-documentation.js`:
- Around line 19-42: hasTopLevelOverviewFolderWithDocs only checks for non-empty
docs, causing a new Overview to be prepended when an empty top-level Overview
folder already exists; modify resolveCollectionForHtmlDocumentation to first
check for any top-level folder named OVERVIEW_FOLDER_NAME (use items =
Array.isArray(openCollection.items) ? openCollection.items : [] and find by
item?.info?.type === 'folder' && item?.info?.name === OVERVIEW_FOLDER_NAME), and
if found and its getDocsContent(item.docs).trim() is empty while
openCollection.docs has content, merge by setting that folder.docs =
openCollection.docs and return openCollection (avoid prepending); otherwise
preserve existing behavior (return openCollection when folder already has docs
or when no merge is needed).

---

Nitpick comments:
In `@packages/bruno-app/src/utils/exporters/html-documentation.js`:
- Around line 20-22: The current check inside the items.some callback uses a
case-sensitive comparison (item?.info?.name !== OVERVIEW_FOLDER_NAME), which
will miss user folders named with different casing; update the comparison in the
callback used by items.some to compare names case-insensitively (e.g., normalize
both item?.info?.name and OVERVIEW_FOLDER_NAME with toLowerCase() or a
locale-insensitive compare) so the helper reliably detects the overview folder;
ensure you guard null/undefined before calling toLowerCase() on
item?.info?.name.

In
`@packages/bruno-app/src/utils/tests/collections/examples-export-import.spec.js`:
- Around line 394-416: Add a test covering an existing top-level "Overview"
folder whose docs are empty: create a collection like openCollection but with
items[0].info.name === 'Overview' and items[0].docs.content === '' (or null) and
call resolveCollectionForHtmlDocumentation; assert either that no duplicate
Overview is added (expect result.items toHaveLength(1) and result
toBe(openCollection)) if you want dedupe-by-name, or assert a second Overview is
prepended (expect length 2) if you allow duplicates; to enforce dedupe-by-name
instead of docs-content matching, update hasTopLevelOverviewFolderWithDocs to
check for a folder with info.name === 'Overview' regardless of docs.content and
use that in resolveCollectionForHtmlDocumentation.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8c362923-cbbe-44c5-a170-8c70741b41cd

📥 Commits

Reviewing files that changed from the base of the PR and between c6281d3 and 22157ed.

📒 Files selected for processing (4)
  • packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/index.js
  • packages/bruno-app/src/utils/collections/index.js
  • packages/bruno-app/src/utils/exporters/html-documentation.js
  • packages/bruno-app/src/utils/tests/collections/examples-export-import.spec.js

Comment on lines +19 to +42
const hasTopLevelOverviewFolderWithDocs = (items = []) => {
return items.some((item) => {
if (item?.info?.type !== 'folder' || item?.info?.name !== OVERVIEW_FOLDER_NAME) {
return false;
}

return getDocsContent(item.docs).trim().length > 0;
});
};

export const resolveCollectionForHtmlDocumentation = (openCollection) => {
if (!openCollection || typeof openCollection !== 'object') {
return openCollection;
}

const docsContent = getDocsContent(openCollection.docs).trim();
if (!docsContent.length) {
return openCollection;
}

const items = Array.isArray(openCollection.items) ? openCollection.items : [];
if (hasTopLevelOverviewFolderWithDocs(items)) {
return openCollection;
}
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

Edge case: an existing empty Overview folder yields two Overview entries.

hasTopLevelOverviewFolderWithDocs returns false when a top-level folder named Overview exists but has empty/whitespace docs. In that case this helper will still prepend a new Overview folder, leaving the collection with two sibling folders of the same name — which the docs sidebar will render as two separate "Overview" entries.

Two reasonable options:

  • Merge: if a top-level Overview folder exists, populate its docs instead of prepending.
  • Skip-by-name: bail out whenever any top-level folder is named Overview, regardless of docs content.
♻️ Example: merge into existing empty Overview
-  const items = Array.isArray(openCollection.items) ? openCollection.items : [];
-  if (hasTopLevelOverviewFolderWithDocs(items)) {
-    return openCollection;
-  }
-
-  const overviewItem = {
-    info: {
-      name: OVERVIEW_FOLDER_NAME,
-      type: 'folder'
-    },
-    docs: {
-      content: docsContent,
-      type: 'text/markdown'
-    }
-  };
-
-  return {
-    ...openCollection,
-    docs: undefined,
-    items: [overviewItem, ...items]
-  };
+  const items = Array.isArray(openCollection.items) ? openCollection.items : [];
+  const existingIdx = items.findIndex(
+    (i) => i?.info?.type === 'folder' && i?.info?.name === OVERVIEW_FOLDER_NAME
+  );
+  if (existingIdx !== -1 && getDocsContent(items[existingIdx].docs).trim().length > 0) {
+    return openCollection;
+  }
+
+  const overviewDocs = { content: docsContent, type: 'text/markdown' };
+  const nextItems = [...items];
+  if (existingIdx !== -1) {
+    nextItems[existingIdx] = { ...nextItems[existingIdx], docs: overviewDocs };
+  } else {
+    nextItems.unshift({
+      info: { name: OVERVIEW_FOLDER_NAME, type: 'folder' },
+      docs: overviewDocs
+    });
+  }
+
+  return { ...openCollection, docs: undefined, items: nextItems };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const hasTopLevelOverviewFolderWithDocs = (items = []) => {
return items.some((item) => {
if (item?.info?.type !== 'folder' || item?.info?.name !== OVERVIEW_FOLDER_NAME) {
return false;
}
return getDocsContent(item.docs).trim().length > 0;
});
};
export const resolveCollectionForHtmlDocumentation = (openCollection) => {
if (!openCollection || typeof openCollection !== 'object') {
return openCollection;
}
const docsContent = getDocsContent(openCollection.docs).trim();
if (!docsContent.length) {
return openCollection;
}
const items = Array.isArray(openCollection.items) ? openCollection.items : [];
if (hasTopLevelOverviewFolderWithDocs(items)) {
return openCollection;
}
const hasTopLevelOverviewFolderWithDocs = (items = []) => {
return items.some((item) => {
if (item?.info?.type !== 'folder' || item?.info?.name !== OVERVIEW_FOLDER_NAME) {
return false;
}
return getDocsContent(item.docs).trim().length > 0;
});
};
export const resolveCollectionForHtmlDocumentation = (openCollection) => {
if (!openCollection || typeof openCollection !== 'object') {
return openCollection;
}
const docsContent = getDocsContent(openCollection.docs).trim();
if (!docsContent.length) {
return openCollection;
}
const items = Array.isArray(openCollection.items) ? openCollection.items : [];
const existingIdx = items.findIndex(
(i) => i?.info?.type === 'folder' && i?.info?.name === OVERVIEW_FOLDER_NAME
);
if (existingIdx !== -1 && getDocsContent(items[existingIdx].docs).trim().length > 0) {
return openCollection;
}
const overviewDocs = { content: docsContent, type: 'text/markdown' };
const nextItems = [...items];
if (existingIdx !== -1) {
nextItems[existingIdx] = { ...nextItems[existingIdx], docs: overviewDocs };
} else {
nextItems.unshift({
info: { name: OVERVIEW_FOLDER_NAME, type: 'folder' },
docs: overviewDocs
});
}
return { ...openCollection, docs: undefined, items: nextItems };
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/bruno-app/src/utils/exporters/html-documentation.js` around lines 19
- 42, hasTopLevelOverviewFolderWithDocs only checks for non-empty docs, causing
a new Overview to be prepended when an empty top-level Overview folder already
exists; modify resolveCollectionForHtmlDocumentation to first check for any
top-level folder named OVERVIEW_FOLDER_NAME (use items =
Array.isArray(openCollection.items) ? openCollection.items : [] and find by
item?.info?.type === 'folder' && item?.info?.name === OVERVIEW_FOLDER_NAME), and
if found and its getDocsContent(item.docs).trim() is empty while
openCollection.docs has content, merge by setting that folder.docs =
openCollection.docs and return openCollection (avoid prepending); otherwise
preserve existing behavior (return openCollection when folder already has docs
or when no merge is needed).

@helloanoop
Copy link
Copy Markdown
Contributor

Thanks for the PR @eeshm !

At this stage, this is under consideration along with other requests. We’ll follow up once there’s a clearer decision or prioritization.

@eeshm
Copy link
Copy Markdown
Author

eeshm commented Apr 18, 2026

Sure @helloanoop . thanks for the update. let me know if you need anything else from my side

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.

Collection/folder docs not included in exported docs.html file

3 participants