Skip to content

feat: documentation to be opened alongside params/auth/headers/body #4586

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
@@ -1,8 +1,105 @@
import styled from 'styled-components';

const StyledWrapper = styled.div`
display: flex;
flex-direction: column;
height: 100%;
background-color: #1e1e1e;
color: white;

.editing-mode {
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
border-radius: 4px;

&:hover {
background-color: rgba(255, 255, 255, 0.1);
}
}

.docs-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px;
background-color: #222;
border-bottom: 1px solid #333;
color: white;
font-size: 16px;
font-weight: 500;

.close-button {
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: none;
width: 24px;
height: 24px;
border-radius: 3px;
color: white;
cursor: pointer;

&:hover {
background-color: rgba(255, 255, 255, 0.1);
}
}
}

.docs-footer {
display: flex;
justify-content: flex-end;
padding: 12px 16px;
background-color: #222;
border-top: 1px solid #333;

.save-button {
background-color: #3d81df;
color: white;
border: none;
border-radius: 4px;
padding: 6px 20px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: background-color 0.2s;

&:hover {
background-color: #2d71cf;
}
}
}

.editor-container {
display: flex;
flex-direction: column;
height: 100%;

.CodeMirror {
height: 100%;
font-family: monospace;
background-color: #1e1e1e;
color: #d4d4d4;

.CodeMirror-gutters {
background-color: #1e1e1e;
border-right: 1px solid #333;
}

.CodeMirror-linenumber {
color: #858585;
}
}
}

.markdown-container {
line-height: 1.5;
padding: 16px;
color: #d4d4d4;
}
`;

Expand Down
62 changes: 57 additions & 5 deletions packages/bruno-app/src/components/Documentation/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { saveRequest } from 'providers/ReduxStore/slices/collections/actions';
import Markdown from 'components/MarkDown';
import CodeEditor from 'components/CodeEditor';
import StyledWrapper from './StyledWrapper';
import { IconEdit, IconX, IconFileText } from '@tabler/icons';

const Documentation = ({ item, collection }) => {
const dispatch = useDispatch();
Expand All @@ -30,19 +31,53 @@ const Documentation = ({ item, collection }) => {
);
};

const onSave = () => dispatch(saveRequest(item.uid, collection.uid));
const handleDiscardChanges = () => {
dispatch(
updateRequestDocs({
itemUid: item.uid,
collectionUid: collection.uid,
docs: docs
})
);
toggleViewMode();
};

const onSave = () => {
dispatch(saveRequest(item.uid, collection.uid));
toggleViewMode();
};

if (!item) {
return null;
}

