From 9bea9e06f15397781a064dc1593b6c71805b1b54 Mon Sep 17 00:00:00 2001 From: Dimitri Mitropoulos Date: Wed, 29 Jun 2022 17:34:28 -0400 Subject: [PATCH] fixes ContentTypeDropdown and AuthDropdown (#4918) --- .../src/dropdown/dropdown.tsx | 4 +- .../ui/components/base/dropdown/dropdown.tsx | 27 ++-- .../ui/components/dropdowns/auth-dropdown.tsx | 45 ++++-- .../dropdowns/content-type-dropdown.tsx | 147 ++++++++++-------- .../src/ui/components/panes/request-pane.tsx | 23 +-- 5 files changed, 136 insertions(+), 110 deletions(-) diff --git a/packages/insomnia-components/src/dropdown/dropdown.tsx b/packages/insomnia-components/src/dropdown/dropdown.tsx index 54e66a8e3..f162837d0 100644 --- a/packages/insomnia-components/src/dropdown/dropdown.tsx +++ b/packages/insomnia-components/src/dropdown/dropdown.tsx @@ -146,9 +146,9 @@ interface State { } const isComponent = (match: string) => (child: ReactNode) => any(equals(match), [ - // @ts-expect-error not sure + // @ts-expect-error this is required by our API for Dropdown child.type.name, - // @ts-expect-error not sure + // @ts-expect-error this is required by our API for Dropdown child.type.displayName, ]); diff --git a/packages/insomnia/src/ui/components/base/dropdown/dropdown.tsx b/packages/insomnia/src/ui/components/base/dropdown/dropdown.tsx index 0cebfd8b2..b66563838 100644 --- a/packages/insomnia/src/ui/components/base/dropdown/dropdown.tsx +++ b/packages/insomnia/src/ui/components/base/dropdown/dropdown.tsx @@ -1,5 +1,6 @@ import { autoBindMethodsForReact } from 'class-autobind-decorator'; import classnames from 'classnames'; +import { any, equals } from 'ramda'; import React, { CSSProperties, Fragment, PureComponent, ReactNode } from 'react'; import ReactDOM from 'react-dom'; @@ -36,6 +37,17 @@ interface State { uniquenessKey: number; } +const isComponent = (match: string) => (child: ReactNode) => any(equals(match), [ + // @ts-expect-error this is required by our API for Dropdown + child.type.name, + // @ts-expect-error this is required by our API for Dropdown + child.type.displayName, +]); + +const isDropdownItem = isComponent(DropdownItem.name); +const isDropdownButton = isComponent(DropdownButton.name); +const isDropdownDivider = isComponent(DropdownDivider.name); + @autoBindMethodsForReact(AUTOBIND_CFG) export class Dropdown extends PureComponent { private _node: HTMLDivElement | null = null; @@ -356,8 +368,7 @@ export class Dropdown extends PureComponent { const allChildren = this._getFlattenedChildren(children); const visibleChildren = allChildren.filter((child, i) => { - // @ts-expect-error -- TSCONVERSION this should cater for all types that ReactNode can be - if (child.type.name !== DropdownItem.name) { + if (isDropdownItem(child)) { return true; } @@ -368,11 +379,9 @@ export class Dropdown extends PureComponent { for (let i = 0; i < allChildren.length; i++) { const child = allChildren[i]; - // @ts-expect-error -- TSCONVERSION this should cater for all types that ReactNode can be - if (child.type.name === DropdownButton.name) { + if (isDropdownButton(child)) { dropdownButtons.push(child); - // @ts-expect-error -- TSCONVERSION this should cater for all types that ReactNode can be - } else if (child.type.name === DropdownItem.name) { + } else if (isDropdownItem(child)) { const active = i === filterActiveIndex; const hide = !visibleChildren.includes(child); dropdownItems.push( @@ -387,14 +396,12 @@ export class Dropdown extends PureComponent { {child} , ); - // @ts-expect-error -- TSCONVERSION this should cater for all types that ReactNode can be - } else if (child.type.name === DropdownDivider.name) { + } else if (isDropdownDivider(child)) { const currentIndex = visibleChildren.indexOf(child); const nextChild = visibleChildren[currentIndex + 1]; // Only show the divider if the next child is a DropdownItem - // @ts-expect-error -- TSCONVERSION this should cater for all types that ReactNode can be - if (nextChild && nextChild.type.name === DropdownItem.name) { + if (nextChild && isDropdownItem(nextChild)) { dropdownItems.push(
  • {child}
  • ); } } diff --git a/packages/insomnia/src/ui/components/dropdowns/auth-dropdown.tsx b/packages/insomnia/src/ui/components/dropdowns/auth-dropdown.tsx index 5adda0ef9..90ba80dac 100644 --- a/packages/insomnia/src/ui/components/dropdowns/auth-dropdown.tsx +++ b/packages/insomnia/src/ui/components/dropdowns/auth-dropdown.tsx @@ -1,4 +1,5 @@ import React, { FC, useCallback } from 'react'; +import { useSelector } from 'react-redux'; import { AUTH_ASAP, @@ -16,6 +17,7 @@ import { } from '../../../common/constants'; import * as models from '../../../models'; import type { Request, RequestAuthentication } from '../../../models/request'; +import { selectActiveRequest } from '../../redux/selectors'; import { Dropdown } from '../base/dropdown/dropdown'; import { DropdownButton } from '../base/dropdown/dropdown-button'; import { DropdownDivider } from '../base/dropdown/dropdown-divider'; @@ -34,17 +36,27 @@ const AuthItem: FC<{ {nameOverride || getAuthTypeName(type, true)} ); +AuthItem.displayName = DropdownItem.name; interface Props { - className?: string; onChange: (request: Request, arg1: RequestAuthentication) => Promise; - request: Request; } -export const AuthDropdown: FC = ({ children, className, onChange, request }) => { - const { authentication } = request; +export const AuthDropdown: FC = ({ onChange }) => { + const activeRequest = useSelector(selectActiveRequest); const onClick = useCallback((type: string) => { + if (!activeRequest) { + return; + } + + if (!('authentication' in activeRequest)) { + // gRPC Requests don't have `authentication` + return; + } + + const { authentication } = activeRequest; + const fn = async () => { if (type === authentication.type) { // Type didn't change @@ -73,21 +85,34 @@ export const AuthDropdown: FC = ({ children, className, onChange, request break; } } - onChange(request, newAuthentication); + onChange(activeRequest, newAuthentication); }; fn(); - }, [authentication, onChange, request]); + }, [onChange, activeRequest]); - const isCurrent = useCallback((type: string) => ( - type === (authentication.type || AUTH_NONE) - ), [authentication.type]); + const isCurrent = useCallback((type: string) => { + if (!activeRequest) { + return false; + } + if (!('authentication' in activeRequest)) { + return false; + } + return type === (activeRequest.authentication.type || AUTH_NONE); + }, [activeRequest]); + + if (!activeRequest) { + return null; + } const itemProps = { onClick, isCurrent }; return ( Auth Types - {children} + + {'authentication' in activeRequest ? getAuthTypeName(activeRequest.authentication.type) || 'Auth' : 'Auth'} + + diff --git a/packages/insomnia/src/ui/components/dropdowns/content-type-dropdown.tsx b/packages/insomnia/src/ui/components/dropdowns/content-type-dropdown.tsx index d050cedfe..4cff98bdf 100644 --- a/packages/insomnia/src/ui/components/dropdowns/content-type-dropdown.tsx +++ b/packages/insomnia/src/ui/components/dropdowns/content-type-dropdown.tsx @@ -16,16 +16,15 @@ import { getContentTypeName, } from '../../../common/constants'; import { selectActiveRequest } from '../../redux/selectors'; -import { Dropdown, DropdownProps } from '../base/dropdown/dropdown'; +import { Dropdown } from '../base/dropdown/dropdown'; import { DropdownButton } from '../base/dropdown/dropdown-button'; import { DropdownDivider } from '../base/dropdown/dropdown-divider'; import { DropdownItem } from '../base/dropdown/dropdown-item'; import { AlertModal } from '../modals/alert-modal'; import { showModal } from '../modals/index'; -interface Props extends DropdownProps { +interface Props { onChange: (mimeType: string | null) => void; - className?: string; } const EMPTY_MIME_TYPE = null; @@ -41,36 +40,38 @@ const MimeTypeItem: FC<{ }) => { const activeRequest = useSelector(selectActiveRequest); const handleChangeMimeType = useCallback(async (mimeType: string | null) => { - if (activeRequest) { - const { body } = activeRequest; - const hasMimeType = 'mimeType' in body; - if (hasMimeType && body.mimeType === mimeType) { - // Nothing to do since the mimeType hasn't changed - return; - } + if (!activeRequest) { + return; + } - const hasParams = 'params' in body && body.params && body.params.length; - const hasText = body.text && body.text.length; - const hasFile = 'fileName' in body && body.fileName && body.fileName.length; - const isEmpty = !hasParams && !hasText && !hasFile; - const isFile = hasMimeType && body.mimeType === CONTENT_TYPE_FILE; - const isMultipart = hasMimeType && body.mimeType === CONTENT_TYPE_FORM_DATA; - const isFormUrlEncoded = hasMimeType && body.mimeType === CONTENT_TYPE_FORM_URLENCODED; - const isText = !isFile && !isMultipart; - const willBeFile = mimeType === CONTENT_TYPE_FILE; - const willBeMultipart = mimeType === CONTENT_TYPE_FORM_DATA; - const willBeGraphQL = mimeType === CONTENT_TYPE_GRAPHQL; - const willConvertToText = !willBeGraphQL && !willBeFile && !willBeMultipart; - const willPreserveText = willConvertToText && isText; - const willPreserveForm = isFormUrlEncoded && willBeMultipart; + const { body } = activeRequest; + const hasMimeType = 'mimeType' in body; + if (hasMimeType && body.mimeType === mimeType) { + // Nothing to do since the mimeType hasn't changed + return; + } - if (!isEmpty && !willPreserveText && !willPreserveForm) { - await showModal(AlertModal, { - title: 'Switch Body Type?', - message: 'Current body will be lost. Are you sure you want to continue?', - addCancel: true, - }); - } + const hasParams = 'params' in body && body.params && body.params.length; + const hasText = body.text && body.text.length; + const hasFile = 'fileName' in body && body.fileName && body.fileName.length; + const isEmpty = !hasParams && !hasText && !hasFile; + const isFile = hasMimeType && body.mimeType === CONTENT_TYPE_FILE; + const isMultipart = hasMimeType && body.mimeType === CONTENT_TYPE_FORM_DATA; + const isFormUrlEncoded = hasMimeType && body.mimeType === CONTENT_TYPE_FORM_URLENCODED; + const isText = !isFile && !isMultipart; + const willBeFile = mimeType === CONTENT_TYPE_FILE; + const willBeMultipart = mimeType === CONTENT_TYPE_FORM_DATA; + const willBeGraphQL = mimeType === CONTENT_TYPE_GRAPHQL; + const willConvertToText = !willBeGraphQL && !willBeFile && !willBeMultipart; + const willPreserveText = willConvertToText && isText; + const willPreserveForm = isFormUrlEncoded && willBeMultipart; + + if (!isEmpty && !willPreserveText && !willPreserveForm) { + await showModal(AlertModal, { + title: 'Switch Body Type?', + message: 'Current body will be lost. Are you sure you want to continue?', + addCancel: true, + }); } onChange(mimeType); @@ -87,40 +88,52 @@ const MimeTypeItem: FC<{ ); }; +MimeTypeItem.displayName = DropdownItem.name; -export const ContentTypeDropdown: FC = ({ - children, - className, - onChange, - ...extraProps -}) => ( - - {children} - - - Structured - - - - - - - - Text - - - - - - - - - - - Other - - - - - -); +export const ContentTypeDropdown: FC = ({ onChange }) => { + const activeRequest = useSelector(selectActiveRequest); + + if (!activeRequest) { + return null; + } + const { body } = activeRequest; + const hasMimeType = 'mimeType' in body; + const hasParams = body && 'params' in body && body.params; + const numBodyParams = hasParams ? body.params?.filter(({ disabled }) => !disabled).length : 0; + + return ( + + + {hasMimeType ? getContentTypeName(body.mimeType) : 'Body'} + {numBodyParams ? {numBodyParams} : null} + + + + + Structured + + + + + + + + Text + + + + + + + + + + + Other + + + + + + ); +}; diff --git a/packages/insomnia/src/ui/components/panes/request-pane.tsx b/packages/insomnia/src/ui/components/panes/request-pane.tsx index 27ac2ed27..43eff0247 100644 --- a/packages/insomnia/src/ui/components/panes/request-pane.tsx +++ b/packages/insomnia/src/ui/components/panes/request-pane.tsx @@ -4,7 +4,6 @@ import React, { FC, useCallback, useEffect, useRef } from 'react'; import { Tab, TabList, TabPanel, Tabs } from 'react-tabs'; import { useMount } from 'react-use'; -import { getAuthTypeName, getContentTypeName } from '../../../common/constants'; import * as models from '../../../models'; import { queryAllWorkspaceUrls } from '../../../models/helpers/query-all-workspace-urls'; import type { @@ -147,12 +146,6 @@ export const RequestPane: FC = ({ ); } - let numBodyParams = 0; - - if (request.body && request.body.params) { - numBodyParams = request.body.params.filter(p => !p.disabled).length; - } - const numParameters = request.parameters.filter(p => !p.disabled).length; const numHeaders = request.headers.filter(h => !h.disabled).length; const urlHasQueryParameters = request.url.indexOf('?') >= 0; @@ -185,24 +178,12 @@ export const RequestPane: FC = ({ - {typeof request.body.mimeType === 'string' - ? getContentTypeName(request.body.mimeType) - : 'Body'} - {numBodyParams ? {numBodyParams} : null} - - + /> - {getAuthTypeName(request.authentication.type) || 'Auth'} - - + />