diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/CollectionVersionInfo/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/CollectionVersionInfo/index.js
index 204d17ed85..eb0c37074b 100644
--- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/CollectionVersionInfo/index.js
+++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/CollectionVersionInfo/index.js
@@ -1,36 +1,27 @@
-import React, { memo } from 'react';
-import semver from 'semver';
+import React, { memo, Fragment } from 'react';
-const DEFAULT_VERSION = 'v1.0.0';
-
-/**
- * Normalise a raw collection version for display: coerce partials to a full
- * major.minor.patch ("1" -> "v1.0.0", "2.1" -> "v2.1.0"), keep a single "v"
- * prefix, preserve pre-releases ("1.0.0-beta" -> "v1.0.0-beta"), and fall back to
- * the default when the version is unset or unparseable.
- */
-const formatVersion = (version) => {
- const coerced = semver.coerce(version, { includePrerelease: true });
- return coerced ? `v${coerced.version}` : DEFAULT_VERSION;
-};
-
-/**
- * Read-only display of the collection's current version and a summary of its
- * contents (folder + request counts). Presentational and prop-driven so it can be
- * reused wherever the collection version needs to be shown.
- */
-const CollectionVersionInfo = ({ version, folderCount = 0, requestCount = 0 }) => {
+const CollectionVersionInfo = ({ name, version, folderCount = 0, requestCount = 0, environmentCount = 0 }) => {
const folderLabel = folderCount === 1 ? 'Folder' : 'Folders';
const requestLabel = requestCount === 1 ? 'request' : 'requests';
return (
- Collection Version:{' '}
- {formatVersion(version)}
+ {name}
+ {version ? (
+ {`version : ${version}`}
+ ) : null}
- {`${folderCount} ${folderLabel} • ${requestCount} ${requestLabel}`}
+ {`${folderCount} ${folderLabel}`}
+
+ {`${requestCount} ${requestLabel}`}
+ {environmentCount === 0 ? (
+
+
+ 0 environments
+
+ ) : null}
);
diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/CollectionVersionInfo/index.spec.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/CollectionVersionInfo/index.spec.js
new file mode 100644
index 0000000000..5158aab6f1
--- /dev/null
+++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/CollectionVersionInfo/index.spec.js
@@ -0,0 +1,39 @@
+import '@testing-library/jest-dom';
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import CollectionVersionInfo from './index';
+
+describe('CollectionVersionInfo', () => {
+ it('shows the raw collection version with a "version :" prefix and no "v"/semver formatting', () => {
+ render();
+ expect(screen.getByTestId('version-value')).toHaveTextContent('version : 1');
+ });
+
+ it('shows whatever version string the collection has, unchanged', () => {
+ render();
+ expect(screen.getByTestId('version-value')).toHaveTextContent('version : 2.3-beta');
+ });
+
+ it('omits the version when the collection has none', () => {
+ render();
+ expect(screen.queryByTestId('version-value')).not.toBeInTheDocument();
+ });
+
+ it('renders folder and request counts and pluralizes them', () => {
+ const { rerender } = render();
+ expect(screen.getByTestId('version-summary')).toHaveTextContent('2 Folders');
+ expect(screen.getByTestId('version-summary')).toHaveTextContent('5 requests');
+
+ rerender();
+ expect(screen.getByTestId('version-summary')).toHaveTextContent('1 Folder');
+ expect(screen.getByTestId('version-summary')).toHaveTextContent('1 request');
+ });
+
+ it('shows "0 environments" only when there are no environments', () => {
+ const { rerender } = render();
+ expect(screen.getByTestId('version-summary')).toHaveTextContent('0 environments');
+
+ rerender();
+ expect(screen.getByTestId('version-summary')).not.toHaveTextContent('environments');
+ });
+});
diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/EnvironmentSelectionList/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/EnvironmentSelectionList/index.js
index 8cf1bbb6be..07e26ad3ed 100644
--- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/EnvironmentSelectionList/index.js
+++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/EnvironmentSelectionList/index.js
@@ -2,14 +2,14 @@ import React, { useCallback, useEffect, useMemo, useRef, memo } from 'react';
import { Virtuoso } from 'react-virtuoso';
import ColorBadge from 'components/ColorBadge';
-// Show at most 5 environments at a glance; the list virtualises and scrolls beyond
+// Show at most 6 environments at a glance; the list virtualises and scrolls beyond
// that, so it stays performant even for collections with hundreds of environments
// (only the visible rows are ever in the DOM).
-const MAX_VISIBLE_ROWS = 5;
+const MAX_VISIBLE_ROWS = 6;
// Fixed row height (px). MUST stay in sync with the `.env-row` height in StyledWrapper.js,
// since it is passed to Virtuoso as `fixedItemHeight`.
-const ENV_ROW_HEIGHT = 34;
+const ENV_ROW_HEIGHT = 28;
/**
* A selectable, virtualised list of collection environments (checkbox + color dot + name)
diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/StyledWrapper.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/StyledWrapper.js
index dbe18a56e5..ccd67dbd00 100644
--- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/StyledWrapper.js
+++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/StyledWrapper.js
@@ -14,33 +14,57 @@ const StyledWrapper = styled.div`
}
.config-card {
- border: 1px solid ${(props) => props.theme.border.border1};
+ border: 1px solid ${(props) => props.theme.table.border};
border-radius: ${(props) => props.theme.border.radius.md};
overflow: hidden;
+ width: 100%;
.version-info {
padding: 0.75rem 1rem;
background-color: ${(props) => props.theme.background.mantle};
.version-line {
- font-size: ${(props) => props.theme.font.size.sm};
- color: ${(props) => props.theme.text};
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 0.5rem;
}
- .version-label {
+ .collection-name {
font-weight: 500;
+ font-size: ${(props) => props.theme.font.size.base};
+ color: ${(props) => props.theme.text};
+ min-width: 0;
+ }
+
+ .version-value {
+ font-weight: 400;
+ font-size: ${(props) => props.theme.font.size.sm};
+ color: ${(props) => props.theme.colors.text.subtext2};
+ white-space: nowrap;
}
.version-summary {
+ display: flex;
+ align-items: center;
+ gap: 0.375rem;
margin: 0.25rem 0 0;
- font-size: ${(props) => props.theme.font.size.xs};
- color: ${(props) => props.theme.colors.text.muted};
+ font-size: ${(props) => props.theme.font.size.sm};
+ color: ${(props) => props.theme.colors.text.subtext2};
+ }
+
+ .version-dot {
+ width: 5px;
+ height: 5px;
+ border-radius: 50%;
+ background-color: ${(props) => props.theme.colors.text.subtext0};
+ flex-shrink: 0;
}
}
.card-divider {
height: 1px;
- background-color: ${(props) => props.theme.border.border1};
+ background-color: ${(props) => props.theme.table.border};
}
.env-section {
@@ -59,7 +83,7 @@ const StyledWrapper = styled.div`
align-items: center;
justify-content: space-between;
gap: 0.5rem;
- margin-bottom: 0.75rem;
+ margin-bottom: 0.15rem;
}
.env-section-heading {
@@ -70,18 +94,18 @@ const StyledWrapper = styled.div`
}
.env-section-count {
- font-size: ${(props) => props.theme.font.size.xs};
- color: ${(props) => props.theme.colors.text.muted};
+ font-size: ${(props) => props.theme.font.size.sm};
+ color: ${(props) => props.theme.colors.text.subtext2};
white-space: nowrap;
}
.env-section-title {
margin: 0;
- font-size: ${(props) => props.theme.font.size.xs};
+ font-size: ${(props) => props.theme.font.size.sm};
font-weight: 600;
letter-spacing: 0.05em;
text-transform: uppercase;
- color: ${(props) => props.theme.colors.text.muted};
+ color: ${(props) => props.theme.colors.text.subtext2};
}
.env-select-all {
@@ -94,7 +118,7 @@ const StyledWrapper = styled.div`
.env-select-all-label {
font-size: ${(props) => props.theme.font.size.sm};
- color: ${(props) => props.theme.colors.text.muted};
+ color: ${(props) => props.theme.colors.text.subtext2};
white-space: nowrap;
}
}
@@ -105,12 +129,12 @@ const StyledWrapper = styled.div`
gap: 0.5rem;
/* Fixed row height — MUST match ENV_ROW_HEIGHT (Virtuoso fixedItemHeight)
in EnvironmentSelectionList. The inter-row spacing is baked in here. */
- height: 34px;
+ height: 28px;
cursor: pointer;
margin: 0;
.env-name {
- font-size: ${(props) => props.theme.font.size.sm};
+ font-size: ${(props) => props.theme.font.size.base};
color: ${(props) => props.theme.text};
min-width: 0;
}
diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/index.js
index ab038a433f..bac6ff4992 100644
--- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/index.js
+++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/GenerateDocumentation/index.js
@@ -189,7 +189,7 @@ const GenerateDocumentation = ({ onClose, collectionUid }) => {
handleCancel={onClose}
confirmDisabled={isLoading}
>
-
+
{isLoading ? (
@@ -215,7 +215,7 @@ const GenerateDocumentation = ({ onClose, collectionUid }) => {
-
+
{environments.length > 0 && (
diff --git a/tests/collection/generate-docs/generate-docs.spec.ts b/tests/collection/generate-docs/generate-docs.spec.ts
index dbc2c48200..edc8c8ece5 100644
--- a/tests/collection/generate-docs/generate-docs.spec.ts
+++ b/tests/collection/generate-docs/generate-docs.spec.ts
@@ -164,7 +164,7 @@ test.describe('Generate Documentation', () => {
await expect(modal).toBeHidden();
});
- test('shows the current collection version formatted as a v-prefixed semver', async ({
+ test('shows the collection name alongside the raw collection version', async ({
pageWithUserData: page
}) => {
const locators = buildCommonLocators(page);
@@ -176,13 +176,18 @@ test.describe('Generate Documentation', () => {
const modal = locators.generateDocs.modal();
await expect(modal).toBeVisible();
- // The fixture's bruno.json version ("1") is normalised for display to "v1.0.0".
- await expect(locators.generateDocs.versionInfo()).toContainText('Collection Version:');
- await expect(locators.generateDocs.versionValue()).toHaveText('v1.0.0');
+ await expect(locators.generateDocs.collectionName()).toHaveText(COLLECTION_NAME);
+
+ // The version is shown exactly as the collection sets it.
+ await expect(locators.generateDocs.versionValue()).toHaveText('version : 1');
// The fixture has 2 folders (Zoo, Aviary) and 5 requests (Lion, Bear, Parrot,
// ReqAlpha, ReqBeta), counted recursively across the whole tree.
- await expect(locators.generateDocs.versionCounts()).toHaveText('2 Folders • 5 requests');
+ await expect(locators.generateDocs.versionCounts()).toContainText('2 Folders');
+ await expect(locators.generateDocs.versionCounts()).toContainText('5 requests');
+
+ // This collection has environments, so the "0 environments" hint is not shown.
+ await expect(locators.generateDocs.versionCounts()).not.toContainText('environments');
await locators.generateDocs.cancelButton().click();
await expect(modal).toBeHidden();
diff --git a/tests/utils/page/locators.ts b/tests/utils/page/locators.ts
index c0b30d4d03..8ee6f3a30c 100644
--- a/tests/utils/page/locators.ts
+++ b/tests/utils/page/locators.ts
@@ -163,8 +163,9 @@ export const buildCommonLocators = (page: Page) => ({
heading: () => page.locator('.bruno-modal').getByText('Interactive API Documentation'),
generateButton: () => page.locator('.bruno-modal').getByRole('button', { name: 'Generate', exact: true }),
cancelButton: () => page.locator('.bruno-modal').getByRole('button', { name: 'Cancel', exact: true }),
- // Collection version (read-only) display
+ // Collection name + version (read-only) display
versionInfo: () => page.locator('.bruno-modal').getByTestId('version-info'),
+ collectionName: () => page.locator('.bruno-modal').getByTestId('collection-name'),
versionValue: () => page.locator('.bruno-modal').getByTestId('version-value'),
versionCounts: () => page.locator('.bruno-modal').getByTestId('version-summary'),
// Environment selection list