return (
<StyledWrapper className="flex flex-col gap-y-1 h-full w-full relative">
<div className="editing-mode" role="tab" onClick={toggleViewMode}>
{isEditing ? 'Preview' : 'Edit'}
<StyledWrapper className="flex flex-col h-full w-full relative">
<div className="docs-header">
<div className="flex items-center">
<IconFileText size={20} strokeWidth={1.5} />
<span className="ml-2">Documentation</span>
</div>
<div className="flex items-center">
{isEditing ? (
<button
className="close-button"
onClick={handleDiscardChanges}
title="Close"
>
<IconX size={18} strokeWidth={1.5} />
</button>
) : (
<div className="editing-mode" role="tab" onClick={toggleViewMode} title="Edit">
<IconEdit className="cursor-pointer" size={18} strokeWidth={1.5} />
</div>
)}
</div>
</div>

{isEditing ? (
<>
<div className="flex-1 editor-container">
<CodeEditor
collection={collection}
theme={displayedTheme}
Expand All @@ -52,9 +87,26 @@ const Documentation = ({ item, collection }) => {
onEdit={onEdit}
onSave={onSave}
mode="application/text"
/>
lineNumbers={true}
/>
</div>
<div className="docs-footer">
<button
className="save-button"
onClick={onSave}
>
Save
</button>
</div>
</>
) : (
<div className="markdown-container flex-1 overflow-auto">
{docs?.length > 0 ? (
<Markdown collectionPath={collection.pathname} onDoubleClick={toggleViewMode} content={docs} />
) : (
<div className="text-gray-400 italic p-2">No documentation available. Click the edit button to add documentation.</div>
)}
</div>
)}
</StyledWrapper>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ const Wrapper = styled.div`
position: relative;
display: inline-block;
cursor: pointer;

&.active svg {
color: ${(props) => props.theme.colors.text.yellow} !important;
}
}

.infotip:hover .infotiptext {
Expand Down
21 changes: 19 additions & 2 deletions packages/bruno-app/src/components/RequestPane/QueryUrl/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import { requestUrlChanged, updateRequestMethod } from 'providers/ReduxStore/sli
import { saveRequest } from 'providers/ReduxStore/slices/collections/actions';
import HttpMethodSelector from './HttpMethodSelector';
import { useTheme } from 'providers/Theme';
import { IconDeviceFloppy, IconArrowRight, IconCode } from '@tabler/icons';
import { IconDeviceFloppy, IconArrowRight, IconCode, IconBook } from '@tabler/icons';
import SingleLineEditor from 'components/SingleLineEditor';
import { isMacOS } from 'utils/common/platform';
import StyledWrapper from './StyledWrapper';
import GenerateCodeItem from 'components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/index';
import toast from 'react-hot-toast';

const QueryUrl = ({ item, collection, handleRun }) => {
const QueryUrl = ({ item, collection, handleRun, showDocsPanel, toggleDocsPanel }) => {
const { theme, storedTheme } = useTheme();
const dispatch = useDispatch();
const method = item.draft ? get(item, 'draft.request.method') : get(item, 'request.method');
Expand Down Expand Up @@ -102,6 +102,23 @@ const QueryUrl = ({ item, collection, handleRun }) => {
item={item}
/>
<div className="flex items-center h-full mr-2 cursor-pointer" id="send-request" onClick={handleRun}>
<div
className={`infotip mr-3 ${showDocsPanel ? 'active' : ''}`}
onClick={(e) => {
e.stopPropagation();
toggleDocsPanel();
}}
>
<IconBook
color={showDocsPanel ? theme.colors.text.yellow : theme.requestTabs.icon.color}
strokeWidth={1.5}
size={22}
className="cursor-pointer"
/>
<span className="infotiptext text-xs">
Documentation
</span>
</div>
<div
className="infotip mr-3"
onClick={(e) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,23 @@ const StyledWrapper = styled.div`
}
}

.docs-toggle {
color: ${(props) => props.theme.textLink};
&:hover {
background-color: ${(props) => props.theme.dropdown.hoverBg};
}
}

section.docs-pane {
width: 350px;
min-width: 350px;
height: 100%;
border-left: 1px solid #333;
display: flex;
flex-direction: column;
background-color: #1e1e1e;
}

