Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion packages/oc-docs/e2e/collection-docs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,22 @@ test.describe('Collection-level documentation', () => {

test('renders markdown headings', async ({ page }) => {
const docs = page.locator('.collection-docs');
await expect(docs.getByRole('heading', { name: 'Bruno Testbench', level: 1 })).toBeVisible();
await expect(docs.getByRole('heading', { name: 'Getting Started', level: 2 })).toBeVisible();
await expect(docs.getByRole('heading', { name: 'Authentication', level: 2 })).toBeVisible();
await expect(docs.getByRole('heading', { name: 'Rate Limits', level: 2 })).toBeVisible();
});

test('renders collection name as page header above docs', async ({ page }) => {
const heading = page
.locator('.playground-content')
.getByRole('heading', { name: 'Bruno Testbench', level: 1 });
await expect(heading).toBeVisible();

const headingBox = await heading.boundingBox();
const docsBox = await page.locator('.collection-docs').boundingBox();
expect(headingBox!.y).toBeLessThan(docsBox!.y);
});

test('renders markdown paragraphs with inline formatting', async ({ page }) => {
const docs = page.locator('.collection-docs');
await expect(docs.getByText('comprehensive API collection for testing')).toBeVisible();
Expand Down
25 changes: 25 additions & 0 deletions packages/oc-docs/src/components/Docs/Docs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import type { OpenCollection as OpenCollectionCollection } from '@opencollection
import type { StructuredText } from '@opencollection/types/common/description';
import Sidebar from './Sidebar/Sidebar';
import Item from './Item/Item';
import FetchInBrunoButton from './Sidebar/FetchInBrunoButton';
import { getItemId, generateSafeId } from '../../utils/itemUtils';
import { isFolder } from '../../utils/schemaHelpers';
import { useAppSelector, useAppDispatch } from '../../store/hooks';
import { selectSelectedItemId, selectItem } from '../../store/slices/docs';
import { selectGitCollectionUrl } from '../../store/slices/app';
import { useMarkdownRenderer } from '../../hooks';

interface DocsProps {
Expand All @@ -22,6 +24,7 @@ const Docs: React.FC<DocsProps> = ({
}) => {
const dispatch = useAppDispatch();
const selectedItemId = useAppSelector(selectSelectedItemId);
const gitCollectionUrl = useAppSelector(selectGitCollectionUrl);
const md = useMarkdownRenderer();
const isInitialMount = useRef(true);

Expand Down Expand Up @@ -112,6 +115,28 @@ const Docs: React.FC<DocsProps> = ({
className="playground-content h-full overflow-y-auto flex-1"
>
<div className="all-endpoints-view h-full overflow-y-auto" style={{ padding: '2rem', maxWidth: '100%' }}>
{docsCollection?.info?.name && (
<div
className="flex items-center gap-3 mb-6"
style={{ maxWidth: '80rem' }}
>
<h1
className="text-2xl font-semibold truncate"
style={{ color: 'var(--text-primary)' }}
>
{docsCollection.info.name}
</h1>
{gitCollectionUrl && (
<a
href={`bruno://app/collection/import/git?url=${encodeURIComponent(gitCollectionUrl)}`}
className="flex-shrink-0"
>
<FetchInBrunoButton />
</a>
)}
</div>
)}

{/* Collection-level documentation/introduction */}
{docsCollection?.docs && (
<div
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from 'react';

const FetchInBrunoButton: React.FC = () => (
<svg xmlns="http://www.w3.org/2000/svg" width="142" height="36" viewBox="0 0 146 36" role="img" aria-label="Fetch in Bruno">
<rect x="2" y="2" width="142" height="32" rx="16" fill="#fffbf7" stroke="#de8116" strokeWidth="1" strokeLinejoin="round" strokeLinecap="round" />
<g transform="translate(10, 1)">
<svg width="24" viewBox="0 0 72 72" xmlns="http://www.w3.org/2000/svg">
<g>
<path fill="#F4AA41" stroke="none" d="M23.5,14.5855l-4.5,1.75l-7.25,8.5l-4.5,10.75l2,5.25c1.2554,3.7911,3.5231,7.1832,7.25,10l2.5-3.3333 c0,0,3.8218,7.7098,10.7384,8.9598c0,0,10.2616,1.936,15.5949-0.8765c3.4203-1.8037,4.4167-4.4167,4.4167-4.4167l3.4167-3.4167 l1.5833,2.3333l2.0833-0.0833l5.4167-7.25L64,37.3355l-0.1667-4.5l-2.3333-5.5l-4.8333-7.4167c0,0-2.6667-4.9167-8.1667-3.9167 c0,0-6.5-4.8333-11.8333-4.0833S32.0833,10.6688,23.5,14.5855z" />
<polygon fill="#EA5A47" stroke="none" points="36,47.2521 32.9167,49.6688 30.4167,49.6688 30.3333,53.5021 31.0833,57.0021 32.1667,58.9188 35,60.4188 39.5833,59.8355 41.1667,58.0855 42.1667,53.8355 41.9167,49.8355 39.9167,50.0855" />
<polygon fill="#3F3F3F" stroke="none" points="32.5,36.9188 30.9167,40.6688 33.0833,41.9188 34.3333,42.4188 38.6667,42.5855 41.5833,40.3355 39.8333,37.0855" />
</g>
<g>
<path fill="#000000" stroke="none" d="M29.5059,30.1088c0,0-1.8051,1.2424-2.7484,0.6679c-0.9434-0.5745-1.2424-1.8051-0.6679-2.7484 s1.805-1.2424,2.7484-0.6679S29.5059,30.1088,29.5059,30.1088z" />
<path fill="none" stroke="#000000" strokeLinecap="round" strokeLinejoin="round" strokeMiterlimit="10" strokeWidth="2" d="M33.1089,37.006h6.1457c0.4011,0,0.7634,0.2397,0.9203,0.6089l1.1579,2.7245l-2.1792,1.1456 c-0.6156,0.3236-1.3654-0.0645-1.4567-0.754" />
<path fill="none" stroke="#000000" strokeLinecap="round" strokeLinejoin="round" strokeMiterlimit="10" strokeWidth="2" d="M34.7606,40.763c-0.1132,0.6268-0.7757,0.9895-1.3647,0.7471l-2.3132-0.952l1.0899-2.9035 c0.1465-0.3901,0.5195-0.6486,0.9362-0.6486" />
<path fill="none" stroke="#000000" strokeLinecap="round" strokeLinejoin="round" strokeMiterlimit="10" strokeWidth="2" d="M30.4364,50.0268c0,0-0.7187,8.7934,3.0072,9.9375c2.6459,0.8125,5.1497,0.5324,6.0625-0.25 c0.875-0.75,2.6323-4.4741,1.8267-9.6875" />
<path fill="#000000" stroke="none" d="M44.2636,30.1088c0,0,1.805,1.2424,2.7484,0.6679c0.9434-0.5745,1.2424-1.8051,0.6679-2.7484 c-0.5745-0.9434-1.805-1.2424-2.7484-0.6679C43.9881,27.9349,44.2636,30.1088,44.2636,30.1088z" />
<path fill="none" stroke="#000000" strokeLinecap="round" strokeLinejoin="round" strokeMiterlimit="10" strokeWidth="2" d="M25.6245,42.8393c-0.475,3.6024,2.2343,5.7505,4.2847,6.8414c1.1968,0.6367,2.6508,0.5182,3.7176-0.3181l2.581-2.0233l2.581,2.0233 c1.0669,0.8363,2.5209,0.9548,3.7176,0.3181c2.0504-1.0909,4.7597-3.239,4.2847-6.8414" />
<path fill="none" stroke="#000000" strokeLinecap="round" strokeLinejoin="round" strokeMiterlimit="10" strokeWidth="2" d="M19.9509,28.3572c-2.3166,5.1597-0.5084,13.0249,0.119,15.3759c0.122,0.4571,0.0755,0.9355-0.1271,1.3631l-1.9874,4.1937 c-0.623,1.3146-2.3934,1.5533-3.331,0.4409c-3.1921-3.7871-8.5584-11.3899-6.5486-16.686 c7.0625-18.6104,15.8677-18.1429,15.8677-18.1429c2.8453-1.9336,13.1042-6.9375,24.8125,0.875c0,0,8.6323-1.7175,14.9375,16.9375 c1.8036,5.3362-3.4297,12.8668-6.5506,16.6442c-0.9312,1.127-2.7162,0.8939-3.3423-0.4272l-1.9741-4.1656 c-0.2026-0.4275-0.2491-0.906-0.1271-1.3631c0.6275-2.3509,2.4356-10.2161,0.119-15.3759" />
<path fill="none" stroke="#000000" strokeLinecap="round" strokeLinejoin="round" strokeMiterlimit="10" strokeWidth="2" d="M52.6309,46.4628c0,0-3.0781,6.7216-7.8049,8.2712" />
<path fill="none" stroke="#000000" strokeLinecap="round" strokeLinejoin="round" strokeMiterlimit="10" strokeWidth="2" d="M19.437,46.969c0,0,3.0781,6.0823,7.8049,7.632" />
<line x1="36.2078" x2="36.2078" y1="47.3393" y2="44.3093" fill="none" stroke="#000000" strokeLinecap="round" strokeLinejoin="round" strokeMiterlimit="10" strokeWidth="2" />
</g>
</svg>
</g>
<text x="39" y="23" fontFamily="system-ui, -apple-system, sans-serif" fontSize="13" fontWeight="600" fill="#d97706">Fetch In Bruno</text>
</svg>
);

export default FetchInBrunoButton;
2 changes: 1 addition & 1 deletion packages/oc-docs/src/components/Docs/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ const Sidebar: React.FC<SidebarProps> = () => {
<SidebarContainer className="h-full flex flex-col" style={{ width: 'var(--sidebar-width)' }}>
{/* Collection name at top */}
<div className="p-4 pt-0">
<div className="flex items-center">
<div className="flex items-center gap-2">
<h1 className="font-semibold truncate flex-1" style={{ color: 'var(--text-primary)' }}>
{collection?.info?.name || 'API Collection'}
</h1>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import {
setCollectionLoading,
setCollectionSucceeded,
setCollectionFailed,
resetCollectionState
resetCollectionState,
setGitCollectionUrl
} from '@slices/app';
import { createOpenCollectionStore, type AppStore } from '../../store/store';

Expand Down Expand Up @@ -162,10 +163,12 @@ const DesktopLayout: React.FC<DesktopLayoutProps> = ({
export interface OpenCollectionProps {
collection: IOpenCollection | string | File;
logo?: React.ReactNode;
gitCollectionUrl?: string;
}

const OpenCollectionContent: React.FC<OpenCollectionProps> = ({
collection,
gitCollectionUrl,
}) => {
const dispatch = useAppDispatch();
const docsCollection = useAppSelector(selectDocsCollection);
Expand All @@ -174,6 +177,10 @@ const OpenCollectionContent: React.FC<OpenCollectionProps> = ({
const collectionError = useAppSelector(selectCollectionError);
const selectedItemId = useAppSelector((state) => state.docs.selectedItemId);

useEffect(() => {
gitCollectionUrl && dispatch(setGitCollectionUrl(gitCollectionUrl));
}, [gitCollectionUrl, dispatch]);

useEffect(() => {
let isActive = true;

Expand Down
1 change: 1 addition & 0 deletions packages/oc-docs/src/dev.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const DevApp: React.FC = () => {
<OpenCollection
collection={sampleCollectionYaml}
logo="/src/assets/opencollection-logo.svg"
gitCollectionUrl="https://github.com/usebruno/bruno-testbench.git"
/>
</div>
</Provider>
Expand Down
2 changes: 0 additions & 2 deletions packages/oc-docs/src/sampleCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ request:
token: "{{bearer_auth_token}}"
docs:
content: |
# Bruno Testbench

This is a comprehensive API collection for testing **OpenCollection** features.

## Getting Started
Expand Down
4 changes: 3 additions & 1 deletion packages/oc-docs/src/standalone.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface OpenCollectionOptions {
target: HTMLElement;
opencollection: any;
logo?: string;
gitCollectionUrl?: string;
}

export class OpenCollectionRenderer {
Expand Down Expand Up @@ -96,7 +97,8 @@ export class OpenCollectionRenderer {

this.root.render(React.createElement(OpenCollection, {
collection,
logo: this.createLogoElement()
logo: this.createLogoElement(),
gitCollectionUrl: this.options.gitCollectionUrl
}));
}

Expand Down
11 changes: 9 additions & 2 deletions packages/oc-docs/src/store/slices/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ export type CollectionStatus = 'idle' | 'loading' | 'succeeded' | 'failed';
export interface AppState {
collectionStatus: CollectionStatus;
collectionError: string | null;
gitCollectionUrl: string | null;
}

const initialState: AppState = {
collectionStatus: 'idle',
collectionError: null
collectionError: null,
gitCollectionUrl: null
};

const appSlice = createSlice({
Expand All @@ -32,6 +34,9 @@ const appSlice = createSlice({
resetCollectionState: (state: AppState) => {
state.collectionStatus = 'idle';
state.collectionError = null;
},
setGitCollectionUrl: (state: AppState, action: PayloadAction<string | null>) => {
state.gitCollectionUrl = action.payload;
}
}
});
Expand All @@ -40,11 +45,13 @@ export const {
setCollectionLoading,
setCollectionSucceeded,
setCollectionFailed,
resetCollectionState
resetCollectionState,
setGitCollectionUrl
} = appSlice.actions;
export default appSlice.reducer;

export const selectCollectionStatus = (state: RootState) => state.app.collectionStatus;
export const selectCollectionError = (state: RootState) => state.app.collectionError;
export const selectGitCollectionUrl = (state: RootState) => state.app.gitCollectionUrl;


Loading