Skip to content
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

[DEV-1040] Rendering component OpenAPI Gitbook #353

Merged
merged 55 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
df9028f
add markdoc config for swagger component
jeremygordillo Oct 26, 2023
edfc36f
swagger component
jeremygordillo Oct 26, 2023
ab26f91
add error placeholder
jeremygordillo Oct 26, 2023
16eaac5
update styles
jeremygordillo Oct 26, 2023
8bb7dc3
feat: improve SchemaWithExample component
jeremygordillo Nov 6, 2023
d390a80
Merge branch 'main' into openapi
jeremygordillo Nov 7, 2023
397ce35
refactor component & improve styling
jeremygordillo Nov 7, 2023
346fa8f
fix styles
jeremygordillo Nov 8, 2023
ad0733a
fix accordion for responses without content
jeremygordillo Nov 8, 2023
9f08008
add some comments
jeremygordillo Nov 8, 2023
c656a74
Merge branch 'main' into openapi
jeremygordillo Nov 9, 2023
6cb4577
create use-spec hook
jeremygordillo Nov 9, 2023
f395c1e
refactor & add messages
jeremygordillo Nov 9, 2023
e2a02b0
add some translations
jeremygordillo Nov 10, 2023
a852896
Fixes after code review
jeremygordillo Nov 10, 2023
72137d0
Merge branch 'main' into openapi
jeremygordillo Nov 13, 2023
e105f3c
Merge branch 'main' into openapi
jeremygordillo Nov 15, 2023
d046085
Merge branch 'main' into openapi
jeremygordillo Nov 20, 2023
1d7a25a
update package-lock.json
jeremygordillo Nov 20, 2023
b644b9a
Merge branch 'main' into openapi
jeremygordillo Nov 20, 2023
b7a4c1e
Merge branch 'main' into openapi
jeremygordillo Nov 23, 2023
2ed46da
Merge branch 'main' into openapi
jeremygordillo Nov 23, 2023
1d8d515
Merge branch 'main' into openapi
jeremygordillo Nov 24, 2023
d6f7018
Merge branch 'main' into openapi
jeremygordillo Nov 24, 2023
72ad27b
Merge branch 'main' into openapi
jeremygordillo Nov 24, 2023
61387a0
Merge branch 'main' into openapi
jeremygordillo Nov 27, 2023
42dca11
fix missing swagger-ui dependency
jeremygordillo Nov 27, 2023
ea5a4f2
add translations
jeremygordillo Nov 27, 2023
9a52585
fix harcoded messages
jeremygordillo Nov 27, 2023
f6bfed8
Merge branch 'main' into openapi
jeremygordillo Nov 29, 2023
ae5859d
fix: swagger test
jeremygordillo Nov 29, 2023
eeb6b9d
Merge branch 'main' into openapi
jeremygordillo Nov 29, 2023
96fcf72
fix: add error message for embedded api
jeremygordillo Nov 29, 2023
7279bb2
style: add margin botton
jeremygordillo Nov 29, 2023
c0091c4
fix: build swagger-ui error
jeremygordillo Nov 29, 2023
6676abc
add comments in declarations.d.ts
jeremygordillo Nov 29, 2023
9629ae2
Merge branch 'main' into openapi
jeremygordillo Nov 29, 2023
c3b89ac
Merge branch 'main' into openapi
marcobottaro Dec 1, 2023
ae1b252
fix: file names
jeremygordillo Dec 1, 2023
e5b9b1e
Merge branch 'main' into openapi
jeremygordillo Dec 1, 2023
4af1250
move eslint-disable rule
jeremygordillo Jan 11, 2024
c6d4cda
Merge branch 'main' into openapi
jeremygordillo Jan 11, 2024
c4e5c5f
fix typography color
jeremygordillo Jan 11, 2024
c450a56
Create clever-coins-call.md
jeremygordillo Jan 11, 2024
4161bce
update changeset
jeremygordillo Jan 11, 2024
b171c23
Merge branch 'main' into openapi
jeremygordillo Jan 11, 2024
ef2671c
Merge branch 'main' into openapi
marcobottaro Jan 11, 2024
b66ecad
Merge branch 'main' into openapi
jeremygordillo Jan 15, 2024
15a4668
Merge branch 'main' into openapi
MarcoPonchia Jan 16, 2024
7943183
Merge branch 'main' into openapi
MarcoPonchia Jan 25, 2024
1e919cd
Merge branch 'main' into openapi
jeremygordillo Jan 29, 2024
7894c15
Merge branch 'main' into openapi
jeremygordillo Jan 29, 2024
9761dbf
Code review suggestion (#586)
datalek Jan 31, 2024
b0732e6
update title style
jeremygordillo Jan 31, 2024
dd046c2
Merge branch 'main' into openapi
jeremygordillo Jan 31, 2024
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
6 changes: 6 additions & 0 deletions .changeset/clever-coins-call.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"nextjs-website": minor
"gitbook-docs": patch
---

[DEV-1040] Rendering component OpenAPI Gitbook
4 changes: 4 additions & 0 deletions apps/nextjs-website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"test": "jest -i"
},
"dependencies": {
"@apidevtools/swagger-parser": "^10.1.0",
"@aws-amplify/auth": "^5.6.6",
"@aws-amplify/ui-react": "^5.3.1",
"@aws-sdk/client-dynamodb": "^3.496.0",
Expand All @@ -37,6 +38,7 @@
"react": "18.2.0",
"react-dom": "18.2.0",
"react-syntax-highlighter": "^15.5.0",
"swagger-ui": "^5.9.1",
"swiper": "^10.0.3"
},
"devDependencies": {
Expand All @@ -45,11 +47,13 @@
"@types/react": "18.2.21",
"@types/react-dom": "18.2.7",
"@types/react-syntax-highlighter": "^15.5.7",
"@types/swagger-ui": "^3.52.4",
"eslint": "8.47.0",
"eslint-config-custom": "*",
"eslint-config-next": "13.4.19",
"jest": "^29.5.0",
"jest-mock-extended": "^3.0.5",
"openapi-types": "^12.1.3",
"ts-jest": "^29.1.1",
"typescript": "5.1.6"
},
Expand Down
1 change: 1 addition & 0 deletions apps/nextjs-website/src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';
import '@/styles/globals.css';
import '@/polyfill';
jeremygordillo marked this conversation as resolved.
Show resolved Hide resolved
import ThemeRegistry from './ThemeRegistry';
import { getProducts } from '@/lib/api';
import SiteFooter from '@/components/atoms/SiteFooter/SiteFooter';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import Tabs from './components/Tabs';
import Quote from './components/Quote';
import Embed from './components/Embed';
import CodeBlock from './components/CodeBlock';
import Swagger from './components/Swagger';
import Swagger from './components/Swagger/Swagger';
import PageLink from '@/components/organisms/GitBookContent/components/PageLink';
import Cards, { Card, CardItem } from './components/Cards';
import { ParseContentConfig } from 'gitbook-docs/parseContent';
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { KeyboardArrowRight } from '@mui/icons-material';
import {
Box,
Collapse,
List,
ListItemButton,
ListItemIcon,
Typography,
} from '@mui/material';
import { OpenAPIV3 } from 'openapi-types';
import { MouseEventHandler, PropsWithChildren, useState } from 'react';
import { useModelProps } from './hooks/useModel';

