mirror of
https://github.com/Kong/insomnia
synced 2024-11-07 22:30:15 +00:00
Refactor/pre request routing (#5481)
* improve prop typings * tidy up error a little
This commit is contained in:
parent
a2a6b4bce8
commit
cfc1ac09aa
@ -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]),
|
||||
);
|
||||
});
|
||||
|
@ -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(
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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} />;
|
||||
|
@ -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[];
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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[];
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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 />}>
|
||||
|
@ -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();
|
||||
|
@ -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,
|
||||
|
@ -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">
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user