div.graphql-docs-explorer-container {
background: white;
outline: none;
Expand Down
38 changes: 29 additions & 9 deletions packages/bruno-app/src/components/RequestTabPanel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import RunnerResults from 'components/RunnerResults';
import VariablesEditor from 'components/VariablesEditor';
import CollectionSettings from 'components/CollectionSettings';
import { DocExplorer } from '@usebruno/graphql-docs';
import Documentation from 'components/Documentation/index';
import { IconBook, IconX } from '@tabler/icons';

import StyledWrapper from './StyledWrapper';
import SecuritySettings from 'components/SecuritySettings';
Expand All @@ -30,6 +32,7 @@ import { closeTabs } from 'providers/ReduxStore/slices/tabs';
const MIN_LEFT_PANE_WIDTH = 300;
const MIN_RIGHT_PANE_WIDTH = 350;
const DEFAULT_PADDING = 5;
const DOCS_PANEL_WIDTH = 350;

const RequestTabPanel = () => {
if (typeof window == 'undefined') {
Expand All @@ -41,6 +44,8 @@ const RequestTabPanel = () => {
const focusedTab = find(tabs, (t) => t.uid === activeTabUid);
const { globalEnvironments, activeGlobalEnvironmentUid } = useSelector((state) => state.globalEnvironments);
const _collections = useSelector((state) => state.collections.collections);
const [showDocsPanel, setShowDocsPanel] = useState(false);
const toggleDocsPanel = () => setShowDocsPanel(!showDocsPanel);

// merge `globalEnvironmentVariables` into the active collection and rebuild `collections` immer proxy object
let collections = produce(_collections, (draft) => {
Expand All @@ -62,10 +67,13 @@ const RequestTabPanel = () => {

const screenWidth = useSelector((state) => state.app.screenWidth);
let asideWidth = useSelector((state) => state.app.leftSidebarWidth);

const adjustedScreenWidth = showDocsPanel ? screenWidth - DOCS_PANEL_WIDTH : screenWidth;

const [leftPaneWidth, setLeftPaneWidth] = useState(
focusedTab && focusedTab.requestPaneWidth ? focusedTab.requestPaneWidth : (screenWidth - asideWidth) / 2.2
focusedTab && focusedTab.requestPaneWidth ? focusedTab.requestPaneWidth : (adjustedScreenWidth - asideWidth) / 2.2
); // 2.2 so that request pane is relatively smaller
const [rightPaneWidth, setRightPaneWidth] = useState(screenWidth - asideWidth - leftPaneWidth - DEFAULT_PADDING);
const [rightPaneWidth, setRightPaneWidth] = useState(adjustedScreenWidth - asideWidth - leftPaneWidth - DEFAULT_PADDING);
const [dragging, setDragging] = useState(false);

// Not a recommended pattern here to have the child component
Expand All @@ -85,26 +93,26 @@ const RequestTabPanel = () => {
};

useEffect(() => {
const leftPaneWidth = (screenWidth - asideWidth) / 2.2;
const leftPaneWidth = (adjustedScreenWidth - asideWidth) / 2.2;
setLeftPaneWidth(leftPaneWidth);
}, [screenWidth]);
}, [adjustedScreenWidth]);

useEffect(() => {
setRightPaneWidth(screenWidth - asideWidth - leftPaneWidth - DEFAULT_PADDING);
}, [screenWidth, asideWidth, leftPaneWidth]);
setRightPaneWidth(adjustedScreenWidth - asideWidth - leftPaneWidth - DEFAULT_PADDING);
}, [adjustedScreenWidth, asideWidth, leftPaneWidth]);

const handleMouseMove = (e) => {
if (dragging) {
e.preventDefault();
let leftPaneXPosition = e.clientX + 2;
if (
leftPaneXPosition < asideWidth + DEFAULT_PADDING + MIN_LEFT_PANE_WIDTH ||
leftPaneXPosition > screenWidth - MIN_RIGHT_PANE_WIDTH
leftPaneXPosition > (adjustedScreenWidth - MIN_RIGHT_PANE_WIDTH)
) {
return;
}
setLeftPaneWidth(leftPaneXPosition - asideWidth);
setRightPaneWidth(screenWidth - e.clientX - DEFAULT_PADDING);
setRightPaneWidth(adjustedScreenWidth - e.clientX - DEFAULT_PADDING);
}
};
const handleMouseUp = (e) => {
Expand Down Expand Up @@ -203,7 +211,13 @@ const RequestTabPanel = () => {
return (
<StyledWrapper className={`flex flex-col flex-grow relative ${dragging ? 'dragging' : ''}`}>
<div className="pt-4 pb-3 px-4">
<QueryUrl item={item} collection={collection} handleRun={handleRun} />
<QueryUrl
item={item}
collection={collection}
handleRun={handleRun}
showDocsPanel={showDocsPanel}
toggleDocsPanel={toggleDocsPanel}
/>
</div>
<section className="main flex flex-grow pb-4 relative">
<section className="request-pane">
Expand Down Expand Up @@ -237,6 +251,12 @@ const RequestTabPanel = () => {
<section className="response-pane flex-grow">
<ResponsePane item={item} collection={collection} rightPaneWidth={rightPaneWidth} response={item.response} />
</section>

{showDocsPanel && (
<section className="docs-pane">
<Documentation item={item} collection={collection} />
</section>
)}
</section>

{item.type === 'graphql-request' ? (
Expand Down