type ModelEntryProps = {
title?: string;
required?: boolean;
schemaType?: string;
};

type ModelItemProps = ModelEntryProps & {
description?: string;
onClick?: MouseEventHandler<HTMLDivElement>;
};

const ModelItem = ({
description,
title,
required,
schemaType,
onClick,
}: ModelItemProps) => {
const showIcon = typeof onClick === 'function';
return (
<ListItemButton
sx={{
display: 'block',
background: 'transparent!important',
py: 1,
}}
disableGutters
onClick={onClick}
>
<Box
sx={{
display: 'inline-flex',
alignItems: 'center',
flexGrow: 1,
width: '100%',
gap: 2,
}}
>
<ListItemIcon>
{showIcon && <KeyboardArrowRight sx={{ fontSize: '1.125rem' }} />}
</ListItemIcon>
{title && (
<Typography sx={{ fontWeight: 'bold' }}>
{title}
{required && (
<Typography component='span' color='red'>
*
</Typography>
)}
</Typography>
)}
<Typography sx={{ color: (theme) => theme.palette.primary.main }}>
{schemaType}
</Typography>
</Box>
<Typography sx={{ ml: 2 }}>{description}</Typography>
</ListItemButton>
);
};

const ModelListEntry = ({
title,
required,
schemaType,
children,
}: PropsWithChildren<ModelEntryProps>) => {
const [open, setOpen] = useState(false);

return (
<List disablePadding>
<ModelItem
title={title}
required={required}
schemaType={schemaType}
onClick={() => setOpen(!open)}
/>
<Collapse
sx={{ borderLeft: 1, borderColor: 'divider', ml: 1, pl: 2 }}
in={open}
timeout='auto'
unmountOnExit
>
{children}
</Collapse>
</List>
);
};

type ModelProps = {
label?: string;
model: OpenAPIV3.SchemaObject;
requiredAttrs?: ReadonlyArray<string>;
};

