Skip to content
Merged
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
Expand Up @@ -36,9 +36,6 @@ import { StyledWrapper } from './StyledWrapper';

const ORIENTATION_BREAKPOINT = 640;

// The applied-guard key combines request + example so switching examples under
// the same request still re-applies, while a null example collapses to the bare
// request slug (matching what handleNavigate / openEnvironments store).
const applyKey = (requestSlug: string | null, exampleSlug: string | null): string =>
exampleSlug ? `${requestSlug} ${exampleSlug}` : requestSlug ?? '';

Expand Down Expand Up @@ -85,8 +82,7 @@ const PlaygroundBody: React.FC<PlaygroundBodyProps> = ({
() => findItemByUuid(collection?.items, selectedItemId),
[collection, selectedItemId]
);
// In example mode only the example row is active; do not also light up its
// parent request row (selectedItemId still points at the parent request).

const activeSlug = viewMode !== 'example' && selectedItemId ? uuidToSlug.get(selectedItemId) ?? '' : '';

const exampleCount =
Expand All @@ -105,18 +101,12 @@ const PlaygroundBody: React.FC<PlaygroundBodyProps> = ({
useResizableSidebar('oc-docs:playgroundSidebarWidth', onCloseSidebar, onOpenSidebar);
const orientation = viewWidth > 0 && viewWidth < ORIENTATION_BREAKPOINT ? 'vertical' : 'horizontal';

// Close the inline-dock overlay when the pointer goes down anywhere outside
// the sidebar, including outside the playground. The backdrop still handles
// clicks over the view (so they don't reach a control underneath); this adds
// the rest of the page. The toggle is excluded so closing via it isn't undone
// by its own click reopening the sidebar; the resize handle sits just outside
// the sidebar too, so grabbing it must not dismiss the overlay mid-drag.
const sidebarRef = useRef<HTMLElement>(null);
useClickOutside(
sidebarRef,
onCloseSidebar,
sidebarOpen && dock === 'inline',
'[data-testid="playground-sidebar-toggle"], [data-testid="playground-sidebar-resizer"]'
'[data-testid="playground-sidebar-toggle"], [data-testid="playground-sidebar-resizer"], [data-tippy-root]'
);

// Reopen whatever the URL says was last open. `pgReq` holds a request, a
Expand All @@ -126,15 +116,8 @@ const PlaygroundBody: React.FC<PlaygroundBodyProps> = ({
const key = applyKey(requestSlug, exampleSlug);
if (!requestSlug || appliedSlugRef.current === key) return;
const target = resolvePlaygroundTarget(requestSlug, model);
if (!target) return; // sidebar list hasn't loaded this item yet - retry once it does
// A request or folder needs the playground's own copy of the collection to
// select it and open its parent folders. On reload that copy can arrive just
// after the sidebar list, so if it isn't ready we wait instead of marking
// this done - otherwise the folders would never open. The environments and
// collection views need no collection, so they open right away.
if (!target) return;
if (target.uuid && !collection?.items) return;
// Resolve the URL's example against the request; an unmatched slug (renamed/
// removed) leaves the example unset so we open the live request instead.
const item = target.uuid ? findItemByUuid(collection?.items, target.uuid) : undefined;
const exampleIndex =
exampleSlug && item && !isFolder(item) ? exampleIndexForSlug(item as HttpRequest, exampleSlug) : null;
Expand All @@ -145,20 +128,13 @@ const PlaygroundBody: React.FC<PlaygroundBodyProps> = ({
if (target.expandUuids.length) dispatch(expandFolders(target.expandUuids));
}, [requestSlug, exampleSlug, model, collection, dispatch, appliedSlugRef]);

// In the inline dock the sidebar is an overlay, so close it once the user has
// picked something to view (mirrors a mobile navigation drawer).
const closeSidebarIfInline = () => {
if (dock === 'inline') onCloseSidebar();
};

// A sidebar click applies the target right away, then writes the slug so a
// reload restores it. Applying directly (not only through the reopen effect) is
// what makes leaving an example work: an example keeps the slug on its parent
// request, so clicking that request is a no-op slug write and the effect would
// never fire. appliedSlugRef is synced so the effect treats it as already done.
const handleNavigate = (slug: string) => {
const target = resolvePlaygroundTarget(slug, model);
if (!target || !target.uuid) return; // not a resolvable item, ignore the click
if (!target || !target.uuid) return;
dispatch(setSelectedItemId(target.uuid));
dispatch(setSelectedExampleIndex(null));
dispatch(setViewMode(target.view));
Expand All @@ -171,9 +147,6 @@ const PlaygroundBody: React.FC<PlaygroundBodyProps> = ({
const handleToggleFolder = (uuid: string) => dispatch(toggleFolderCollapse(uuid));
const handleExpandFolder = (uuid: string) => dispatch(expandFolders([uuid]));

// An example is applied directly and its slug written to the URL (pgReq+pgEx),
// so a reload / share restores it. Mark the combined key applied first so the
// reopen effect treats it as done and doesn't re-run.
const handleExampleClick = (requestUuid: string, index: number) => {
dispatch(setSelectedItemId(requestUuid));
dispatch(setSelectedExampleIndex(index));
Expand Down Expand Up @@ -226,8 +199,6 @@ const PlaygroundBody: React.FC<PlaygroundBodyProps> = ({
return <ExampleView request={selectedItem as HttpRequest} example={example} orientation={orientation} />;
}
}
// Also render the live request when an example index no longer resolves (e.g.
// the examples array shrank), so we never land on the empty prompt instead.
if ((viewMode === 'playground' || viewMode === 'example') && selectedItem && !isFolder(selectedItem) && collection) {
return (
<PlaygroundView
Expand All @@ -248,8 +219,6 @@ const PlaygroundBody: React.FC<PlaygroundBodyProps> = ({
style={{ '--sidebar-width': `${sidebarWidth}px` } as React.CSSProperties}
>
{sidebarOpen && dock === 'inline' && (
// In the inline dock the sidebar overlays the view, so a click outside it
// dismisses it, same as the docs navigation drawer's backdrop.
<div
className="sidebar-backdrop"
data-testid="playground-sidebar-backdrop"
Expand Down
Loading