Skip to content

Commit

Permalink
Merge branch 'main' into fix/elements-core/http-method-request-body-o…
Browse files Browse the repository at this point in the history
…mission
  • Loading branch information
mnaumanali94 committed Jul 12, 2024
2 parents ecc4e9f + b6d8236 commit d20e02d
Show file tree
Hide file tree
Showing 33 changed files with 4,204 additions and 2,167 deletions.
4 changes: 2 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
build:
working_directory: /mnt/ramdisk/project
docker:
- image: cimg/node:16.17
- image: cimg/node:18.20
resource_class: xlarge
environment:
CYPRESS_CACHE_FOLDER: /mnt/ramdisk/.cache/Cypress
Expand Down Expand Up @@ -93,7 +93,7 @@ jobs:
command: weekly_lockfile_maintenance.sh
release:
docker:
- image: cimg/node:16.17
- image: cimg/node:18.20
steps:
- checkout
- run:
Expand Down
1 change: 0 additions & 1 deletion .nvmrc

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"start-server-and-test": "^2.0.0",
"storybook": "7.5.3",
"style-loader": "^3.3.3",
"ts-jest": "^26.4.5",
"ts-jest": "^26.5.6",
"tsconfig-paths-webpack-plugin": "^3.2.0",
"typescript": "4.7.4",
"webpack": "5.76.1",
Expand Down
4 changes: 2 additions & 2 deletions packages/elements-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"**/*"
],
"engines": {
"node": ">=14.13"
"node": ">=16"
},
"scripts": {
"build": "yarn build.react",
Expand Down Expand Up @@ -88,7 +88,7 @@
},
"devDependencies": {
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@stoplight/scripts": "9.3.4",
"@stoplight/scripts": "10.0.0",
"@testing-library/dom": "^7.26.5",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^11.1.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import { Box, Flex, Heading, HStack, NodeAnnotation, useThemeIsDark, VStack } from '@stoplight/mosaic';
import {
Box,
Flex,
Heading,
HStack,
IBackgroundColorProps,
NodeAnnotation,
useThemeIsDark,
VStack,
} from '@stoplight/mosaic';
import { withErrorBoundary } from '@stoplight/react-error-boundary';
import { IHttpEndpointOperation, IHttpOperation } from '@stoplight/types';
import { HttpMethod, IHttpEndpointOperation, IHttpOperation } from '@stoplight/types';
import cn from 'classnames';
import { useAtomValue } from 'jotai/utils';
import * as React from 'react';
Expand Down Expand Up @@ -173,7 +182,7 @@ function MethodPathInner({ method, path, chosenServerUrl }: MethodPathProps & {
py={1}
px={2.5}
rounded="lg"
bg={!isDark ? HttpMethodColors[method] : 'canvas-100'}
bg={!isDark ? (HttpMethodColors[method as HttpMethod] as IBackgroundColorProps['bg']) : 'canvas-100'}
color={!isDark ? 'on-primary' : 'body'}
fontSize="lg"
fontWeight="semibold"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,22 @@ interface ParametersProps {
parameters?: IHttpParam[];
}

const readableStyles = {
const readableStyles: Readonly<Partial<Record<HttpParamStyles, string>>> = {
[HttpParamStyles.PipeDelimited]: 'Pipe separated values',
[HttpParamStyles.SpaceDelimited]: 'Space separated values',
[HttpParamStyles.CommaDelimited]: 'Comma separated values',
[HttpParamStyles.Simple]: 'Comma separated values',
[HttpParamStyles.Matrix]: 'Path style values',
[HttpParamStyles.Label]: 'Label style values',
[HttpParamStyles.Form]: 'Form style values',
} as const;
};

const defaultStyle = {
const defaultStyle: Readonly<Partial<Record<string, HttpParamStyles>>> = {
query: HttpParamStyles.Form,
header: HttpParamStyles.Simple,
path: HttpParamStyles.Simple,
cookie: HttpParamStyles.Form,
} as const;
};

export const Parameters: React.FunctionComponent<ParametersProps> = ({ parameters, parameterType }) => {
const { nodeHasChanged, renderExtensionAddon } = useOptionsCtx();
Expand Down Expand Up @@ -85,14 +85,12 @@ const httpOperationParamsToSchema = ({ parameters, parameterType }: ParametersPr

// TODO (CL): This can be removed when http operations are fixed https://github.com/stoplightio/http-spec/issues/26
const paramDescription = description || paramSchema.description;

const paramDeprecated = !!(deprecated || paramSchema.deprecated);
const paramStyleUnspecified = style === HttpParamStyles.Unspecified;
const paramStyle = paramStyleUnspecified
? undefined
: style && defaultStyle[parameterType] !== style
? readableStyles[style] || style
: undefined;

let paramStyle: string | undefined;
if (style && style !== HttpParamStyles.Unspecified && defaultStyle[parameterType] !== style) {
paramStyle = readableStyles[style] || style;
}

if (isPlainObject(schema.properties)) {
schema.properties![p.name] = {
Expand Down
6 changes: 3 additions & 3 deletions packages/elements-core/src/components/Docs/Model/Model.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ const ModelComponent: React.FC<ModelProps> = ({

const { ref: layoutRef, isCompact } = useIsCompact(layoutOptions);

const nodeId = data?.['x-stoplight']?.id;
const nodeId = (data?.['x-stoplight' as keyof JSONSchema7] as { [key: string]: any })?.id;
const title = data.title ?? nodeTitle;
const isDeprecated = !!data['deprecated'];
const isInternal = !!data['x-internal'];
const isDeprecated = !!data['deprecated' as keyof JSONSchema7];
const isInternal = !!data['x-internal' as keyof JSONSchema7];

const shouldDisplayHeader =
!layoutOptions?.noHeading && (title !== undefined || (exportProps && !layoutOptions?.hideExport));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { INode } from '@stoplight/types';
import type { JSONSchema7 } from 'json-schema';
import { memoize } from 'lodash';
import { isEmpty, memoize, pickBy } from 'lodash';
import * as React from 'react';

import { useOptionsCtx } from '../../context/Options';
Expand All @@ -21,16 +21,7 @@ export type NodeVendorExtensionsProps = {
*
* @param data The object to extract the vendor extensions from.
*/
const getVendorExtensions = memoize((data: object) => {
const vendorExtensionNames = Object.keys(data).filter(item => item.startsWith('x-'));
const vendorExtensions = vendorExtensionNames.reduce((previousValue, currentValue, currentIndex: number) => {
return {
...previousValue,
[currentValue]: data[currentValue],
};
}, {});
return vendorExtensions;
});
const getVendorExtensions = memoize((data: INode) => pickBy(data, (_val, key) => key.startsWith('x-')));

/**
* @private
Expand All @@ -45,10 +36,11 @@ export const NodeVendorExtensions = React.memo<NodeVendorExtensionsProps>(({ dat

const originalObject = getOriginalObject(data) as INode;
const vendorExtensions = originalObject.extensions ? originalObject.extensions : getVendorExtensions(originalObject);
const vendorExtensionKeys = Object.keys(vendorExtensions);
if (vendorExtensionKeys.length === 0) {

if (isEmpty(vendorExtensions)) {
return null;
}

return (
<>
{renderExtensionAddon({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { JsonSchemaViewer } from '@stoplight/json-schema-viewer';
import { DefaultSMDComponents } from '@stoplight/markdown-viewer';
import { Box, Flex, Icon } from '@stoplight/mosaic';
import { HttpParamStyles, IHttpOperation, IHttpRequest, NodeType } from '@stoplight/types';
import { isObject } from 'lodash';
import { isPlainObject, isString } from 'lodash';
import React from 'react';
import URI from 'urijs';

Expand All @@ -26,11 +26,9 @@ type PartialHttpRequest = Pick<IHttpRequest, 'method' | 'url'> & Partial<IHttpRe

function isPartialHttpRequest(maybeHttpRequest: unknown): maybeHttpRequest is PartialHttpRequest {
return (
isObject(maybeHttpRequest) &&
'method' in maybeHttpRequest &&
typeof maybeHttpRequest['method'] === 'string' &&
'url' in maybeHttpRequest &&
typeof maybeHttpRequest['url'] === 'string'
isPlainObject(maybeHttpRequest) &&
isString((maybeHttpRequest as PartialHttpRequest).method) &&
isString((maybeHttpRequest as PartialHttpRequest).url)
);
}

Expand Down Expand Up @@ -92,7 +90,7 @@ export const CodeComponent: CustomComponentMapping['code'] = props => {
}

if (http) {
if (!isObject(parsedValue) || (!isPartialHttpRequest(parsedValue) && !isHttpOperation(parsedValue))) {
if (!isPlainObject(parsedValue) || (!isPartialHttpRequest(parsedValue) && !isHttpOperation(parsedValue))) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Box, Flex, Icon } from '@stoplight/mosaic';
import { Box, Flex, Icon, ITextColorProps } from '@stoplight/mosaic';
import { HttpMethod, NodeType } from '@stoplight/types';
import * as React from 'react';

import { useRouterType } from '../../context/RouterType';
Expand Down Expand Up @@ -167,15 +168,23 @@ const GroupItem = React.memo<{
onLinkClick={onLinkClick}
meta={
item.meta ? (
<Box color={NODE_META_COLOR[item.meta]} textTransform="uppercase" fontWeight="medium">
<Box
color={NODE_META_COLOR[item.meta as HttpMethod] as ITextColorProps['color']}
textTransform="uppercase"
fontWeight="medium"
>
{item.meta}
</Box>
) : (
NODE_TYPE_META_ICON[item.type] && (
<Flex alignItems="center">
{item.version && <Version value={item.version} />}
{item.type !== 'model' && (
<Box as={Icon} color={NODE_TYPE_ICON_COLOR[item.type]} icon={NODE_TYPE_META_ICON[item.type]} />
<Box
as={Icon}
color={NODE_TYPE_ICON_COLOR[item.type as NodeType] as ITextColorProps['color']}
icon={NODE_TYPE_META_ICON[item.type]}
/>
)}
</Flex>
)
Expand Down
19 changes: 10 additions & 9 deletions packages/elements-core/src/components/TableOfContents/constants.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,39 @@
import { faBullseye, faCloud, faCube, faCubes, faEnvelope, faEnvelopesBulk } from '@fortawesome/free-solid-svg-icons';
import { IIconProps } from '@stoplight/mosaic';
import { IIconProps, ITextColorProps } from '@stoplight/mosaic';
import { HttpMethod } from '@stoplight/types';

// Icons appear left of the node title
export const NODE_TYPE_TITLE_ICON: { [nodeType: string]: IIconProps['icon'] } = {
export const NODE_TYPE_TITLE_ICON: Readonly<{ [nodeType: string]: IIconProps['icon'] }> = {
http_service: faCloud,
http_operation: faBullseye,
http_webhook: faEnvelope,
model: faCube,
};

export const NODE_GROUP_ICON: { [itemType: string]: IIconProps['icon'] } = {
export const NODE_GROUP_ICON: Readonly<{ [itemType: string]: IIconProps['icon'] }> = {
http_webhook: faEnvelopesBulk,
model: faCubes,
};

// Icons appear in the right meta
export const NODE_TYPE_META_ICON: { [nodeType: string]: IIconProps['icon'] } = {
export const NODE_TYPE_META_ICON: Readonly<{ [nodeType: string]: IIconProps['icon'] }> = {
webhook: faEnvelope,
model: faCube,
};

export const NODE_TYPE_ICON_COLOR = {
export const NODE_TYPE_ICON_COLOR: Readonly<{ [nodeType: string]: ITextColorProps['color'] }> = {
model: 'warning',
http_service: '#D812EA',
http_operation: '#9747FF',
http_service: '#D812EA' as ITextColorProps['color'],
http_operation: '#9747FF' as ITextColorProps['color'],
http_webhook: 'primary',
};

export const NODE_GROUP_ICON_COLOR = {
export const NODE_GROUP_ICON_COLOR: Readonly<{ [nodeType: string]: ITextColorProps['color'] }> = {
http_webhook: 'primary',
model: 'warning',
};

export const NODE_META_COLOR = {
export const NODE_META_COLOR: Readonly<Record<HttpMethod, string>> = {
get: 'success',
post: 'primary',
put: 'warning',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
IOauth2SecurityScheme,
} from '@stoplight/types';
import { atom, useAtom } from 'jotai';
import { flatten, isObject } from 'lodash';
import { flatten, isObject, isPlainObject } from 'lodash';
import React from 'react';

import { persistAtom } from '../../../utils/jotai/persistAtom';
Expand Down Expand Up @@ -68,6 +68,10 @@ const getSecuritySchemeNames = (securitySchemes: HttpSecurityScheme[]): string[]

type SecuritySchemeValues = Dictionary<string>;

const isSecuritySchemeValues = (
maybeSecuritySchemeValues: unknown,
): maybeSecuritySchemeValues is SecuritySchemeValues => isPlainObject(maybeSecuritySchemeValues);

const securitySchemeValuesAtom = persistAtom('TryIt_securitySchemeValues', atom<SecuritySchemeValues>({}));
export const usePersistedSecuritySchemeWithValues = (): [
HttpSecuritySchemeWithValues[] | undefined,
Expand Down Expand Up @@ -96,7 +100,7 @@ export const usePersistedSecuritySchemeWithValues = (): [
return currentScheme.map(scheme => {
return {
scheme: scheme.scheme,
authValue: securitySchemeValues[scheme.scheme.key],
authValue: isSecuritySchemeValues(securitySchemeValues) ? securitySchemeValues[scheme.scheme.key] : undefined,
};
});
}, [currentScheme, securitySchemeValues]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export function mapSchemaPropertiesToParameters(
name,
schema: typeof schema !== 'boolean' ? schema : undefined,
examples:
typeof schema !== 'boolean' && schema.examples && schema.examples[0]
typeof schema !== 'boolean' && Array.isArray(schema.examples) && schema.examples[0]
? [{ key: 'example', value: schema.examples[0] }]
: undefined,
...(required?.includes(name) && { required: true }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as React from 'react';
import { filterOutAuthorizationParams } from '../Auth/authentication-utils';
import { initialParameterValues, ParameterSpec } from './parameter-utils';

const persistedParameterValuesAtom = atom({});
const persistedParameterValuesAtom = atom<Record<string, string | undefined>>({});
export const useRequestParameters = (httpOperation: IHttpEndpointOperation) => {
const [persistedParameterValues, setPersistedParameterValues] = useAtom(persistedParameterValuesAtom);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export const useServerVariables = () => {
const [serverVariables, setPersistedServerVariableValues] = useAtom(persistedServerVariableValuesAtom);

const updateServerVariableValue = (op: 'set' | 'unset', name: string, value: string) => {
const newServerVariables = { ...serverVariables };
const newServerVariables: { [key: string]: string } = { ...serverVariables };
if (op === 'unset') {
delete newServerVariables[name];
} else {
Expand Down
15 changes: 10 additions & 5 deletions packages/elements-core/src/components/TryIt/TryIt.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Box, Button, HStack, Icon, Panel, useThemeIsDark } from '@stoplight/mosaic';
import type { IHttpEndpointOperation, IServer } from '@stoplight/types';
import { Box, Button, HStack, Icon, ITextColorProps, Panel, useThemeIsDark } from '@stoplight/mosaic';
import type { HttpMethod, IHttpEndpointOperation, IServer } from '@stoplight/types';
import { Request as HarRequest } from 'har-format';
import { useAtom } from 'jotai';
import * as React from 'react';
Expand All @@ -11,7 +11,7 @@ import { extractCodeSamples, RequestSamples } from '../RequestSamples';
import { TryItAuth } from './Auth/Auth';
import { usePersistedSecuritySchemeWithValues } from './Auth/authentication-utils';
import { FormDataBody } from './Body/FormDataBody';
import { useBodyParameterState } from './Body/request-body-utils';
import { BodyParameterValues, useBodyParameterState } from './Body/request-body-utils';
import { RequestBody } from './Body/RequestBody';
import { useTextRequestBodyState } from './Body/useTextRequestBodyState';
import { buildFetchRequest, buildHarRequest } from './build-request';
Expand Down Expand Up @@ -120,7 +120,7 @@ export const TryIt: React.FC<TryItProps> = ({
const getValues = () =>
Object.keys(bodyParameterValues)
.filter(param => !isAllowedEmptyValues[param] ?? true)
.reduce((previousValue, currentValue) => {
.reduce<BodyParameterValues>((previousValue, currentValue) => {
previousValue[currentValue] = bodyParameterValues[currentValue];
return previousValue;
}, {});
Expand Down Expand Up @@ -320,7 +320,12 @@ export const TryIt: React.FC<TryItProps> = ({
tryItPanelElem = (
<Panel isCollapsible={false} p={0} className="TryItPanel">
<Panel.Titlebar bg="canvas-300">
<Box fontWeight="bold" color={!isDark ? HttpMethodColors[httpOperation.method] : undefined}>
<Box
fontWeight="bold"
color={
!isDark ? (HttpMethodColors[httpOperation.method as HttpMethod] as ITextColorProps['color']) : undefined
}
>
{httpOperation.method.toUpperCase()}
</Box>
<Box fontWeight="medium" ml={2} textOverflow="truncate" overflowX="hidden">
Expand Down
Loading

0 comments on commit d20e02d

Please sign in to comment.