Skip to content

Commit

Permalink
[ENG-1207] Render modal for response examples in API Portal (#239)
Browse files Browse the repository at this point in the history
* make styling for navlink consistent

* move OperationReferenceMain under components/

* DRY badge styling

* default color scheme is dark

* remove bg from prism code

* make active header tab brighter

* render response example/schemas

* add comment for confusing part of transformSpec
  • Loading branch information
dphuang2 authored Oct 3, 2023
1 parent 7ffbd12 commit 4a4b5c6
Show file tree
Hide file tree
Showing 17 changed files with 305 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,13 @@ export const transformSpec = async ({
inheritExamplesFromTopLevelExample({ schema, spec })
})

// x-konfig-generated-schema (for generating example in generated documentation for free-form object schema)
// x-konfig-generated-schema (for generating example in generated
// documentation for free-form object schema)
// Why?
// We do this because a lot of code in Java is built to generate examples from
// a schema. So to generate examples for a free-form object (e.g. "type:
// object" with no properties), we have to generate a schema for the example
// and then reference that schema in the spec to reuse the same Java code.
recurseObject(spec.spec, ({ value: schema, path }) => {
// Found schema w/ example
if (typeof schema !== 'object') return
Expand Down
1 change: 1 addition & 0 deletions generator/konfig-next-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"mobx-react": "^7.6.0",
"next": "^13.4.6",
"octokit": "^2.0.19",
"openapi-sampler": "^1.3.1",
"prismjs": "^1.29.0",
"react": "18.2.0",
"react-dom": "18.2.0",
Expand Down
14 changes: 2 additions & 12 deletions generator/konfig-next-app/src/components/ExecuteOutput.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { useMantineColorScheme, Transition, Tabs, Code } from '@mantine/core'
import { useState, useEffect, useCallback } from 'react'
const ReactJson = dynamic(() => import('react-json-view'), {
ssr: false,
})
import { DemoTable } from './DemoTable'
import { tryTableOutput } from '@/utils/try-table-output'
import { tryJsonOutput } from '@/utils/try-json-output'
import dynamic from 'next/dynamic'
import { JsonViewer } from './JsonViewer'

export function ExecuteOutput({
jsonOutput,
Expand Down Expand Up @@ -118,18 +115,11 @@ export function ExecuteOutput({
onMouseEnter={() => setIsFocusedOnJson(true)}
onMouseLeave={() => setIsFocusedOnJson(false)}
>
<ReactJson
<JsonViewer
collapsed={1}
displayObjectSize
displayDataTypes={false}
name={false}
theme={colorScheme === 'dark' ? 'tomorrow' : undefined}
style={{
fontSize: '0.85rem',
padding: '0.75rem',
maxHeight: '500px',
overflowY: 'scroll',
}}
src={jsonOutput}
/>
</div>
Expand Down
2 changes: 1 addition & 1 deletion generator/konfig-next-app/src/components/HeaderTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export function HeaderTab({
theme.colorScheme === 'dark'
? navLinkColor({ active, theme: { ...theme, colorScheme: 'dark' } })
: active
? theme.colors.gray[2]
? theme.colors.gray[0]
: theme.colors.gray[4]

return (
Expand Down
19 changes: 2 additions & 17 deletions generator/konfig-next-app/src/components/HttpMethodBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,9 @@ import {
import type { HttpMethods } from 'konfig-lib'
import { HttpMethodsEnum } from 'konfig-lib/dist/forEachOperation'

export function HttpMethodBadge({
httpMethod,
size,
}: {
httpMethod: HttpMethods
size?: MantineSize
}) {
export function HttpMethodBadge({ httpMethod }: { httpMethod: HttpMethods }) {
const theme = useMantineTheme()
return (
<Badge
size={size}
variant={theme.colorScheme === 'light' ? 'filled' : 'light'}
color={httpMethodColor(httpMethod)}
radius="xs"
>
{httpMethod}
</Badge>
)
return <Badge color={httpMethodColor(httpMethod)}>{httpMethod}</Badge>
}

function httpMethodColor(method: HttpMethods): MantineColor {
Expand Down
20 changes: 20 additions & 0 deletions generator/konfig-next-app/src/components/JsonViewer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useMantineTheme } from '@mantine/core'
import dynamic from 'next/dynamic'
const ReactJson = dynamic(() => import('react-json-view'), {
ssr: false,
})
export const JsonViewer: typeof ReactJson = (props) => {
const theme = useMantineTheme()
return (
<ReactJson
theme={theme.colorScheme === 'dark' ? 'tomorrow' : undefined}
style={{
fontSize: '0.85rem',
padding: '0.75rem',
maxHeight: '500px',
overflowY: 'scroll',
}}
{...props}
/>
)
}
10 changes: 1 addition & 9 deletions generator/konfig-next-app/src/components/LinksGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,6 @@ const useStyles = createStyles((theme) => ({
paddingLeft: rem(20),
},

link: {
fontWeight: 500,
fontSize: theme.fontSizes.sm,
},

chevron: {
transition: 'transform 200ms ease',
},
Expand Down Expand Up @@ -116,13 +111,10 @@ export function LinksGroup({
}}
ref={ref}
component={Link}
className={classes.link}
href={link.link}
label={link.label}
active={link.active}
rightSection={
<HttpMethodBadge size="xs" httpMethod={link.httpMethod} />
}
rightSection={<HttpMethodBadge httpMethod={link.httpMethod} />}
/>
</Box>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export function OperationFormGeneratedCode(args: CodeGeneratorConstructorArgs) {
styles: {
code: {
maxHeight: 400,
backgroundColor: 'unset !important',
},
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,37 @@ import {
Alert,
useMantineTheme,
} from '@mantine/core'
import { HttpMethodBadge } from './components/HttpMethodBadge'
import { OperationForm } from './components/OperationForm'
import { OperationFormGeneratedCode } from './components/OperationFormGeneratedCode'
import { httpResponseCodeMeaning } from './utils/http-response-code-meaning'
import { HttpMethodBadge } from './HttpMethodBadge'
import { OperationForm } from './OperationForm'
import { OperationFormGeneratedCode } from './OperationFormGeneratedCode'
import { httpResponseCodeMeaning } from '../utils/http-response-code-meaning'
import {
FORM_VALUES_LOCAL_STORAGE_KEY,
generateInitialFormValues,
generateInitialFormValuesWithStorage,
} from './utils/generate-initial-operation-form-values'
} from '../utils/generate-initial-operation-form-values'
import {
OperationClientStateForm,
OperationSecuritySchemeForm,
} from './components/OperationSecuritySchemeForm'
} from './OperationSecuritySchemeForm'
import type { SecurityScheme, RequestBodyObject } from 'konfig-lib'
import { generateParametersFromRequestBodyProperties } from './utils/generate-parameters-from-request-body-properties'
import { generateParametersFromRequestBodyProperties } from '../utils/generate-parameters-from-request-body-properties'
import { useEffect, useMemo, useState } from 'react'
import { FormProvider, useForm } from './utils/operation-form-context'
import { FormProvider, useForm } from '../utils/operation-form-context'
import { useRouter } from 'next/router'
import { CodeGeneratorConstructorArgs } from './utils/code-generator'
import { CodeGeneratorTypeScript } from './utils/code-generator-typescript'
import { ExecuteOutput } from './components/ExecuteOutput'
import { tryJsonOutput } from './utils/try-json-output'
import { tryTableOutput } from './utils/try-table-output'
import { CodeGeneratorConstructorArgs } from '../utils/code-generator'
import { CodeGeneratorTypeScript } from '../utils/code-generator-typescript'
import { ExecuteOutput } from './ExecuteOutput'
import { tryJsonOutput } from '../utils/try-json-output'
import { tryTableOutput } from '../utils/try-table-output'
import { IconAlertCircle, IconTerminal } from '@tabler/icons-react'
import { deepmerge } from './utils/deepmerge'
import { deepmerge } from '../utils/deepmerge'
import { notifications } from '@mantine/notifications'
import localforage from 'localforage'
import { ReferencePageProps } from './utils/generate-props-for-reference-page'
import { SocialFooter } from './components/SocialFooter'
import { Breadcrumbs } from './components/Breadcrumbs'
import { ReferencePageProps } from '../utils/generate-props-for-reference-page'
import { SocialFooter } from './SocialFooter'
import { Breadcrumbs } from './Breadcrumbs'
import { OperationReferenceResponses } from './OperationReferenceResponses'

export function OperationReferenceMain({
pathParameters,
Expand Down Expand Up @@ -301,57 +302,7 @@ export function OperationReferenceMain({
requestBodyProperties={requestBodyProperties}
requestBodyRequired={requestBodyRequired}
/>
{responses && (
<Box my="lg">
<Title order={4}>Responses</Title>
<Divider my="sm" />
<Stack>
{Object.entries(responses).map(([responseCode, response]) => (
<Box key={responseCode}>
{/* 1. Render response code
2. Render meaning of response code like "OK" for 200 and "Not Found" for 404 in same text box as (1)
3. Render green "Success" badge next to 2xx codes and red "Error" badge next to 4xx and 5xx codes
4. Render response description if it exists under the response code + badge
*/}

<Flex gap="xs" align="center">
<Title order={6}>
{responseCode} {httpResponseCodeMeaning(responseCode)}
</Title>
{responseCode.startsWith('2') ? (
<Badge
variant={
colorScheme === 'dark' ? 'light' : 'filled'
}
radius="xs"
color="blue"
size="xs"
>
Success
</Badge>
) : (
<Badge
variant={
colorScheme === 'dark' ? 'light' : 'filled'
}
radius="xs"
color="red"
size="xs"
>
Error
</Badge>
)}
</Flex>
{response.description && (
<Text c="dimmed" fz="sm">
{response.description}
</Text>
)}
</Box>
))}
</Stack>
</Box>
)}
{responses && <OperationReferenceResponses responses={responses} />}
<MediaQuery smallerThan="sm" styles={{ display: 'none' }}>
<Box>
<SocialFooter konfigYaml={konfigYaml} />
Expand Down Expand Up @@ -406,7 +357,6 @@ export function OperationReferenceMain({
<Box p="sm">
{/* if status is not successful (e.g. 4xx or 5xx), the badge is red */}
<Badge
variant={colorScheme === 'dark' ? 'light' : 'filled'}
color={result.status >= 300 ? 'red' : 'blue'}
>{`${result.status} ${result.statusText}`}</Badge>
</Box>
Expand Down
Loading

0 comments on commit 4a4b5c6

Please sign in to comment.