export const Model = (props: ModelProps) => {
const {
description,
items,
properties,
required,
requiredAttrs,
schemaType,
title,
} = useModelProps(props);

if (schemaType === 'object') {
return (
<ModelListEntry title={title} required={required} schemaType={schemaType}>
{Object.entries(properties).map(([key, property]) => (
<Model
key={key}
label={key}
model={property}
requiredAttrs={requiredAttrs}
/>
))}
</ModelListEntry>
);
} else if (schemaType === 'array') {
return (
<ModelListEntry title={title} required={required} schemaType={schemaType}>
<Model model={items} requiredAttrs={requiredAttrs} />
</ModelListEntry>
);
} else {
return (
<ModelItem
title={title}
required={required}
schemaType={schemaType}
description={description}
/>
);
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import {
Box,
Chip,
ChipProps,
Typography,
chipClasses,
styled,
} from '@mui/material';
import { OpenAPIV3 } from 'openapi-types';

import Expandable, {
ExpandableDetails,
ExpandableSummary,
} from '../Expandable';
import { Parameters } from './Parameters';
import { RequestBody } from './RequestBody';
import { Responses } from './Responses';

const StyledChip = styled(Chip)(() => ({
[`& .${chipClasses.label}`]: {
textTransform: 'uppercase',
fontWeight: 'bold',
color: 'white!important',
},
}));

export const API_METHODS_COLORS: Record<
OpenAPIV3.HttpMethods,
ChipProps['color']
> = {
get: 'primary',
post: 'success',
put: 'warning',
delete: 'error',
options: 'default',
head: 'default',
patch: 'default',
trace: 'default',
};

type OperationProps = OpenAPIV3.OperationObject<{
method: OpenAPIV3.HttpMethods;
path: string;
}>;

export const Operation = ({
method,
path,
summary,
description,
parameters,
responses,
requestBody,
servers = [],
}: OperationProps) => {
const chipColor = API_METHODS_COLORS[method] || 'default';
const baseUrl = servers[0]?.url || '';

return (
<Expandable>
<ExpandableSummary>
<Box display='inline-flex' alignItems='center' flexWrap='wrap'>
<StyledChip
sx={{ mr: 2 }}
label={method}
color={chipColor}
size='small'
/>
<Typography
variant='caption'
sx={{ color: (theme) => theme.palette.text.secondary }}
>
{baseUrl}
</Typography>
<Typography variant='caption-semibold'>{path}</Typography>
</Box>
<Typography sx={{ fontWeight: 'bold', mt: 2 }} variant='body1'>
{summary}
</Typography>
</ExpandableSummary>
<ExpandableDetails>
<Typography variant='body2'>{description}</Typography>
<Parameters parameters={parameters as OpenAPIV3.ParameterObject[]} />
{requestBody && (
<RequestBody {...(requestBody as OpenAPIV3.RequestBodyObject)} />
)}
{responses && <Responses responses={responses} />}
</ExpandableDetails>
</Expandable>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { useTranslations } from 'next-intl';
import { OpenAPIV3 } from 'openapi-types';

import { Operation } from './Operation';
import { Card, Typography } from '@mui/material';

const methods = [
'get',
'post',
'put',
'delete',
'options',
'head',
'patch',
'trace',
];

const getOperations = (
pathItemObj: Omit<OpenAPIV3.PathItemObject, 'parameters'>
) =>
Object.keys(pathItemObj)
.filter((key) => methods.includes(key))
.reduce<[string, OpenAPIV3.OperationObject][]>((acc, key) => {
const method = key as OpenAPIV3.HttpMethods;
const operation = pathItemObj[method] as OpenAPIV3.OperationObject;
return [...acc, [method, operation]];
}, []);

type OperationsProps = {
spec: OpenAPIV3.Document;
validOperations?: Record<string, OpenAPIV3.HttpMethods[]>;
};

export const Operations = ({ spec, validOperations }: OperationsProps) => {
const t = useTranslations('swagger');

if (!spec.paths || !validOperations) {
const noOpHeader = t('emptyOperations.header');
const noOpMessage = t('emptyOperations.message');
return (
<Card sx={{ borderRadius: 1, p: 2 }} variant='outlined'>
<Typography sx={{ fontWeight: 'bold' }} variant='body1'>
{noOpHeader}
</Typography>
<Typography
variant='body2'
sx={{ color: (theme) => theme.palette.text.secondary }}
>
{noOpMessage}
</Typography>
</Card>
);
}

const paths = Object.entries(spec.paths);
const specServers = spec.servers || [];

const renderOperationTag = ([path, pathItemObj = {}]: [
string,
OpenAPIV3.PathItemObject | undefined
]) => {
const operations = getOperations(pathItemObj);
const headerParameters = pathItemObj?.parameters || [];
const validOperationMethods = validOperations[path] || [];

return (
<div key={`operation-${path}`}>
{operations.map(([method, operation]) => {
const httpMethod = method as OpenAPIV3.HttpMethods;
const renderOp = validOperationMethods.includes(httpMethod);

if (!renderOp) return null;

const { parameters: pathParameters = [], servers, ...op } = operation;
const parameters = pathParameters.concat(headerParameters);
const operationServers = servers || specServers;
return (
<Operation
key={`${path}-${method}`}
method={httpMethod}
path={path}
parameters={parameters}
servers={operationServers}
{...op}
/>
);
})}
</div>
);
};

return <div>{paths.map(renderOperationTag)}</div>;
};
Loading
Loading