From 6493f57e3b8d4076614a730a39b90e14479ee965 Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Thu, 29 Mar 2018 11:40:37 -0400 Subject: [PATCH] Cleaned up request switcher --- .../modals/request-switcher-modal.js | 158 ++++++++++-------- .../ui/components/sidebar/sidebar-filter.js | 2 +- .../insomnia-app/app/ui/redux/selectors.js | 15 +- packages/insomnia-app/flow-typed/reselect.js | 5 + 4 files changed, 101 insertions(+), 79 deletions(-) create mode 100644 packages/insomnia-app/flow-typed/reselect.js diff --git a/packages/insomnia-app/app/ui/components/modals/request-switcher-modal.js b/packages/insomnia-app/app/ui/components/modals/request-switcher-modal.js index 591077bd3..0842f2389 100644 --- a/packages/insomnia-app/app/ui/components/modals/request-switcher-modal.js +++ b/packages/insomnia-app/app/ui/components/modals/request-switcher-modal.js @@ -1,8 +1,7 @@ -import React, {PureComponent} from 'react'; -import PropTypes from 'prop-types'; +// @flow +import * as React from 'react'; import autobind from 'autobind-decorator'; import classnames from 'classnames'; -import {buildQueryStringFromParams, joinUrlAndQueryString} from 'insomnia-url'; import Button from '../base/button'; import Modal from '../base/modal'; import ModalHeader from '../base/modal-header'; @@ -10,10 +9,35 @@ import ModalBody from '../base/modal-body'; import MethodTag from '../tags/method-tag'; import * as models from '../../../models'; import {fuzzyMatchAll} from '../../../common/misc'; +import type {RequestGroup} from '../../../models/request-group'; +import type {Request} from '../../../models/request'; +import type {Workspace} from '../../../models/workspace'; + +type Props = { + handleSetActiveWorkspace: (id: string) => void, + activateRequest: (id: string) => void, + workspaceId: string, + activeRequestParentId: string, + workspaceChildren: Array, + workspaces: Array +}; + +type State = { + searchString: string, + requestGroups: Array, + requests: Array, + workspaces: Array, + matchedRequests: Array, + matchedWorkspaces: Array, + activeIndex: number +}; @autobind -class RequestSwitcherModal extends PureComponent { - constructor (props) { +class RequestSwitcherModal extends React.PureComponent { + modal: ?Modal; + _input: ?HTMLInputElement; + + constructor (props: Props) { super(props); this.state = { @@ -27,7 +51,7 @@ class RequestSwitcherModal extends PureComponent { }; } - _handleKeydown (e) { + _handleKeydown (e: KeyboardEvent) { const keyCode = e.keyCode; if (keyCode === 38 || (keyCode === 9 && e.shiftKey)) { @@ -46,15 +70,15 @@ class RequestSwitcherModal extends PureComponent { e.preventDefault(); } - _setModalRef (n) { + _setModalRef (n: ?Modal) { this.modal = n; } - _setInputRef (n) { + _setInputRef (n: ?HTMLInputElement) { this._input = n; } - _setActiveIndex (activeIndex) { + _setActiveIndex (activeIndex: number) { const maxIndex = this.state.matchedRequests.length + this.state.matchedWorkspaces.length; if (activeIndex < 0) { activeIndex = this.state.matchedRequests.length - 1; @@ -80,7 +104,9 @@ class RequestSwitcherModal extends PureComponent { // Activate the workspace if there is one const index = activeIndex - matchedRequests.length; const workspace = matchedWorkspaces[index]; - this._activateWorkspace(workspace); + if (workspace) { + this._activateWorkspace(workspace); + } } else { // Create request if no match this._createRequestFromSearch(); @@ -101,66 +127,64 @@ class RequestSwitcherModal extends PureComponent { this._activateRequest(request); } - _activateWorkspace (workspace) { - if (!workspace) { - return; - } - + _activateWorkspace (workspace: Workspace) { this.props.handleSetActiveWorkspace(workspace._id); - this.modal.hide(); + this.modal && this.modal.hide(); } - _activateRequest (request) { + _activateRequest (request: ?Request) { if (!request) { return; } this.props.activateRequest(request._id); - this.modal.hide(); + this.modal && this.modal.hide(); } - _handleChange (e) { - this._handleChangeValue(e.target.value); + _handleChange (e: SyntheticEvent) { + this._handleChangeValue(e.currentTarget.value); } - /** - * Appends path of ancestor groups, delimited by forward slashes - * E.g. Folder1/Folder2/Folder3 - */ - _groupOf (requestOrRequestGroup) { + /** Return array of path segments for given request or folder */ + _groupOf (requestOrRequestGroup: Request | RequestGroup): Array { const {workspaceChildren} = this.props; const requestGroups = workspaceChildren.filter(d => d.type === models.requestGroup.type); const matchedGroups = requestGroups.filter(g => g._id === requestOrRequestGroup.parentId); - const currentGroupName = requestOrRequestGroup.type === models.requestGroup.type && requestOrRequestGroup.name ? `${requestOrRequestGroup.name}` : ''; + const currentGroupName = requestOrRequestGroup.type === models.requestGroup.type + ? `${requestOrRequestGroup.name}` + : ''; + // It's the final parent if (matchedGroups.length === 0) { - return currentGroupName; + return [currentGroupName]; } - const parentGroup = this._groupOf(matchedGroups[0]); - const parentGroupText = parentGroup ? `${parentGroup}/` : ''; - const group = `${parentGroupText}${currentGroupName}`; + // Still has more parents + if (currentGroupName) { + return [currentGroupName, ...this._groupOf(matchedGroups[0])]; + } - return group; + // It's the child + return this._groupOf(matchedGroups[0]); } - _isMatch (searchStrings) { - return (request) => { - let finalUrl = request.url; - if (request.parameters) { - finalUrl = joinUrlAndQueryString( - finalUrl, - buildQueryStringFromParams(request.parameters)); - } + _isMatch (searchStrings: string): (Request) => boolean { + return (request: Request): boolean => { + // Disable URL filtering until we have proper UI to show this + // let finalUrl = request.url; + // if (request.parameters) { + // finalUrl = joinUrlAndQueryString( + // finalUrl, + // buildQueryStringFromParams(request.parameters)); + // } // Match request attributes - const matchesAttributes = fuzzyMatchAll(searchStrings, - [ - request.name, - finalUrl, - request.method, - this._groupOf(request) - ]); + const matchesAttributes = fuzzyMatchAll(searchStrings, [ + request.name, + // finalUrl, + // request.method, + this._groupOf(request).join('/') + ]); // Match exact Id const matchesId = request._id === searchStrings; @@ -169,7 +193,7 @@ class RequestSwitcherModal extends PureComponent { }; } - async _handleChangeValue (searchString) { + async _handleChangeValue (searchString: string) { const {workspaceChildren, workspaces} = this.props; const {workspaceId, activeRequestParentId} = this.props; @@ -218,16 +242,18 @@ class RequestSwitcherModal extends PureComponent { async show () { await this._handleChangeValue(''); - this.modal.show(); - setTimeout(() => this._input.focus(), 100); + this.modal && this.modal.show(); + setTimeout(() => { + this._input && this._input.focus(); + }, 100); } hide () { - this.modal.hide(); + this.modal && this.modal.hide(); } toggle () { - if (this.modal.isOpen()) { + if (this.modal && this.modal.isOpen()) { this.hide(); } else { this.show(); @@ -248,14 +274,15 @@ class RequestSwitcherModal extends PureComponent { return ( -
- tab or -   - ↑ ↓  to navigate -     -  to select -     - esc to dismiss +
+ +
+ tab or  + ↑↓ to navigate     +  to select     + esc to dismiss +
+
Quick Switch
@@ -264,7 +291,7 @@ class RequestSwitcherModal extends PureComponent {
{requestGroup && (
- {requestGroup.name} + {this._groupOf(r).join(' / ')}   
@@ -339,13 +366,4 @@ class RequestSwitcherModal extends PureComponent { } } -RequestSwitcherModal.propTypes = { - handleSetActiveWorkspace: PropTypes.func.isRequired, - activateRequest: PropTypes.func.isRequired, - workspaceId: PropTypes.string.isRequired, - activeRequestParentId: PropTypes.string.isRequired, - workspaceChildren: PropTypes.arrayOf(PropTypes.object).isRequired, - workspaces: PropTypes.arrayOf(PropTypes.object).isRequired -}; - export default RequestSwitcherModal; diff --git a/packages/insomnia-app/app/ui/components/sidebar/sidebar-filter.js b/packages/insomnia-app/app/ui/components/sidebar/sidebar-filter.js index e6d4335b5..5e84a6fb6 100644 --- a/packages/insomnia-app/app/ui/components/sidebar/sidebar-filter.js +++ b/packages/insomnia-app/app/ui/components/sidebar/sidebar-filter.js @@ -52,7 +52,7 @@ class SidebarFilter extends PureComponent { diff --git a/packages/insomnia-app/app/ui/redux/selectors.js b/packages/insomnia-app/app/ui/redux/selectors.js index c042c173f..4f25e7bf1 100644 --- a/packages/insomnia-app/app/ui/redux/selectors.js +++ b/packages/insomnia-app/app/ui/redux/selectors.js @@ -113,13 +113,16 @@ export const selectSidebarChildren = createSelector( const hasMatchedChildren = child.children.find(c => c.hidden === false); // Try to match request attributes - const {name, url, method, parameters} = child.doc; + const {name, method} = child.doc; + + // Don't use URL/parameters yet until we have UI to show it + // const {name, url, method, parameters} = child.doc; const hasMatchedAttributes = fuzzyMatchAll(sidebarFilter, [ name, - url, + // url, method, - ...(parameters ? parameters.map(p => `${p.name}=${p.value}`) : []), + // ...(parameters ? parameters.map(p => `${p.name}=${p.value}`) : []), ...parentNames ]); @@ -191,11 +194,7 @@ export const selectUnseenWorkspaces = createSelector( const {workspaces, workspaceMetas} = entities; return workspaces.filter(workspace => { const meta = workspaceMetas.find(m => m.parentId === workspace._id); - if (meta && !meta.hasSeen) { - return true; - } else { - return false; - } + return !!(meta && !meta.hasSeen); }); } ); diff --git a/packages/insomnia-app/flow-typed/reselect.js b/packages/insomnia-app/flow-typed/reselect.js new file mode 100644 index 000000000..489fb7e83 --- /dev/null +++ b/packages/insomnia-app/flow-typed/reselect.js @@ -0,0 +1,5 @@ +declare module 'reselect' { + declare module.exports: { + createSelector: Function + } +}