Adds dropdown items for New Folder (and requisite work to accomplish this) (#4862)

Co-authored-by: Dimitri Mitropoulos <dimitropoulos@users.noreply.github.com>
Co-authored-by: gatzjames <jamesgatzos@gmail.com>
This commit is contained in:
authored and GitHub committed 2022-06-14 10:00:12 -04:00
1 parent 4e85928998
commit d1f4063e7d
14 files changed
+578 -614

No files matched your search

+13 -12
View File
@@ -73,6 +73,7 @@
"@types/fs-extra": "^5.1.0",
"@types/hapi__hawk": "^8.0.2",
"@types/js-yaml": "^4.0.1",
"@types/jshint": "^2.12.1",
"@types/license-checker": "^25.0.1",
"@types/marked": "^4.0.2",
"@types/mime-types": "^2.1.1",
@@ -4675,12 +4676,6 @@
"integrity": "sha512-xdOvNmXmrZqqPy3kuCQ+fz6wA0xU5pji9cd1nDrflWaAWtYLLGk5ykW0H6yg5TVyehHP1pfmuuSaZkhP+kspVA==",
"dev": true
},
"node_modules/@types/jshint": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/@types/jshint/-/jshint-2.12.1.tgz",
"integrity": "sha512-Sen/qexrVc74JFfqPfaRB5zF/aIuziEmENKFQgpUNU23Ebja/aAFXdnPpiB9qumE8QWLCHFinuVbx5THc5tWkw==",
"dev": true
},
"node_modules/@types/jsdom": {
"version": "16.2.14",
"resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-16.2.14.tgz",
@@ -4692,6 +4687,12 @@
"@types/tough-cookie": "*"
}
},
"node_modules/@types/jshint": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/@types/jshint/-/jshint-2.12.1.tgz",
"integrity": "sha512-Sen/qexrVc74JFfqPfaRB5zF/aIuziEmENKFQgpUNU23Ebja/aAFXdnPpiB9qumE8QWLCHFinuVbx5THc5tWkw==",
"dev": true
},
"node_modules/@types/json-schema": {
"version": "7.0.9",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
@@ -24041,12 +24042,6 @@
"integrity": "sha512-xdOvNmXmrZqqPy3kuCQ+fz6wA0xU5pji9cd1nDrflWaAWtYLLGk5ykW0H6yg5TVyehHP1pfmuuSaZkhP+kspVA==",
"dev": true
},
"@types/jshint": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/@types/jshint/-/jshint-2.12.1.tgz",
"integrity": "sha512-Sen/qexrVc74JFfqPfaRB5zF/aIuziEmENKFQgpUNU23Ebja/aAFXdnPpiB9qumE8QWLCHFinuVbx5THc5tWkw==",
"dev": true
},
"@types/jsdom": {
"version": "16.2.14",
"resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-16.2.14.tgz",
@@ -24058,6 +24053,12 @@
"@types/tough-cookie": "*"
}
},
"@types/jshint": {
"version": "2.12.1",
"resolved": "https://registry.npmjs.org/@types/jshint/-/jshint-2.12.1.tgz",
"integrity": "sha512-Sen/qexrVc74JFfqPfaRB5zF/aIuziEmENKFQgpUNU23Ebja/aAFXdnPpiB9qumE8QWLCHFinuVbx5THc5tWkw==",
"dev": true
},
"@types/json-schema": {
"version": "7.0.9",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz",
@@ -1,10 +1,8 @@
import { autoBindMethodsForReact } from 'class-autobind-decorator';
import classnames from 'classnames';
import { HotKeyRegistry } from 'insomnia-common';
import React, { PureComponent } from 'react';
import { connect } from 'react-redux';
import React, { forwardRef, useCallback, useImperativeHandle, useRef, useState } from 'react';
import { useSelector } from 'react-redux';
import { AUTOBIND_CFG } from '../../../common/constants';
import { hotKeyRefs } from '../../../common/hotkeys';
import { RENDER_PURPOSE_NO_RENDER } from '../../../common/render';
import * as models from '../../../models';
@@ -12,8 +10,8 @@ import type { RequestGroup } from '../../../models/request-group';
import type { RequestGroupAction } from '../../../plugins';
import { getRequestGroupActions } from '../../../plugins';
import * as pluginContexts from '../../../plugins/context/index';
import { RootState } from '../../redux/modules';
import { selectActiveEnvironment, selectActiveProject } from '../../redux/selectors';
import { createRequest, CreateRequestType } from '../../hooks/create-request';
import { selectActiveEnvironment, selectActiveProject, selectActiveWorkspace } from '../../redux/selectors';
import { Dropdown, DropdownProps } from '../base/dropdown/dropdown';
import { DropdownButton } from '../base/dropdown/dropdown-button';
import { DropdownDivider } from '../base/dropdown/dropdown-divider';
@@ -23,154 +21,160 @@ import { PromptButton } from '../base/prompt-button';
import { showError, showModal } from '../modals';
import { EnvironmentEditModal } from '../modals/environment-edit-modal';
type ReduxProps = ReturnType<typeof mapStateToProps>;
const mapStateToProps = (state: RootState) => ({
activeProject: selectActiveProject(state),
activeEnvironment: selectActiveEnvironment(state),
});
interface Props extends ReduxProps, Partial<DropdownProps> {
interface Props extends Partial<DropdownProps> {
requestGroup: RequestGroup;
hotKeyRegistry: HotKeyRegistry;
handleCreateRequest: (id: string) => any;
handleDuplicateRequestGroup: (requestGroup: RequestGroup) => any;
handleShowSettings: (requestGroup: RequestGroup) => any;
handleCreateRequestGroup: (requestGroup: string) => any;
}
interface State {
actionPlugins: RequestGroupAction[];
loadingActions: Record<string, boolean>;
interface RequestGroupActionsDropdownHandle {
show: () => void;
}
@autoBindMethodsForReact(AUTOBIND_CFG)
export class UnconnectedRequestGroupActionsDropdown extends PureComponent<Props, State> {
_dropdown: Dropdown | null = null;
state: State = {
actionPlugins: [],
loadingActions: {},
};
export const RequestGroupActionsDropdown = forwardRef<RequestGroupActionsDropdownHandle, Props>(({
requestGroup,
hotKeyRegistry,
handleShowSettings,
handleDuplicateRequestGroup,
handleCreateRequestGroup,
...other
}, ref) => {
const [actionPlugins, setActionPlugins] = useState<RequestGroupAction[]>([]);
const [loadingActions, setLoadingActions] = useState< Record<string, boolean>>({});
const dropdownRef = useRef<Dropdown | null>(null);
_setDropdownRef(dropdown: Dropdown) {
this._dropdown = dropdown;
}
const activeProject = useSelector(selectActiveProject);
const activeEnvironment = useSelector(selectActiveEnvironment);
const activeWorkspace = useSelector(selectActiveWorkspace);
const activeWorkspaceId = activeWorkspace?._id;
async _handleRequestCreate() {
this.props.handleCreateRequest(this.props.requestGroup._id);
}
_handleRequestGroupDuplicate() {
this.props.handleDuplicateRequestGroup(this.props.requestGroup);
}
async _handleRequestGroupCreate() {
this.props.handleCreateRequestGroup(this.props.requestGroup._id);
}
async _handleDeleteFolder() {
await models.stats.incrementDeletedRequestsForDescendents(this.props.requestGroup);
models.requestGroup.remove(this.props.requestGroup);
}
_handleEditEnvironment() {
showModal(EnvironmentEditModal, this.props.requestGroup);
}
async onOpen() {
const plugins = await getRequestGroupActions();
this.setState({
actionPlugins: plugins,
});
}
async show() {
this._dropdown?.show();
}
async _handlePluginClick(p: RequestGroupAction) {
this.setState(state => ({
loadingActions: { ...state.loadingActions, [p.label]: true },
}));
try {
const { activeEnvironment, requestGroup, activeProject } = this.props;
const activeEnvironmentId = activeEnvironment ? activeEnvironment._id : null;
const context = {
...(pluginContexts.app.init(RENDER_PURPOSE_NO_RENDER) as Record<string, any>),
...pluginContexts.data.init(activeProject._id),
...(pluginContexts.store.init(p.plugin) as Record<string, any>),
...(pluginContexts.network.init(activeEnvironmentId) as Record<string, any>),
};
const requests = await models.request.findByParentId(requestGroup._id);
requests.sort((a, b) => a.metaSortKey - b.metaSortKey);
await p.action(context, {
requestGroup,
requests,
});
} catch (err) {
showError({
title: 'Plugin Action Failed',
error: err,
});
const create = useCallback((requestType: CreateRequestType) => {
if (activeWorkspaceId) {
createRequest({ parentId: requestGroup._id, requestType, workspaceId: activeWorkspaceId });
}
}, [activeWorkspaceId, requestGroup._id]);
this.setState(state => ({
loadingActions: { ...state.loadingActions, [p.label]: false },
}));
this._dropdown?.hide();
}
useImperativeHandle(ref, () => ({
show: () => {
dropdownRef.current?.show();
},
}));
render() {
const {
// eslint-disable-line @typescript-eslint/no-unused-vars
requestGroup,
// eslint-disable-line @typescript-eslint/no-unused-vars
hotKeyRegistry,
...other
} = this.props;
const { actionPlugins, loadingActions } = this.state;
return (
<Dropdown ref={this._setDropdownRef} onOpen={this.onOpen} {...other}>
<DropdownButton>
<i className="fa fa-caret-down" />
</DropdownButton>
<DropdownItem onClick={() => this._handleRequestCreate()}>
<i className="fa fa-plus-circle" /> New Request
<DropdownHint keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_CREATE_HTTP.id]} />
</DropdownItem>
<DropdownItem onClick={this._handleRequestGroupCreate}>
<i className="fa fa-folder" /> New Folder
<DropdownHint keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_SHOW_CREATE_FOLDER.id]} />
</DropdownItem>
<DropdownDivider />
<DropdownItem onClick={this._handleRequestGroupDuplicate}>
<i className="fa fa-copy" /> Duplicate
</DropdownItem>
<DropdownItem onClick={this._handleEditEnvironment}>
<i className="fa fa-code" /> Environment
</DropdownItem>
<DropdownItem buttonClass={PromptButton} addIcon onClick={this._handleDeleteFolder}>
<i className="fa fa-trash-o" /> Delete
</DropdownItem>
{actionPlugins.length > 0 && <DropdownDivider>Plugins</DropdownDivider>}
{actionPlugins.map((p: RequestGroupAction) => (
<DropdownItem key={p.label} onClick={() => this._handlePluginClick(p)} stayOpenAfterClick>
{loadingActions[p.label] ? (
<i className="fa fa-refresh fa-spin" />
) : (
<i className={classnames('fa', p.icon || 'fa-code')} />
)}
{p.label}
</DropdownItem>
))}
<DropdownDivider />
<DropdownItem onClick={this.props.handleShowSettings}>
<i className="fa fa-wrench" /> Settings
</DropdownItem>
</Dropdown>
);
}
}
const onOpen = useCallback(() => {
getRequestGroupActions().then(actionPlugins => {
setActionPlugins(actionPlugins);
});
}, []);
export const RequestGroupActionsDropdown = connect(mapStateToProps, null, null, { forwardRef: true })(UnconnectedRequestGroupActionsDropdown);
const handleRequestGroupDuplicate = useCallback(() => {
handleDuplicateRequestGroup(requestGroup);
}, [requestGroup, handleDuplicateRequestGroup]);
const handleRequestGroupCreate = useCallback(() => {
handleCreateRequestGroup(requestGroup._id);
}, [handleCreateRequestGroup, requestGroup._id]);
const handleDeleteFolder = useCallback(() => {
models.stats.incrementDeletedRequestsForDescendents(requestGroup).then(() => {
models.requestGroup.remove(requestGroup);
});
}, [requestGroup]);
const handleEditEnvironment = useCallback(() => {
showModal(EnvironmentEditModal, requestGroup);
}, [requestGroup]);
const handlePluginClick = useCallback(({ label, plugin, action }: RequestGroupAction) => {
const fn = async () => {
setLoadingActions({ ...loadingActions, [label]: true });
try {
const activeEnvironmentId = activeEnvironment ? activeEnvironment._id : null;
const context = {
...(pluginContexts.app.init(RENDER_PURPOSE_NO_RENDER) as Record<string, any>),
...pluginContexts.data.init(activeProject._id),
...(pluginContexts.store.init(plugin) as Record<string, any>),
...(pluginContexts.network.init(activeEnvironmentId) as Record<string, any>),
};
const requests = await models.request.findByParentId(requestGroup._id);
requests.sort((a, b) => a.metaSortKey - b.metaSortKey);
await action(context, {
requestGroup,
requests,
});
} catch (err) {
showError({
title: 'Plugin Action Failed',
error: err,
});
}
setLoadingActions({
...loadingActions,
[label]: false,
});
dropdownRef.current?.hide();
};
fn();
}, [dropdownRef, loadingActions, activeEnvironment, requestGroup, activeProject]);
return (
<Dropdown ref={dropdownRef} onOpen={onOpen} {...other}>
<DropdownButton>
<i className="fa fa-caret-down" />
</DropdownButton>
<DropdownItem value="HTTP" onClick={create}>
<i className="fa fa-plus-circle" />New HTTP Request
<DropdownHint keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_CREATE_HTTP.id]} />
</DropdownItem>
<DropdownItem value="GraphQL" onClick={create}>
<i className="fa fa-plus-circle" />New GraphQL Request
</DropdownItem>
<DropdownItem value="gRPC" onClick={create}>
<i className="fa fa-plus-circle" />New gRPC Request
</DropdownItem>
<DropdownItem onClick={handleRequestGroupCreate}>
<i className="fa fa-folder" /> New Folder
<DropdownHint keyBindings={hotKeyRegistry[hotKeyRefs.REQUEST_SHOW_CREATE_FOLDER.id]} />
</DropdownItem>
<DropdownDivider />
<DropdownItem onClick={handleRequestGroupDuplicate}>
<i className="fa fa-copy" /> Duplicate
</DropdownItem>
<DropdownItem onClick={handleEditEnvironment}>
<i className="fa fa-code" /> Environment
</DropdownItem>
<DropdownItem buttonClass={PromptButton} addIcon onClick={handleDeleteFolder}>
<i className="fa fa-trash-o" /> Delete
</DropdownItem>
{actionPlugins.length > 0 && <DropdownDivider>Plugins</DropdownDivider>}
{actionPlugins.map((requestGroupAction: RequestGroupAction) => (
<DropdownItem key={requestGroupAction.label} onClick={() => handlePluginClick(requestGroupAction)} stayOpenAfterClick>
{loadingActions[requestGroupAction.label] ? (
<i className="fa fa-refresh fa-spin" />
) : (
<i className={classnames('fa', requestGroupAction.icon || 'fa-code')} />
)}
{requestGroupAction.label}
</DropdownItem>
))}
<DropdownDivider />
<DropdownItem onClick={handleShowSettings}>
<i className="fa fa-wrench" /> Settings
</DropdownItem>
</Dropdown>
);
});
RequestGroupActionsDropdown.displayName = 'RequestGroupActionsDropdown';
@@ -2,24 +2,29 @@ import React, { FC, useCallback } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { hotKeyRefs } from '../../../common/hotkeys';
import { createRequest } from '../../hooks/create-request';
import { ForceToWorkspace } from '../../redux/modules/helpers';
import { importFile } from '../../redux/modules/import';
import { selectActiveWorkspace, selectSettings } from '../../redux/selectors';
import { Hotkey } from '../hotkey';
import { Pane, PaneBody, PaneHeader } from './pane';
interface Props {
handleCreateRequest: () => void;
}
export const PlaceholderRequestPane: FC<Props> = ({
handleCreateRequest,
}) => {
export const PlaceholderRequestPane: FC = () => {
const dispatch = useDispatch();
const { hotKeyRegistry } = useSelector(selectSettings);
const workspaceId = useSelector(selectActiveWorkspace)?._id;
const handleImportFile = useCallback(() => dispatch(importFile({ workspaceId, forceToWorkspace: ForceToWorkspace.current })), [workspaceId, dispatch]);
const createHttpRequest = useCallback(() => {
if (workspaceId) {
createRequest({
requestType: 'HTTP',
parentId: workspaceId,
workspaceId: workspaceId,
});
}
}, [workspaceId]);
return (
<Pane type="request">
<PaneHeader />
@@ -67,8 +72,8 @@ export const PlaceholderRequestPane: FC<Props> = ({
<button className="btn inline-block btn--clicky" onClick={handleImportFile}>
Import from File
</button>
<button className="btn inline-block btn--clicky" onClick={() => handleCreateRequest()}>
New Request
<button className="btn inline-block btn--clicky" onClick={createHttpRequest}>
New HTTP Request
</button>
</div>
</div>
@@ -37,7 +37,6 @@ interface Props {
forceRefreshCounter: number;
forceUpdateRequest: (r: Request, patch: Partial<Request>) => Promise<Request>;
forceUpdateRequestHeaders: (r: Request, headers: RequestHeader[]) => Promise<Request>;
handleCreateRequest: () => void;
handleGenerateCode: Function;
handleImport: Function;
handleSend: () => void;
@@ -64,7 +63,6 @@ export const RequestPane: FC<Props> = ({
forceRefreshCounter,
forceUpdateRequest,
forceUpdateRequestHeaders,
handleCreateRequest,
handleGenerateCode,
handleImport,
handleSend,
@@ -145,9 +143,7 @@ export const RequestPane: FC<Props> = ({
if (!request) {
return (
<PlaceholderRequestPane
handleCreateRequest={handleCreateRequest}
/>
<PlaceholderRequestPane />
);
}
@@ -27,8 +27,14 @@ export const targetCollect = (connect: DropTargetConnector, monitor: DropTargetM
});
export const isAbove = (monitor: DropTargetMonitor, component: any) => {
const hoveredNode = ReactDOM.findDOMNode(component);
// @ts-expect-error -- TSCONVERSION
let hoveredNode;
try {
// Try to find the node if it's a class component
hoveredNode = ReactDOM.findDOMNode(component);
} catch (error: unknown) {
// Try to find the component if it's a function component
hoveredNode = component.node;
}
const hoveredTop = hoveredNode.getBoundingClientRect().top;
const draggedTop = monitor.getSourceClientOffset()?.y;
return draggedTop && hoveredTop > draggedTop;
@@ -35,7 +35,6 @@ const mapStateToProps = (state: RootState) => ({
interface Props extends ReduxProps {
handleActivateRequest: Function;
handleCreateRequest: (id: string) => any;
handleCreateRequestGroup: (parentId: string) => void;
handleSetRequestPinned: Function;
handleSetRequestGroupCollapsed: Function;
@@ -53,7 +52,6 @@ class UnconnectedSidebarChildren extends PureComponent<Props> {
_renderChildren(children: Child[], isInPinnedList: boolean) {
const {
filter,
handleCreateRequest,
handleCreateRequestGroup,
handleSetRequestPinned,
handleSetRequestGroupCollapsed,
@@ -81,7 +79,6 @@ class UnconnectedSidebarChildren extends PureComponent<Props> {
handleDuplicateRequest={handleDuplicateRequest}
handleGenerateCode={handleGenerateCode}
handleCopyAsCurl={handleCopyAsCurl}
requestCreate={handleCreateRequest}
isActive={child.doc._id === activeRequestId}
isPinned={child.pinned}
disableDragAndDrop={isInPinnedList}
@@ -120,7 +117,6 @@ class UnconnectedSidebarChildren extends PureComponent<Props> {
handleSetRequestGroupCollapsed={handleSetRequestGroupCollapsed}
handleDuplicateRequestGroup={handleDuplicateRequestGroup}
isCollapsed={child.collapsed}
handleCreateRequest={handleCreateRequest}
handleCreateRequestGroup={handleCreateRequestGroup}
requestGroup={requestGroup}
hotKeyRegistry={hotKeyRegistry}
@@ -141,13 +137,6 @@ class UnconnectedSidebarChildren extends PureComponent<Props> {
);
}
_handleCreateRequest() {
const { handleCreateRequest, workspace } = this.props;
if (workspace) {
handleCreateRequest(workspace._id);
}
}
_handleCreateRequestGroup() {
const { handleCreateRequestGroup, workspace } = this.props;
if (workspace) {
@@ -161,7 +150,6 @@ class UnconnectedSidebarChildren extends PureComponent<Props> {
const contextMenuPortal = ReactDOM.createPortal(
<div className="hide">
<SidebarCreateDropdown
handleCreateRequest={this._handleCreateRequest}
handleCreateRequestGroup={this._handleCreateRequestGroup}
hotKeyRegistry={hotKeyRegistry}
/>
@@ -1,29 +1,38 @@
import { HotKeyRegistry } from 'insomnia-common';
import React, { FC, useCallback } from 'react';
import { useSelector } from 'react-redux';
import { hotKeyRefs } from '../../../common/hotkeys';
import { RequestGroup } from '../../../models/request-group';
import { createRequest, CreateRequestType } from '../../hooks/create-request';
import { selectActiveWorkspace } from '../../redux/selectors';
import { Dropdown } from '../base/dropdown/dropdown';
import { DropdownButton } from '../base/dropdown/dropdown-button';
import { DropdownHint } from '../base/dropdown/dropdown-hint';
import { DropdownItem } from '../base/dropdown/dropdown-item';
interface Props {
handleCreateRequest: (id: string) => any;
handleCreateRequestGroup: (requestGroup: RequestGroup) => any;
hotKeyRegistry: HotKeyRegistry;
right?: boolean;
}
export const SidebarCreateDropdown: FC<Props> = ({
handleCreateRequest,
handleCreateRequestGroup,
hotKeyRegistry,
right,
}) => {
const create = useCallback((value: string) => {
handleCreateRequest(value);
}, [handleCreateRequest]);
const activeWorkspace = useSelector(selectActiveWorkspace);
const activeWorkspaceId = activeWorkspace?._id;
const create = useCallback((value: CreateRequestType) => {
if (activeWorkspaceId) {
createRequest({
requestType: value,
parentId: activeWorkspaceId,
workspaceId: activeWorkspaceId,
});
}
}, [activeWorkspaceId]);
return (
<Dropdown right={right}>
@@ -11,7 +11,6 @@ import { SidebarSortDropdown } from './sidebar-sort-dropdown';
interface Props {
onChange: (value: string) => Promise<void>;
requestCreate: (requestType?: string) => void;
requestGroupCreate: () => void;
sidebarSort: (sortOrder: SortOrder) => void;
filter: string;
@@ -51,10 +50,6 @@ export class SidebarFilter extends PureComponent<Props> {
this.props.requestGroupCreate();
}
_handleRequestCreate(requestType?: string) {
this.props.requestCreate(requestType);
}
_handleKeydown(event: KeyboardEvent) {
executeHotKey(event, hotKeyRefs.SIDEBAR_FOCUS_FILTER, () => {
this._input?.focus();
@@ -82,7 +77,6 @@ export class SidebarFilter extends PureComponent<Props> {
</div>
<SidebarSortDropdown handleSort={sidebarSort} />
<SidebarCreateDropdown
handleCreateRequest={this._handleRequestCreate}
handleCreateRequestGroup={this._handleRequestGroupCreate}
hotKeyRegistry={hotKeyRegistry}
/>
@@ -2,7 +2,7 @@ import { autoBindMethodsForReact } from 'class-autobind-decorator';
import classnames from 'classnames';
import { HotKeyRegistry } from 'insomnia-common';
import { noop } from 'ramda-adjunct';
import React, { PureComponent } from 'react';
import React, { ElementRef, MouseEvent, PureComponent } from 'react';
import { PropsWithChildren } from 'react';
import { createRef } from 'react';
import { DragSource, DragSourceSpec, DropTarget, DropTargetMonitor, DropTargetSpec } from 'react-dnd';
@@ -13,7 +13,7 @@ import { RequestGroup } from '../../../models/request-group';
import { RootState } from '../../redux/modules';
import { selectActiveEnvironment, selectActiveRequest } from '../../redux/selectors';
import { Highlight } from '../base/highlight';
import { RequestGroupActionsDropdown, UnconnectedRequestGroupActionsDropdown } from '../dropdowns/request-group-actions-dropdown';
import { RequestGroupActionsDropdown } from '../dropdowns/request-group-actions-dropdown';
import { showModal } from '../modals';
import { RequestGroupSettingsModal } from '../modals/request-group-settings-modal';
import { DnDDragProps, DnDDropProps, DnDProps, DragObject, dropHandleCreator, hoverHandleCreator, sourceCollect, targetCollect } from './dnd';
@@ -30,7 +30,6 @@ interface Props extends DnDProps, ReduxProps, PropsWithChildren<{}> {
handleSetRequestGroupCollapsed: Function;
handleDuplicateRequestGroup: (requestGroup: RequestGroup) => any;
handleActivateRequest: Function;
handleCreateRequest: (id: string) => any;
handleCreateRequestGroup: (requestGroup: string) => any;
filter: string;
isActive: boolean;
@@ -49,7 +48,7 @@ class UnconnectedSidebarRequestGroupRow extends PureComponent<Props, State> {
dragDirection: 0,
};
private dropdownRef = createRef<UnconnectedRequestGroupActionsDropdown>();
private dropdownRef = createRef<ElementRef<typeof RequestGroupActionsDropdown>>();
private expandTagRef = createRef<HTMLDivElement>();
getExpandTag() {
@@ -61,7 +60,7 @@ class UnconnectedSidebarRequestGroupRow extends PureComponent<Props, State> {
handleSetRequestGroupCollapsed(requestGroup._id, !isCollapsed);
}
_handleShowActions(event) {
_handleShowActions(event: MouseEvent<HTMLButtonElement>) {
event.preventDefault();
this.dropdownRef.current?.show();
@@ -90,7 +89,6 @@ class UnconnectedSidebarRequestGroupRow extends PureComponent<Props, State> {
requestGroup,
isCollapsed,
isActive,
handleCreateRequest,
handleCreateRequestGroup,
handleDuplicateRequestGroup,
isDragging,
@@ -145,7 +143,6 @@ class UnconnectedSidebarRequestGroupRow extends PureComponent<Props, State> {
<div className="sidebar__actions">
<RequestGroupActionsDropdown
ref={this.dropdownRef}
handleCreateRequest={handleCreateRequest}
handleCreateRequestGroup={handleCreateRequestGroup}
handleDuplicateRequestGroup={handleDuplicateRequestGroup}
handleShowSettings={this._handleShowRequestGroupSettings}
@@ -172,7 +169,6 @@ class UnconnectedSidebarRequestGroupRow extends PureComponent<Props, State> {
handleSetRequestPinned={noop}
isActive={false}
requestGroup={requestGroup}
requestCreate={handleCreateRequest}
filter={filter}
hotKeyRegistry={hotKeyRegistry}
isPinned={false} // Necessary so that plugin actions work
@@ -1,18 +1,18 @@
import { autoBindMethodsForReact } from 'class-autobind-decorator';
import classnames from 'classnames';
import { HotKeyRegistry } from 'insomnia-common';
import React, { FC, PureComponent } from 'react';
import React, { FC, forwardRef, MouseEvent, ReactElement, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
import { DragSource, DragSourceSpec, DropTarget, DropTargetSpec } from 'react-dnd';
import { useSelector } from 'react-redux';
import { AUTOBIND_CFG, CONTENT_TYPE_GRAPHQL } from '../../../common/constants';
import { CONTENT_TYPE_GRAPHQL } from '../../../common/constants';
import { getMethodOverrideHeader } from '../../../common/misc';
import { GrpcRequest, isGrpcRequest } from '../../../models/grpc-request';
import * as requestOperations from '../../../models/helpers/request-operations';
import { Request } from '../../../models/request';
import { RequestGroup } from '../../../models/request-group';
import { useNunjucks } from '../../context/nunjucks/use-nunjucks';
import { selectActiveEnvironment, selectActiveProject } from '../../redux/selectors';
import { createRequest } from '../../hooks/create-request';
import { selectActiveEnvironment, selectActiveProject, selectActiveWorkspace } from '../../redux/selectors';
import { Editable } from '../base/editable';
import { Highlight } from '../base/highlight';
import { RequestActionsDropdown } from '../dropdowns/request-actions-dropdown';
@@ -23,15 +23,12 @@ import { GrpcTag } from '../tags/grpc-tag';
import { MethodTag } from '../tags/method-tag';
import { DnDProps, DragObject, dropHandleCreator, hoverHandleCreator, sourceCollect, targetCollect } from './dnd';
type DerivedProps = ReturnType<typeof useDerivedProps>;
interface RawProps {
handleActivateRequest: Function;
handleSetRequestPinned: Function;
handleDuplicateRequest: Function;
handleGenerateCode: Function;
handleCopyAsCurl: Function;
requestCreate: Function;
filter: string;
isActive: boolean;
isPinned: boolean;
@@ -42,307 +39,255 @@ interface RawProps {
disableDragAndDrop?: boolean;
}
type Props = RawProps & DnDProps & DerivedProps;
interface State {
dragDirection: number;
isEditing: boolean;
renderedUrl: string;
}
@autoBindMethodsForReact(AUTOBIND_CFG)
class UnconnectedSidebarRequestRow extends PureComponent<Props, State> {
state: State = {
dragDirection: 0,
isEditing: false,
renderedUrl: '',
};
_urlUpdateInterval: NodeJS.Timeout | null = null;
_requestActionsDropdown: RequestActionsDropdown | null = null;
_setRequestActionsDropdownRef(requestActionsDropdown: RequestActionsDropdown) {
this._requestActionsDropdown = requestActionsDropdown;
}
_handleShowRequestActions(event) {
event.preventDefault();
this._requestActionsDropdown?.show();
}
_handleEditStart() {
this.setState({
isEditing: true,
});
}
async _handleRequestUpdateName(name) {
const { request } = this.props;
const patch = {
name,
};
// @ts-expect-error -- TSCONVERSION skip this if request is undefined
await requestOperations.update(request, patch);
this.setState({
isEditing: false,
});
}
_handleRequestCreateFromEmpty() {
const parentId = this.props.requestGroup?._id;
this.props.requestCreate(parentId);
}
_handleRequestActivate() {
const { isActive, request, handleActivateRequest } = this.props;
if (isActive) {
return;
}
// @ts-expect-error -- TSCONVERSION skip this if request is undefined
handleActivateRequest(request._id);
}
_handleShowRequestSettings() {
showModal(RequestSettingsModal, {
request: this.props.request,
});
}
_getMethodOverrideHeaderValue() {
const { request } = this.props;
// @ts-expect-error -- TSCONVERSION skip this if request is undefined or grpc
const header = getMethodOverrideHeader(request.headers);
if (header) {
return header.value;
}
// If no override, use GraphQL as override if it's a gql request
// @ts-expect-error -- TSCONVERSION skip this if request is undefined or grpc
if (request.body && request.body.mimeType === CONTENT_TYPE_GRAPHQL) {
return 'GQL';
}
return null;
}
async _debouncedUpdateRenderedUrl(props: Props) {
if (this._urlUpdateInterval !== null) {
clearTimeout(this._urlUpdateInterval);
}
this._urlUpdateInterval = setTimeout(() => {
this._updateRenderedUrl(props);
}, 300);
}
async _updateRenderedUrl(props: Props) {
let renderedUrl;
try {
// @ts-expect-error -- TSCONVERSION skip this if request is undefined or grpc
renderedUrl = await props.handleRender(props.request.url);
} catch (error) {
// Certain things, such as invalid variable tags and Prompts
// without titles will result in a failure to parse. Can't do
// much else, so let's just give them the unrendered URL
// @ts-expect-error -- TSCONVERSION skip this if request is undefined
renderedUrl = props.request.url;
}
this.setState({
renderedUrl,
});
}
setDragDirection(dragDirection) {
if (dragDirection !== this.state.dragDirection) {
this.setState({
dragDirection,
});
}
}
componentDidMount() {
const { request } = this.props;
if (request && !request.name) {
this._debouncedUpdateRenderedUrl(this.props);
}
}
// eslint-disable-next-line camelcase
UNSAFE_componentWillUpdate(nextProps) {
if (!nextProps.request) {
return;
}
const requestUrl = this.props.request ? this.props.request.url : '';
if (nextProps.request.url !== requestUrl) {
this._debouncedUpdateRenderedUrl(nextProps);
}
}
componentWillUnmount() {
if (this._urlUpdateInterval !== null) {
clearTimeout(this._urlUpdateInterval);
}
}
render() {
const {
activeEnvironment,
connectDragSource,
connectDropTarget,
disableDragAndDrop,
filter,
handleCopyAsCurl,
handleDuplicateRequest,
handleGenerateCode,
handleSetRequestPinned,
hotKeyRegistry,
isActive,
isDragging,
isDraggingOver,
isPinned,
request,
requestGroup,
activeProject,
} = this.props;
const { dragDirection } = this.state;
let node;
const classes = classnames('sidebar__row', {
'sidebar__row--dragging': isDragging,
'sidebar__row--dragging-above': isDraggingOver && dragDirection > 0,
'sidebar__row--dragging-below': isDraggingOver && dragDirection < 0,
});
if (!request) {
node = (
<li className={classes}>
<div className="sidebar__item">
<button className="sidebar__clickable" onClick={this._handleRequestCreateFromEmpty}>
<em className="faded">click to add first request...</em>
</button>
</div>
</li>
);
} else {
const methodTag =
isGrpcRequest(request) ? (
<GrpcTag />
) : (
<MethodTag method={request.method} override={this._getMethodOverrideHeaderValue()} />
);
node = (
<li className={classes}>
<div
className={classnames('sidebar__item', 'sidebar__item--request', {
'sidebar__item--active': isActive,
})}
>
<button
className="wide"
onClick={this._handleRequestActivate}
onContextMenu={this._handleShowRequestActions}
>
<div className="sidebar__clickable">
{methodTag}
<Editable
value={request.name}
fallbackValue={this.state.renderedUrl}
blankValue="Empty"
className="inline-block"
onEditStart={this._handleEditStart}
onSubmit={this._handleRequestUpdateName}
renderReadView={(value, props) => (
<Highlight
search={filter}
text={value}
{...props}
title={`${request.name}\n${props.title}`}
/>
)}
/>
<GrpcSpinner requestId={request._id} className="margin-right-sm" />
</div>
</button>
<div className="sidebar__actions">
<RequestActionsDropdown
right
ref={this._setRequestActionsDropdownRef}
handleDuplicateRequest={handleDuplicateRequest}
handleSetRequestPinned={handleSetRequestPinned}
handleGenerateCode={handleGenerateCode}
handleCopyAsCurl={handleCopyAsCurl}
handleShowSettings={this._handleShowRequestSettings}
request={request}
isPinned={isPinned}
requestGroup={requestGroup}
hotKeyRegistry={hotKeyRegistry} // Necessary for plugin actions to have network capabilities
activeEnvironment={activeEnvironment}
activeProject={activeProject}
/>
</div>
{isPinned && (
<div className="sidebar__item__icon-pin">
<i className="fa fa-thumb-tack" />
</div>
)}
</div>
</li>
);
}
if (disableDragAndDrop) {
return node;
} else if (!this.state.isEditing) {
return connectDragSource(connectDropTarget(node));
} else {
return connectDropTarget(node);
}
}
}
type Props = RawProps & DnDProps;
const dragSource: DragSourceSpec<Props, DragObject> = {
beginDrag(props) {
beginDrag({ request }) {
return {
item: props.request,
item: request,
};
},
};
const dropHandle = dropHandleCreator<Props>({
getParentId: props => props.requestGroup?._id || props.request?.parentId,
getTargetId: props => props.request?._id,
});
const hoverHandle = hoverHandleCreator<Props>();
const dragTarget: DropTargetSpec<Props> = {
drop: dropHandle,
hover: hoverHandle,
drop: dropHandleCreator<Props>({
getParentId: props => props.requestGroup?._id || props.request?.parentId,
getTargetId: props => props.request?._id,
}),
hover: hoverHandleCreator<Props>(),
};
const source = DragSource('SIDEBAR_REQUEST_ROW', dragSource, sourceCollect)(UnconnectedSidebarRequestRow);
const Target = DropTarget('SIDEBAR_REQUEST_ROW', dragTarget, targetCollect)(source);
const useDerivedProps = () => {
export const _SidebarRequestRow: FC<Props> = forwardRef(({
connectDragSource,
connectDropTarget,
disableDragAndDrop,
filter,
handleActivateRequest,
handleCopyAsCurl,
handleDuplicateRequest,
handleGenerateCode,
handleSetRequestPinned,
hotKeyRegistry,
isActive,
isDragging,
isDraggingOver,
isPinned,
request,
requestGroup,
}, ref) => {
const { handleRender } = useNunjucks();
const activeProject = useSelector(selectActiveProject);
const activeEnvironment = useSelector(selectActiveEnvironment);
const activeWorkspace = useSelector(selectActiveWorkspace);
const activeWorkspaceId = activeWorkspace?._id;
const [dragDirection, setDragDirection] = useState(0);
const [isEditing, setIsEditing] = useState(false);
return {
handleRender,
activeProject,
activeEnvironment,
};
};
const nodeRef = useRef<HTMLLIElement>(null);
useImperativeHandle(ref, () => ({
setDragDirection,
node: nodeRef.current,
}));
export const SidebarRequestRow: FC<RawProps> = props => {
const derivedProps = useDerivedProps();
return <Target {...props} {...derivedProps} />;
};
const startEditing = useCallback(() => {
setIsEditing(true);
}, []);
const stopEditing = useCallback(() => {
setIsEditing(false);
}, []);
const [renderedUrl, setRenderedUrl] = useState('');
const requestActionsDropdown = useRef<RequestActionsDropdown | null>(null);
const handleShowRequestActions = useCallback((event: MouseEvent<HTMLButtonElement>) => {
event.preventDefault();
requestActionsDropdown.current?.show();
}, [requestActionsDropdown]);
const handleRequestUpdateName = useCallback((name: string) => {
if (!request) {
return;
}
requestOperations.update(request, { name }).then(() => {
stopEditing();
});
}, [request, stopEditing]);
const handleRequestCreateFromEmpty = useCallback(() => {
if (!requestGroup?._id || !activeWorkspaceId) {
return;
}
createRequest({
requestType: 'HTTP',
parentId: requestGroup?._id,
workspaceId: activeWorkspaceId,
});
}, [requestGroup?._id, activeWorkspaceId]);
const handleRequestActivate = useCallback(() => {
if (isActive) {
return;
}
handleActivateRequest(request?._id);
}, [isActive, request?._id, handleActivateRequest]);
const handleShowRequestSettings = useCallback(() => {
showModal(RequestSettingsModal, { request });
}, [request]);
const [methodOverrideValue, setMethodOverrideValue] = useState<string | null>(null);
useEffect(() => {
if (!request) {
return;
}
if (isGrpcRequest(request)) {
return;
}
const header = getMethodOverrideHeader(request.headers);
if (header) {
setMethodOverrideValue(header.value);
return;
}
// If no override, use GraphQL as override if it's a GraphQL request
if (request.body && request.body.mimeType === CONTENT_TYPE_GRAPHQL) {
setMethodOverrideValue('GQL');
return;
}
setMethodOverrideValue(null);
return;
}, [request]);
useEffect(() => {
if (!request) {
return;
}
if (isGrpcRequest(request)) {
return;
}
if (request.name) {
setRenderedUrl(request.name);
return;
}
handleRender(request.url)
.then(requestUrl => {
setRenderedUrl(requestUrl);
})
.catch(() => {
// Certain things, such as invalid variable tags and Prompts
// without titles will result in a failure to parse. Can't do
// much else, so let's just give them the unrendered URL
setRenderedUrl(request.url);
});
}, [handleRender, request, request?.url]);
let node: ReactElement<HTMLLIElement> | null = null;
const classes = classnames('sidebar__row', {
'sidebar__row--dragging': isDragging,
'sidebar__row--dragging-above': isDraggingOver && dragDirection > 0,
'sidebar__row--dragging-below': isDraggingOver && dragDirection < 0,
});
if (!request) {
node = (
<li ref={nodeRef} className={classes}>
<div className="sidebar__item">
<button className="sidebar__clickable" onClick={handleRequestCreateFromEmpty}>
<em className="faded">click to add first request...</em>
</button>
</div>
</li>
);
} else {
const methodTag =
isGrpcRequest(request) ? (
<GrpcTag />
) : (
<MethodTag method={request.method} override={methodOverrideValue} />
);
node = (
<li ref={nodeRef} className={classes}>
<div
className={classnames('sidebar__item', 'sidebar__item--request', {
'sidebar__item--active': isActive,
})}
>
<button
className="wide"
onClick={handleRequestActivate}
onContextMenu={handleShowRequestActions}
>
<div className="sidebar__clickable">
{methodTag}
<Editable
value={request.name}
fallbackValue={renderedUrl}
blankValue="Empty"
className="inline-block"
onEditStart={startEditing}
onSubmit={handleRequestUpdateName}
renderReadView={(value, props) => (
<Highlight
search={filter}
text={value}
{...props}
title={`${request.name}\n${props.title}`}
/>
)}
/>
<GrpcSpinner requestId={request._id} className="margin-right-sm" />
</div>
</button>
<div className="sidebar__actions">
<RequestActionsDropdown
right
ref={requestActionsDropdown}
handleDuplicateRequest={handleDuplicateRequest}
handleSetRequestPinned={handleSetRequestPinned}
handleGenerateCode={handleGenerateCode}
handleCopyAsCurl={handleCopyAsCurl}
handleShowSettings={handleShowRequestSettings}
request={request}
isPinned={isPinned}
requestGroup={requestGroup}
hotKeyRegistry={hotKeyRegistry} // Necessary for plugin actions to have network capabilities
activeEnvironment={activeEnvironment}
activeProject={activeProject}
/>
</div>
{isPinned && (
<div className="sidebar__item__icon-pin">
<i className="fa fa-thumb-tack" />
</div>
)}
</div>
</li>
);
}
if (disableDragAndDrop) {
return node;
} else if (!isEditing) {
return connectDragSource(connectDropTarget(node));
} else {
return connectDropTarget(node);
}
});
_SidebarRequestRow.displayName = 'SidebarRequestRow';
const source = DragSource('SIDEBAR_REQUEST_ROW', dragSource, sourceCollect)(_SidebarRequestRow);
export const SidebarRequestRow = DropTarget('SIDEBAR_REQUEST_ROW', dragTarget, targetCollect)(source);
@@ -35,7 +35,6 @@ interface Props extends ReturnType<typeof mapStateToProps> {
handleForceUpdateRequest: (r: Request, patch: Partial<Request>) => Promise<Request>;
handleForceUpdateRequestHeaders: (r: Request, headers: RequestHeader[]) => Promise<Request>;
handleImport: Function;
handleRequestCreate: () => void;
handleRequestGroupCreate: () => void;
handleSendAndDownloadRequestWithActiveEnvironment: (filepath?: string) => Promise<void>;
handleSendRequestWithActiveEnvironment: () => void;
@@ -101,7 +100,6 @@ class UnconnectedWrapperDebug extends PureComponent<Props> {
activeWorkspace,
environments,
handleChangeEnvironment,
handleRequestCreate,
handleRequestGroupCreate,
handleSidebarSort,
settings,
@@ -111,7 +109,6 @@ class UnconnectedWrapperDebug extends PureComponent<Props> {
const {
handleActivateRequest,
handleCopyAsCurl,
handleCreateRequest,
handleCreateRequestGroup,
handleDuplicateRequest,
handleDuplicateRequestGroup,
@@ -146,7 +143,6 @@ class UnconnectedWrapperDebug extends PureComponent<Props> {
<SidebarFilter
key={`${activeWorkspace._id}::filter`}
onChange={handleSetSidebarFilter}
requestCreate={handleRequestCreate}
requestGroupCreate={handleRequestGroupCreate}
sidebarSort={handleSidebarSort}
filter={sidebarFilter || ''}
@@ -156,7 +152,6 @@ class UnconnectedWrapperDebug extends PureComponent<Props> {
<SidebarChildren
childObjects={sidebarChildren}
handleActivateRequest={handleActivateRequest}
handleCreateRequest={handleCreateRequest}
handleCreateRequestGroup={handleCreateRequestGroup}
handleSetRequestGroupCollapsed={handleSetRequestGroupCollapsed}
handleSetRequestPinned={handleSetRequestPinned}
@@ -194,7 +189,6 @@ class UnconnectedWrapperDebug extends PureComponent<Props> {
settings,
} = this.props;
const {
handleCreateRequestForWorkspace,
handleGenerateCodeForActiveRequest,
handleUpdateDownloadPath,
handleUpdateRequestMimeType,
@@ -229,7 +223,6 @@ class UnconnectedWrapperDebug extends PureComponent<Props> {
forceRefreshCounter={forceRefreshKey}
forceUpdateRequest={handleForceUpdateRequest}
forceUpdateRequestHeaders={handleForceUpdateRequestHeaders}
handleCreateRequest={handleCreateRequestForWorkspace}
handleGenerateCode={handleGenerateCodeForActiveRequest}
handleImport={handleImport}
handleSend={handleSendRequestWithActiveEnvironment}
+10 -43
View File
@@ -128,14 +128,12 @@ export type WrapperProps = AppProps & {
handleSetSidebarFilter: (value: string) => Promise<void>;
handleShowSettingsModal: Function;
handleSetActiveEnvironment: (environmentId: string | null) => Promise<void>;
handleCreateRequest: (id: string, requestType?: string) => void;
handleDuplicateRequest: Function;
handleDuplicateRequestGroup: (requestGroup: RequestGroup) => void;
handleCreateRequestGroup: (parentId: string) => void;
handleGenerateCodeForActiveRequest: Function;
handleGenerateCode: Function;
handleCopyAsCurl: Function;
handleCreateRequestForWorkspace: (requestType?: string) => void;
requestPaneRef: Ref<HTMLElement>;
responsePaneRef: Ref<HTMLElement>;
handleSetResponsePreviewMode: Function;
@@ -434,16 +432,6 @@ export class Wrapper extends PureComponent<WrapperProps, State> {
this.props.handleSetResponseFilter(activeRequestId, filter);
}
_handleCreateRequestInWorkspace(requestType?: string) {
const { activeWorkspace, handleCreateRequest } = this.props;
if (!activeWorkspace) {
return;
}
handleCreateRequest(activeWorkspace._id, requestType);
}
_handleCreateRequestGroupInWorkspace() {
const { activeWorkspace, handleCreateRequestGroup } = this.props;
@@ -680,45 +668,24 @@ export class Wrapper extends PureComponent<WrapperProps, State> {
handleDeleteResponse={this._handleDeleteResponse}
handleDeleteResponses={this._handleDeleteResponses}
handleForceUpdateRequest={this._handleForceUpdateRequest}
handleForceUpdateRequestHeaders={
this._handleForceUpdateRequestHeaders
}
handleForceUpdateRequestHeaders={this._handleForceUpdateRequestHeaders}
handleImport={this._handleImport}
handleRequestCreate={this._handleCreateRequestInWorkspace}
handleRequestGroupCreate={
this._handleCreateRequestGroupInWorkspace
}
handleSendAndDownloadRequestWithActiveEnvironment={
this._handleSendAndDownloadRequestWithActiveEnvironment
}
handleSendRequestWithActiveEnvironment={
this._handleSendRequestWithActiveEnvironment
}
handleRequestGroupCreate={this._handleCreateRequestGroupInWorkspace}
handleSendAndDownloadRequestWithActiveEnvironment={this._handleSendAndDownloadRequestWithActiveEnvironment}
handleSendRequestWithActiveEnvironment={this._handleSendRequestWithActiveEnvironment}
handleSetActiveResponse={this._handleSetActiveResponse}
handleSetPreviewMode={this._handleSetPreviewMode}
handleSetResponseFilter={this._handleSetResponseFilter}
handleShowRequestSettingsModal={
this._handleShowRequestSettingsModal
}
handleShowRequestSettingsModal={this._handleShowRequestSettingsModal}
handleSidebarSort={handleSidebarSort}
handleUpdateRequestAuthentication={
Wrapper._handleUpdateRequestAuthentication
}
handleUpdateRequestAuthentication={Wrapper._handleUpdateRequestAuthentication}
handleUpdateRequestBody={Wrapper._handleUpdateRequestBody}
handleUpdateRequestHeaders={
Wrapper._handleUpdateRequestHeaders
}
handleUpdateRequestHeaders={Wrapper._handleUpdateRequestHeaders}
handleUpdateRequestMethod={Wrapper._handleUpdateRequestMethod}
handleUpdateRequestParameters={
Wrapper._handleUpdateRequestParameters
}
handleUpdateRequestParameters={Wrapper._handleUpdateRequestParameters}
handleUpdateRequestUrl={Wrapper._handleUpdateRequestUrl}
handleUpdateSettingsUseBulkHeaderEditor={
this._handleUpdateSettingsUseBulkHeaderEditor
}
handleUpdateSettingsUseBulkParametersEditor={
this._handleUpdateSettingsUseBulkParametersEditor
}
handleUpdateSettingsUseBulkHeaderEditor={this._handleUpdateSettingsUseBulkHeaderEditor}
handleUpdateSettingsUseBulkParametersEditor={this._handleUpdateSettingsUseBulkParametersEditor}
wrapperProps={this.props}
/>
</Suspense>
+3 -67
View File
@@ -14,8 +14,6 @@ import {
ACTIVITY_HOME,
AUTOBIND_CFG,
COLLAPSE_SIDEBAR_REMS,
CONTENT_TYPE_GRAPHQL,
CONTENT_TYPE_JSON,
DEFAULT_PANE_HEIGHT,
DEFAULT_PANE_WIDTH,
DEFAULT_SIDEBAR_WIDTH,
@@ -24,8 +22,6 @@ import {
MAX_PANE_HEIGHT,
MAX_PANE_WIDTH,
MAX_SIDEBAR_REMS,
METHOD_GET,
METHOD_POST,
MIN_PANE_HEIGHT,
MIN_PANE_WIDTH,
MIN_SIDEBAR_REMS,
@@ -70,7 +66,6 @@ import { AskModal } from '../components/modals/ask-modal';
import { showCookiesModal } from '../components/modals/cookies-modal';
import { GenerateCodeModal } from '../components/modals/generate-code-modal';
import { showAlert, showModal, showPrompt } from '../components/modals/index';
import ProtoFilesModal from '../components/modals/proto-files-modal';
import { RequestRenderErrorModal } from '../components/modals/request-render-error-modal';
import { RequestSettingsModal } from '../components/modals/request-settings-modal';
import RequestSwitcherModal from '../components/modals/request-switcher-modal';
@@ -200,19 +195,13 @@ class App extends PureComponent<AppProps, State> {
};
this._savePaneWidth = debounce(paneWidth =>
this._updateActiveWorkspaceMeta({
paneWidth,
}),
this._updateActiveWorkspaceMeta({ paneWidth }),
);
this._savePaneHeight = debounce(paneHeight =>
this._updateActiveWorkspaceMeta({
paneHeight,
}),
this._updateActiveWorkspaceMeta({ paneHeight }),
);
this._saveSidebarWidth = debounce(sidebarWidth =>
this._updateActiveWorkspaceMeta({
sidebarWidth,
}),
this._updateActiveWorkspaceMeta({ sidebarWidth }),
);
this._globalKeyMap = null;
this._updateVCSLock = null;
@@ -400,51 +389,6 @@ class App extends PureComponent<AppProps, State> {
});
}
async _requestCreate(parentId: string, requestType?: string) {
if (requestType === 'gRPC') {
showModal(ProtoFilesModal, {
onSave: async (protoFileId: string) => {
const createdRequest = await models.grpcRequest.create({
parentId,
name: 'New Request',
protoFileId,
});
models.stats.incrementCreatedRequests();
trackSegmentEvent(SegmentEvent.requestCreate, { requestType });
this._handleSetActiveRequest(createdRequest._id);
},
});
return;
}
if (requestType === 'GraphQL') {
const request = await models.request.create({
parentId,
method: METHOD_POST,
headers:[{
name: 'Content-Type',
value: CONTENT_TYPE_JSON,
}],
body:{
mimeType: CONTENT_TYPE_GRAPHQL,
text: '',
},
name: 'New Request',
});
models.stats.incrementCreatedRequests();
trackSegmentEvent(SegmentEvent.requestCreate, { requestType });
this._handleSetActiveRequest(request._id);
return;
}
const request = await models.request.create({
parentId,
method: METHOD_GET,
name: 'New Request',
});
models.stats.incrementCreatedRequests();
trackSegmentEvent(SegmentEvent.requestCreate, { requestType: 'HTTP' });
this._handleSetActiveRequest(request._id);
}
async _recalculateMetaSortKey(docs: (RequestGroup | Request | GrpcRequest)[]) {
function __updateDoc(doc, metaSortKey) {
// @ts-expect-error -- TSCONVERSION the fetched model will only ever be a RequestGroup, Request, or GrpcRequest
@@ -901,12 +845,6 @@ class App extends PureComponent<AppProps, State> {
}
}
_requestCreateForWorkspace(requestType?: string) {
if (this.props.activeWorkspace) {
this._requestCreate(this.props.activeWorkspace._id, requestType);
}
}
_startDragSidebar() {
this.setState({
draggingSidebar: true,
@@ -1508,7 +1446,6 @@ class App extends PureComponent<AppProps, State> {
paneWidth={paneWidth}
paneHeight={paneHeight}
sidebarWidth={sidebarWidth}
handleCreateRequestForWorkspace={this._requestCreateForWorkspace}
handleSetRequestPinned={this._handleSetRequestPinned}
handleSetRequestGroupCollapsed={this._handleSetRequestGroupCollapsed}
handleActivateRequest={this._handleSetActiveRequest}
@@ -1521,7 +1458,6 @@ class App extends PureComponent<AppProps, State> {
handleStartDragPaneVertical={this._startDragPaneVertical}
handleResetDragPaneHorizontal={this._resetDragPaneHorizontal}
handleResetDragPaneVertical={this._resetDragPaneVertical}
handleCreateRequest={this._requestCreate}
handleDuplicateRequest={this._requestDuplicate}
handleDuplicateRequestGroup={App._requestGroupDuplicate}
handleCreateRequestGroup={this._requestGroupCreate}
@@ -0,0 +1,124 @@
import { unreachableCase } from 'ts-assert-unreachable';
import { SegmentEvent, trackSegmentEvent } from '../../common/analytics';
import {
CONTENT_TYPE_GRAPHQL,
CONTENT_TYPE_JSON,
METHOD_GET,
METHOD_POST,
} from '../../common/constants';
import * as models from '../../models';
import { isGrpcRequestId } from '../../models/grpc-request';
import { GrpcRequestMeta } from '../../models/grpc-request-meta';
import { RequestMeta } from '../../models/request-meta';
import { WorkspaceMeta } from '../../models/workspace-meta';
import { showModal } from '../components/modals';
import ProtoFilesModal from '../components/modals/proto-files-modal';
export const updateActiveWorkspaceMeta = async (
patch: Partial<WorkspaceMeta>,
workspaceId: string
) => {
const activeWorkspaceMeta = await models.workspaceMeta.getByParentId(
workspaceId
);
if (activeWorkspaceMeta) {
await models.workspaceMeta.update(activeWorkspaceMeta, patch);
}
};
export const updateRequestMetaByParentId = async (
requestId: string,
patch: Partial<GrpcRequestMeta> | Partial<RequestMeta>
) => {
if (isGrpcRequestId(requestId)) {
await models.grpcRequestMeta.updateOrCreateByParentId(requestId, patch);
return;
}
await models.requestMeta.updateOrCreateByParentId(requestId, patch);
};
export const setActiveRequest = async (
activeRequestId: string,
workspaceId: string
) => {
await updateActiveWorkspaceMeta({ activeRequestId }, workspaceId);
await updateRequestMetaByParentId(activeRequestId, {
lastActive: Date.now(),
});
};
export type CreateRequestType = 'HTTP' | 'gRPC' | 'GraphQL';
type RequestCreator = (input: {
parentId: string;
requestType: CreateRequestType;
workspaceId: string;
}) => Promise<void>;
export const createRequest: RequestCreator = async ({
parentId,
requestType,
workspaceId,
}) => {
let requestId = '';
switch (requestType) {
case 'gRPC': {
showModal(ProtoFilesModal, {
onSave: async (protoFileId: string) => {
const createdRequest = await models.grpcRequest.create({
parentId,
name: 'New Request',
protoFileId,
});
models.stats.incrementCreatedRequests();
requestId = createdRequest._id;
},
});
break;
}
case 'GraphQL': {
const request = await models.request.create({
parentId,
method: METHOD_POST,
headers: [
{
name: 'Content-Type',
value: CONTENT_TYPE_JSON,
},
],
body: {
mimeType: CONTENT_TYPE_GRAPHQL,
text: '',
},
name: 'New Request',
});
models.stats.incrementCreatedRequests();
requestId = request._id;
break;
}
case 'HTTP': {
const request = await models.request.create({
parentId,
method: METHOD_GET,
name: 'New Request',
});
models.stats.incrementCreatedRequests();
requestId = request._id;
break;
}
default:
unreachableCase(
requestType,
"tried to create a request but didn't specify the type"
);
}
trackSegmentEvent(SegmentEvent.requestCreate, { requestType });
setActiveRequest(requestId, workspaceId);
};