Refactor/pre request routing (#5481)

* improve prop typings

* tidy up error a little
This commit is contained in:
Jack Kavanagh 2022-12-05 12:18:30 +01:00 committed by GitHub
parent a2a6b4bce8
commit cfc1ac09aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 59 additions and 62 deletions

View File

@ -11,8 +11,8 @@ describe('queryAllWorkspaceUrls', () => {
const w = await models.workspace.create({
name: 'Workspace',
});
await expect(queryAllWorkspaceUrls(w, models.request.type)).resolves.toHaveLength(0);
await expect(queryAllWorkspaceUrls(w, models.grpcRequest.type)).resolves.toHaveLength(0);
await expect(queryAllWorkspaceUrls(w._id, models.request.type)).resolves.toHaveLength(0);
await expect(queryAllWorkspaceUrls(w._id, models.grpcRequest.type)).resolves.toHaveLength(0);
});
it('should return urls and exclude that of the selected request', async () => {
@ -78,17 +78,17 @@ describe('queryAllWorkspaceUrls', () => {
url: 'diff.url',
});
// All items
await expect(queryAllWorkspaceUrls(w, models.request.type)).resolves.toStrictEqual(
await expect(queryAllWorkspaceUrls(w._id, models.request.type)).resolves.toStrictEqual(
expect.arrayContaining([r1.url, r2.url]),
);
await expect(queryAllWorkspaceUrls(w, models.grpcRequest.type)).resolves.toStrictEqual(
await expect(queryAllWorkspaceUrls(w._id, models.grpcRequest.type)).resolves.toStrictEqual(
expect.arrayContaining([gr1.url, gr2.url]),
);
// Ignore url of the selected request id
await expect(queryAllWorkspaceUrls(w, models.request.type, r1._id)).resolves.toStrictEqual(
await expect(queryAllWorkspaceUrls(w._id, models.request.type, r1._id)).resolves.toStrictEqual(
expect.arrayContaining([r2.url]),
);
await expect(queryAllWorkspaceUrls(w, models.grpcRequest.type, gr1._id)).resolves.toStrictEqual(
await expect(queryAllWorkspaceUrls(w._id, models.grpcRequest.type, gr1._id)).resolves.toStrictEqual(
expect.arrayContaining([gr2.url]),
);
});

View File

@ -1,13 +1,16 @@
import { database as db } from '../../common/database';
import * as models from '../../models';
import { invariant } from '../../utils/invariant';
import { GrpcRequest, type as GrpcRequestType } from '../grpc-request';
import { Request, type as RequestType } from '../request';
import { Workspace } from '../workspace';
export const queryAllWorkspaceUrls = async (
workspace: Workspace | null,
workspaceId: string,
reqType: typeof RequestType | typeof GrpcRequestType,
reqId = 'n/a',
): Promise<string[]> => {
const workspace = await models.workspace.getById(workspaceId);
invariant(workspace, `Workspace ${workspaceId} not found`);
const docs = await db.withDescendants(workspace, reqType) as (Request | GrpcRequest)[];
const urls = docs
.filter(

View File

@ -23,7 +23,7 @@ interface Props {
className?: string;
fallbackValue?: string;
onEditStart?: () => void;
onSubmit: (value?: string) => void;
onSubmit: (value: string) => void;
preventBlank?: boolean;
renderReadView?: (value: string | undefined, props: any) => ReactElement<HighlightProps>;
singleClick?: boolean;
@ -63,7 +63,7 @@ export const Editable: FC<Props> = ({
const handleEditEnd = useCallback(() => {
if (shouldSave(value, inputRef.current?.value.trim(), preventBlank)) {
// Don't run onSubmit for values that haven't been changed
onSubmit(inputRef.current?.value.trim());
onSubmit(inputRef.current?.value.trim() || '');
}
// This timeout prevents the UI from showing the old value after submit.

View File

@ -3,7 +3,6 @@ import { useSelector } from 'react-redux';
import * as models from '../../../models';
import type { Environment } from '../../../models/environment';
import type { Workspace } from '../../../models/workspace';
import { selectActiveWorkspaceMeta, selectEnvironments, selectHotKeyRegistry } from '../../redux/selectors';
import { type DropdownHandle, Dropdown } from '../base/dropdown/dropdown';
import { DropdownButton } from '../base/dropdown/dropdown-button';
@ -17,12 +16,12 @@ import { Tooltip } from '../tooltip';
interface Props {
activeEnvironment?: Environment | null;
workspace: Workspace;
workspaceId: string;
}
export const EnvironmentsDropdown: FC<Props> = ({
activeEnvironment,
workspace,
workspaceId,
}) => {
const environments = useSelector(selectEnvironments);
const hotKeyRegistry = useSelector(selectHotKeyRegistry);
@ -38,7 +37,7 @@ export const EnvironmentsDropdown: FC<Props> = ({
});
// NOTE: Base environment might not exist if the users hasn't managed environments yet.
const baseEnvironment = environments.find(environment => environment.parentId === workspace._id);
const baseEnvironment = environments.find(environment => environment.parentId === workspaceId);
const subEnvironments = environments
.filter(environment => environment.parentId === (baseEnvironment && baseEnvironment._id))
.sort((e1, e2) => e1.metaSortKey - e2.metaSortKey);

View File

@ -22,7 +22,6 @@ import {
newBodyFormUrlEncoded,
newBodyRaw,
} from '../../../../models/request';
import type { Settings } from '../../../../models/settings';
import type { Workspace } from '../../../../models/workspace';
import { NunjucksEnabledProvider } from '../../../context/nunjucks/nunjucks-enabled-context';
import { AskModal } from '../../modals/ask-modal';
@ -38,35 +37,28 @@ import { UrlEncodedEditor } from './url-encoded-editor';
interface Props {
request: Request;
workspace: Workspace;
settings: Settings;
environmentId: string;
}
export const BodyEditor: FC<Props> = ({
request,
workspace,
settings,
environmentId,
}) => {
const handleRawChange = useCallback((rawValue: string) => {
const oldContentType = request.body.mimeType || '';
const body = newBodyRaw(rawValue, oldContentType);
models.request.update(request, { body });
models.request.update(request, { body: newBodyRaw(rawValue, request.body.mimeType || '') });
}, [request]);
const handleGraphQLChange = useCallback((content: string) => {
const body = newBodyRaw(content, CONTENT_TYPE_GRAPHQL);
models.request.update(request, { body });
models.request.update(request, { body: newBodyRaw(content, CONTENT_TYPE_GRAPHQL) });
}, [request]);
const handleFormUrlEncodedChange = useCallback((parameters: RequestBodyParameter[]) => {
const body = newBodyFormUrlEncoded(parameters);
models.request.update(request, { body });
models.request.update(request, { body: newBodyFormUrlEncoded(parameters) });
}, [request]);
const handleFormChange = useCallback((parameters: RequestBodyParameter[]) => {
const body = newBodyForm(parameters);
models.request.update(request, { body });
models.request.update(request, { body: newBodyForm(parameters) });
}, [request]);
const handleFileChange = async (path: string) => {
@ -118,7 +110,7 @@ export const BodyEditor: FC<Props> = ({
} else if (mimeType === CONTENT_TYPE_FILE) {
return <FileEditor key={uniqueKey} onChange={handleFileChange} path={fileName || ''} />;
} else if (mimeType === CONTENT_TYPE_GRAPHQL) {
return <GraphQLEditor key={uniqueKey} uniquenessKey={uniqueKey} request={request} settings={settings} workspaceId={workspace._id} environmentId={environmentId} onChange={handleGraphQLChange} />;
return <GraphQLEditor key={uniqueKey} uniquenessKey={uniqueKey} request={request} workspaceId={workspace._id} environmentId={environmentId} onChange={handleGraphQLChange} />;
} else if (!isBodyEmpty) {
const contentType = getContentTypeFromHeaders(request.headers) || mimeType;
return <RawEditor uniquenessKey={uniqueKey} contentType={contentType || 'text/plain'} content={request.body.text || ''} onChange={handleRawChange} />;

View File

@ -3,7 +3,12 @@ import React, { FC } from 'react';
import { KeyValueEditor } from '../../key-value-editor/key-value-editor';
interface Props {
onChange: Function;
onChange: (c: {
name: string;
value: string;
description?: string;
disabled?: boolean;
}[]) => void;
parameters: any[];
}

View File

@ -10,6 +10,7 @@ import { Maybe } from 'graphql-language-service';
import prettier from 'prettier';
import React, { FC, useEffect, useRef, useState } from 'react';
import ReactDOM from 'react-dom';
import { useSelector } from 'react-redux';
import { jarFromCookies } from '../../../../common/cookies';
import { markdownToHTML } from '../../../../common/markdown-to-html';
@ -18,11 +19,11 @@ import { getRenderContext, render, RENDER_PURPOSE_SEND } from '../../../../commo
import type { ResponsePatch } from '../../../../main/network/libcurl-promise';
import * as models from '../../../../models';
import type { Request } from '../../../../models/request';
import type { Settings } from '../../../../models/settings';
import { axiosRequest } from '../../../../network/axios-request';
import { jsonPrettify } from '../../../../utils/prettify/json';
import { setDefaultProtocol } from '../../../../utils/url/protocol';
import { buildQueryStringFromParams, joinUrlAndQueryString } from '../../../../utils/url/querystring';
import { selectSettings } from '../../../redux/selectors';
import { Dropdown } from '../../base/dropdown/dropdown';
import { DropdownButton } from '../../base/dropdown/dropdown-button';
import { DropdownDivider } from '../../base/dropdown/dropdown-divider';
@ -151,7 +152,6 @@ interface GraphQLBody {
interface Props {
onChange: (value: string) => void;
request: Request;
settings: Settings;
environmentId: string;
className?: string;
uniquenessKey?: string;
@ -172,7 +172,6 @@ interface State {
export const GraphQLEditor: FC<Props> = ({
request,
environmentId,
settings,
onChange,
className,
uniquenessKey,
@ -252,12 +251,13 @@ export const GraphQLEditor: FC<Props> = ({
};
}, [environmentId, request._id, request.url, workspaceId]);
const { editorIndentWithTabs, editorIndentSize } = useSelector(selectSettings);
const beautifyRequestBody = () => {
const { body } = state;
const prettyQuery = prettier.format(body.query, {
parser: 'graphql',
useTabs: settings.editorIndentWithTabs,
tabWidth: settings.editorIndentSize,
useTabs: editorIndentWithTabs,
tabWidth: editorIndentSize,
});
const prettyVariables = body.variables && JSON.parse(jsonPrettify(JSON.stringify(body.variables)));
changeQuery(prettyQuery);

View File

@ -3,7 +3,12 @@ import React, { FC } from 'react';
import { KeyValueEditor } from '../../key-value-editor/key-value-editor';
interface Props {
onChange: Function;
onChange: (c: {
name: string;
value: string;
description?: string;
disabled?: boolean;
}[]) => void;
parameters: any[];
}

View File

@ -33,7 +33,12 @@ interface Props {
isDisabled?: boolean;
isWebSocketRequest?: boolean;
namePlaceholder?: string;
onChange: Function;
onChange: (c: {
name: string;
value: string;
description?: string;
disabled?: boolean;
}[]) => void;
pairs: Pair[];
valuePlaceholder?: string;
}

View File

@ -1,9 +1,7 @@
import React, { forwardRef, useImperativeHandle, useRef, useState } from 'react';
import { useSelector } from 'react-redux';
import * as session from '../../../account/session';
import { getAppVersion, getProductName } from '../../../common/constants';
import { selectSettings } from '../../redux/selectors';
import { type ModalHandle, Modal, ModalProps } from '../base/modal';
import { ModalBody } from '../base/modal-body';
import { ModalHeader } from '../base/modal-header';
@ -26,7 +24,6 @@ export const TAB_INDEX_SHORTCUTS = 'keyboard';
export const TAB_INDEX_THEMES = 'themes';
export const TAB_INDEX_PLUGINS = 'plugins';
export const SettingsModal = forwardRef<SettingsModalHandle, ModalProps>((props, ref) => {
const settings = useSelector(selectSettings);
const [defaultTabKey, setDefaultTabKey] = useState('general');
const modalRef = useRef<ModalHandle>(null);
const email = session.isLoggedIn() ? session.getFullName() : null;
@ -79,7 +76,7 @@ export const SettingsModal = forwardRef<SettingsModalHandle, ModalProps>((props,
</TabItem>
<TabItem key="plugins" title="Plugins">
<PanelContainer className="pad">
<Plugins settings={settings} />
<Plugins />
</PanelContainer>
</TabItem>
</Tabs>

View File

@ -138,10 +138,7 @@ export const GrpcRequestPane: FunctionComponent<Props> = ({
defaultValue={activeRequest.url}
placeholder="grpcb.in:9000"
onChange={url => models.grpcRequest.update(activeRequest, { url })}
getAutocompleteConstants={async () => {
const workspace = await models.workspace.getById(workspaceId);
return queryAllWorkspaceUrls(workspace, models.grpcRequest.type, activeRequest._id);
}}
getAutocompleteConstants={() => queryAllWorkspaceUrls(workspaceId, models.grpcRequest.type, activeRequest._id)}
/>
</StyledUrlEditor>
<StyledDropdown>

View File

@ -88,10 +88,6 @@ export const RequestPane: FC<Props> = ({
handleEditDescription(true);
}, [handleEditDescription]);
const autocompleteUrls = useCallback(() => {
return queryAllWorkspaceUrls(workspace, models.request.type, request?._id);
}, [workspace, request]);
const handleUpdateSettingsUseBulkHeaderEditor = useCallback(() => {
models.settings.update(settings, { useBulkHeaderEditor:!settings.useBulkHeaderEditor });
}, [settings]);
@ -178,7 +174,7 @@ export const RequestPane: FC<Props> = ({
ref={requestUrlBarRef}
uniquenessKey={uniqueKey}
onUrlChange={updateRequestUrl}
handleAutocompleteUrls={autocompleteUrls}
handleAutocompleteUrls={() => queryAllWorkspaceUrls(workspace._id, models.request.type, request?._id)}
nunjucksPowerUserMode={settings.nunjucksPowerUserMode}
request={request}
setLoading={setLoading}
@ -192,7 +188,6 @@ export const RequestPane: FC<Props> = ({
request={request}
workspace={workspace}
environmentId={environmentId}
settings={settings}
/>
</TabItem>
<TabItem key="auth" title={<AuthDropdown />}>

View File

@ -1,5 +1,6 @@
import * as path from 'path';
import React, { FC, useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import {
NPM_PACKAGE_BASE,
@ -8,21 +9,17 @@ import {
import { docsPlugins } from '../../../common/documentation';
import { clickLink, getDataDirectory } from '../../../common/electron-helpers';
import * as models from '../../../models';
import type { Settings } from '../../../models/settings';
import { createPlugin } from '../../../plugins/create';
import type { Plugin } from '../../../plugins/index';
import { getPlugins } from '../../../plugins/index';
import { reload } from '../../../templating/index';
import { selectSettings } from '../../redux/selectors';
import { CopyButton } from '../base/copy-button';
import { Link } from '../base/link';
import { HelpTooltip } from '../help-tooltip';
import { showAlert, showPrompt } from '../modals';
import { Button } from '../themed-button';
interface Props {
settings: Settings;
}
interface State {
plugins: Plugin[];
npmPluginValue: string;
@ -31,7 +28,7 @@ interface State {
isInstallingFromNpm: boolean;
isRefreshingPlugins: boolean;
}
export const Plugins: FC<Props> = ({ settings }) => {
export const Plugins: FC = () => {
const [state, setState] = useState<State>({
plugins: [],
npmPluginValue: '',
@ -48,6 +45,7 @@ export const Plugins: FC<Props> = ({ settings }) => {
isRefreshingPlugins,
npmPluginValue,
} = state;
const settings = useSelector(selectSettings);
useEffect(() => {
refreshPlugins();

View File

@ -192,7 +192,7 @@ export const SidebarLayout: FC<Props> = ({
renderPaneTwo,
renderPageSidebar,
}) => {
const settings = useSelector(selectSettings);
const { forceVerticalLayout } = useSelector(selectSettings);
const activeWorkspaceMeta = useSelector(selectActiveWorkspaceMeta);
const reduxPaneHeight = useSelector(selectPaneHeight);
const reduxPaneWidth = useSelector(selectPaneWidth);
@ -359,7 +359,7 @@ export const SidebarLayout: FC<Props> = ({
<LayoutGrid
key="wrapper"
id="wrapper"
orientation={settings.forceVerticalLayout ? 'vertical' : 'horizontal'}
orientation={forceVerticalLayout ? 'vertical' : 'horizontal'}
style={{
gridTemplateColumns: gridColumns,
gridTemplateRows: gridRows,

View File

@ -173,7 +173,7 @@ export const Debug: FC = () => {
<div className="sidebar__menu">
<EnvironmentsDropdown
activeEnvironment={activeEnvironment}
workspace={activeWorkspace}
workspaceId={activeWorkspace._id}
/>
<button className="btn btn--super-compact" onClick={showCookiesModal}>
<div className="sidebar__menu__thing">

View File

@ -44,8 +44,8 @@ export const ErrorRoute: FC = () => {
return (
<Container>
<h1>Application Error</h1>
<p>
<h1 style={{ color: 'var(--color-font)' }}>Application Error</h1>
<p style={{ color: 'var(--color-font)' }}>
Failed to render. Please send the following error to{' '}
<Mailto
email="support@insomnia.rest"
@ -54,8 +54,9 @@ export const ErrorRoute: FC = () => {
/>
.
</p>
<h2>Message:</h2>
<pre>{errorMessage}</pre>
<span style={{ color: 'var(--color-font)' }}>Message:
<code style={{ wordBreak: 'break-word', margin: 'var(--padding-sm)' }}>{errorMessage}</code>
</span>
<Button onClick={() => navigate(`/organization/${DEFAULT_ORGANIZATION_ID}/project/${DEFAULT_PROJECT_ID}`)}>
Try to reload the app{' '}
<span>{navigation.state === 'loading' ? <Spinner /> : null}</span>