Skip to content

Commit

Permalink
Merge branch 'main' into fix/2419-sibling-examples-ref
Browse files Browse the repository at this point in the history
  • Loading branch information
chohmann authored Dec 15, 2023
2 parents df9d8bc + 43b8ff6 commit 8a41d06
Show file tree
Hide file tree
Showing 11 changed files with 244 additions and 19 deletions.
2 changes: 1 addition & 1 deletion demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"type-check": "tsc --noEmit"
},
"dependencies": {
"@stoplight/elements": "^7.15.3",
"@stoplight/elements": "^7.16.0",
"@stoplight/mosaic": "^1.46.1",
"history": "^5.0.0",
"react": "16.14.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/elements-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@stoplight/elements-core",
"version": "7.15.2",
"version": "7.16.0",
"sideEffects": [
"web-components.min.js",
"src/web-components/**",
Expand Down
103 changes: 102 additions & 1 deletion packages/elements-core/src/__fixtures__/operations/put-todos.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HttpParamStyles, IHttpOperation } from '@stoplight/types';
import { HttpOperationSecurityDeclarationTypes, HttpParamStyles, IHttpOperation } from '@stoplight/types';

export const httpOperation: IHttpOperation = {
id: '?http-operation-id?',
Expand Down Expand Up @@ -522,6 +522,107 @@ export const httpOperation: IHttpOperation = {
},
],
},
callbacks: [
{
key: 'newPet',
extensions: {},
id: '3245690b6a7fc',
method: 'post',
path: '{$request.body#/newPetAvailableUrl}',
request: {
body: {
description: 'Callback body description',
contents: [
{
encodings: [],
examples: [],
id: 'abc',
mediaType: 'application/json',
schema: {
$schema: 'http://json-schema.org/draft-07/schema#',
properties: {
message: {
examples: ['A new pet has arrived'],
type: 'string',
},
},
required: ['message'],
type: 'object',
},
},
],
id: 'abc',
required: true,
},
cookie: [],
headers: [],
path: [],
query: [],
},
responses: [
{
code: '200',
contents: [],
description: 'Your server returns this code if it accepts the callback',
headers: [],
id: 'abc',
},
],
security: [],
securityDeclarationType: HttpOperationSecurityDeclarationTypes.InheritedFromService,
servers: [],
tags: [],
},
{
key: 'returnedPet',
extensions: {},
id: '07041d5723f4a',
method: 'post',
path: '{$request.body#/returnedPetAvailableUrl}',
request: {
body: {
contents: [
{
encodings: [],
examples: [],
id: 'abc',
mediaType: 'application/json',
schema: {
$schema: 'http://json-schema.org/draft-07/schema#',
properties: {
message: {
examples: ['A pet has been returned'],
type: 'string',
},
},
required: ['message'],
type: 'object',
},
},
],
id: 'abc',
required: true,
},
cookie: [],
headers: [],
path: [],
query: [],
},
responses: [
{
code: '200',
contents: [],
description: 'Your server returns this code if it accepts the callback',
headers: [],
id: 'abc',
},
],
security: [],
securityDeclarationType: HttpOperationSecurityDeclarationTypes.InheritedFromService,
servers: [],
tags: [],
},
],
tags: [
{
id: '?http-tags-todos?',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { SectionSubtitle } from '../Sections';

export interface BodyProps {
body: IHttpOperationRequestBody;
onChange: (requestBodyIndex: number) => void;
onChange?: (requestBodyIndex: number) => void;
}

export const isBodyEmpty = (body?: BodyProps['body']) => {
Expand All @@ -29,7 +29,7 @@ export const Body = ({ body, onChange }: BodyProps) => {
const { nodeHasChanged } = useOptionsCtx();

React.useEffect(() => {
onChange(chosenContent);
onChange?.(chosenContent);
// disabling because we don't want to react on `onChange` change
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [chosenContent]);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { Box, Flex, NodeAnnotation, Select, VStack } from '@stoplight/mosaic';
import { IHttpCallbackOperation } from '@stoplight/types';
import * as React from 'react';

import { useOptionsCtx } from '../../../context/Options';
import { MarkdownViewer } from '../../MarkdownViewer';
import { SectionSubtitle, SectionTitle } from '../Sections';
import { OperationHeader } from './HttpOperation';
import { Request } from './Request';
import { Responses } from './Responses';

export interface CallbacksProps {
callbacks: IHttpCallbackOperation[];
isCompact?: boolean;
}

export interface CallbackProps {
data: IHttpCallbackOperation;
isCompact?: boolean;
}

export const Callbacks = ({ callbacks, isCompact }: CallbacksProps) => {
const [selectedCallbackIndex, setSelectedCallbackIndex] = React.useState(0);

const callback = React.useMemo(() => callbacks[selectedCallbackIndex], [callbacks, selectedCallbackIndex]);

return (
<VStack spacing={8}>
<SectionTitle title="Callbacks" isCompact={isCompact}>
{callbacks.length > 0 && (
<Flex flex={1} justify="end">
<Select
aria-label="Callback"
value={String(selectedCallbackIndex)}
onChange={value => setSelectedCallbackIndex(parseInt(String(value), 10))}
options={callbacks.map((c, index) => ({
label: `${c.key} - ${c.path} - ${c.method}`,
value: index,
}))}
size="sm"
/>
</Flex>
)}
</SectionTitle>

{callback && <Callback data={callback} isCompact={isCompact} />}
</VStack>
);
};

Callbacks.displayName = 'HttpOperation.Callbacks';

export const Callback = ({ data, isCompact }: CallbackProps) => {
const { nodeHasChanged } = useOptionsCtx();

const isDeprecated = !!data.deprecated;
const isInternal = !!data.internal;

const descriptionChanged = nodeHasChanged?.({ nodeId: data.id, attr: 'description' });

return (
<VStack spacing={10}>
<Box>
<SectionSubtitle title={data.key} id="callback-key"></SectionSubtitle>
<OperationHeader
id={data.id}
method={data.method}
path={`/${data.path}`}
isDeprecated={isDeprecated}
isInternal={isInternal}
/>
</Box>
{data.description && (
<Box pos="relative">
<MarkdownViewer className="HttpOperation__Description" markdown={data.description} />
<NodeAnnotation change={descriptionChanged} />
</Box>
)}

<Request operation={data} />

{data.responses && <Responses responses={data.responses} isCompact={isCompact} />}
</VStack>
);
};
Callbacks.displayName = 'HttpOperation.Callback';
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ describe('HttpOperation', () => {

expect(serversButton).toHaveTextContent('PR');

expect(screen.queryByText(/{proto}:\/\/x-{pr}.todos-pr.stoplight.io:{port}/)).toBeInTheDocument();
expect(screen.queryAllByText(/{proto}:\/\/x-{pr}.todos-pr.stoplight.io:{port}/)[0]).toBeInTheDocument();
unmount();
});
});
Expand Down Expand Up @@ -617,6 +617,41 @@ describe('HttpOperation', () => {
});
});

describe('Callbacks', () => {
it('should display callback operation', async () => {
const { unmount } = render(<HttpOperation data={{ ...httpOperation, deprecated: false }} />);

//operation name
expect(screen.queryByText('newPet')).toBeInTheDocument();

// operation header
expect(screen.queryByText('/{$request.body#/newPetAvailableUrl}')).toBeInTheDocument();

// operation body
expect(screen.queryByText('Callback body description')).toBeInTheDocument();

// operation response
expect(screen.queryByText('Your server returns this code if it accepts the callback')).toBeInTheDocument();

unmount();
});
it('should display callback selector and switch between events', () => {
const { unmount } = render(<HttpOperation data={{ ...httpOperation, deprecated: false }} />);

const select = screen.getByLabelText('Callback');

expect(select).toHaveTextContent('newPet - {$request.body#/newPetAvailableUrl} - post');

chooseOption(select, 'returnedPet - {$request.body#/returnedPetAvailableUrl} - post');

expect(select).toHaveTextContent('returnedPet - {$request.body#/returnedPetAvailableUrl} - post');

expect(screen.queryByText('returnedPet')).toBeInTheDocument();

unmount();
});
});

describe('Visibility', () => {
it('should hide TryIt', async () => {
const { unmount } = render(<HttpOperation data={httpOperation} layoutOptions={{ hideTryIt: true }} />);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { chosenServerAtom, TryItWithRequestSamples } from '../../TryIt';
import { DocsComponentProps } from '..';
import { TwoColumnLayout } from '../TwoColumnLayout';
import { DeprecatedBadge, InternalBadge } from './Badges';
import { Callbacks } from './Callbacks';
import { Request } from './Request';
import { Responses } from './Responses';

Expand Down Expand Up @@ -84,6 +85,8 @@ const HttpOperationComponent = React.memo<HttpOperationProps>(
/>
)}

{data.callbacks?.length && <Callbacks callbacks={data.callbacks} isCompact={isCompact} />}

{isCompact && tryItPanel}
</VStack>
);
Expand Down Expand Up @@ -170,7 +173,7 @@ function MethodPathInner({ method, path, chosenServerUrl }: MethodPathProps & {
);
}

function OperationHeader({
export function OperationHeader({
id,
noHeading,
hasBadges,
Expand All @@ -182,8 +185,8 @@ function OperationHeader({
}: {
id: string;
noHeading?: boolean;
hasBadges: boolean;
name: string;
hasBadges?: boolean;
name?: string;
isDeprecated?: boolean;
isInternal?: boolean;
method: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { Parameters } from './Parameters';

interface IRequestProps {
operation: IHttpOperation;
onChange: (requestBodyIndex: number) => void;
onChange?: (requestBodyIndex: number) => void;
}

export const Request: React.FunctionComponent<IRequestProps> = ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ import { Parameters } from './Parameters';

interface ResponseProps {
response: IHttpOperationResponse;
onMediaTypeChange(mediaType: string): void;
onMediaTypeChange?: (mediaType: string) => void;
}

interface ResponsesProps {
responses: IHttpOperationResponse[];
onMediaTypeChange(mediaType: string): void;
onStatusCodeChange(statusCode: string): void;
onMediaTypeChange?: (mediaType: string) => void;
onStatusCodeChange?: (statusCode: string) => void;
isCompact?: boolean;
}

Expand Down Expand Up @@ -70,7 +70,7 @@ export const Responses = ({
);

React.useEffect(() => {
onStatusCodeChange(activeResponseId);
onStatusCodeChange?.(activeResponseId);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [activeResponseId]);

Expand Down Expand Up @@ -172,7 +172,7 @@ const Response = ({ response, onMediaTypeChange }: ResponseProps) => {
const schema = responseContent?.schema;

React.useEffect(() => {
responseContent && onMediaTypeChange(responseContent.mediaType);
responseContent && onMediaTypeChange?.(responseContent.mediaType);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [responseContent]);

Expand Down
4 changes: 2 additions & 2 deletions packages/elements-dev-portal/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@stoplight/elements-dev-portal",
"version": "1.18.1",
"version": "1.19.0",
"description": "UI components for composing beautiful developer documentation.",
"keywords": [],
"sideEffects": [
Expand Down Expand Up @@ -64,7 +64,7 @@
]
},
"dependencies": {
"@stoplight/elements-core": "~7.15.1",
"@stoplight/elements-core": "~7.16.0",
"@stoplight/markdown-viewer": "^5.5.0",
"@stoplight/mosaic": "^1.46.1",
"@stoplight/path": "^1.3.2",
Expand Down
Loading

0 comments on commit 8a41d06

Please sign in to comment.