mirror of
https://github.com/Kong/insomnia
synced 2024-11-08 06:39:48 +00:00
Cleaned up request switcher
This commit is contained in:
parent
e17332c7de
commit
6493f57e3b
@ -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<Request | RequestGroup>,
|
||||
workspaces: Array<Workspace>
|
||||
};
|
||||
|
||||
type State = {
|
||||
searchString: string,
|
||||
requestGroups: Array<RequestGroup>,
|
||||
requests: Array<Request>,
|
||||
workspaces: Array<Workspace>,
|
||||
matchedRequests: Array<Request>,
|
||||
matchedWorkspaces: Array<Workspace>,
|
||||
activeIndex: number
|
||||
};
|
||||
|
||||
@autobind
|
||||
class RequestSwitcherModal extends PureComponent {
|
||||
constructor (props) {
|
||||
class RequestSwitcherModal extends React.PureComponent<Props, State> {
|
||||
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];
|
||||
if (workspace) {
|
||||
this._activateWorkspace(workspace);
|
||||
}
|
||||
} else {
|
||||
// Create request if no match
|
||||
this._createRequestFromSearch();
|
||||
@ -101,65 +127,63 @@ 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<HTMLInputElement>) {
|
||||
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<string> {
|
||||
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}`;
|
||||
|
||||
return group;
|
||||
// Still has more parents
|
||||
if (currentGroupName) {
|
||||
return [currentGroupName, ...this._groupOf(matchedGroups[0])];
|
||||
}
|
||||
|
||||
_isMatch (searchStrings) {
|
||||
return (request) => {
|
||||
let finalUrl = request.url;
|
||||
if (request.parameters) {
|
||||
finalUrl = joinUrlAndQueryString(
|
||||
finalUrl,
|
||||
buildQueryStringFromParams(request.parameters));
|
||||
// It's the child
|
||||
return this._groupOf(matchedGroups[0]);
|
||||
}
|
||||
|
||||
_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,
|
||||
[
|
||||
const matchesAttributes = fuzzyMatchAll(searchStrings, [
|
||||
request.name,
|
||||
finalUrl,
|
||||
request.method,
|
||||
this._groupOf(request)
|
||||
// finalUrl,
|
||||
// request.method,
|
||||
this._groupOf(request).join('/')
|
||||
]);
|
||||
|
||||
// Match exact Id
|
||||
@ -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,15 +274,16 @@ class RequestSwitcherModal extends PureComponent {
|
||||
return (
|
||||
<Modal ref={this._setModalRef} dontFocus tall>
|
||||
<ModalHeader hideCloseButton>
|
||||
<div className="pull-right txt-sm pad-right">
|
||||
<span className="monospace">tab</span> or
|
||||
|
||||
<span className="monospace">↑ ↓</span> to navigate
|
||||
|
||||
<span className="monospace">↵</span> to select
|
||||
|
||||
<div className="pull-right txt-sm pad-right tall">
|
||||
<span className="vertically-center">
|
||||
<div>
|
||||
<span className="monospace">tab</span> or
|
||||
<span className="monospace">↑↓</span> to navigate
|
||||
<span className="monospace">↵</span> to select
|
||||
<span className="monospace">esc</span> to dismiss
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<div>Quick Switch</div>
|
||||
</ModalHeader>
|
||||
<ModalBody className="request-switcher">
|
||||
@ -264,7 +291,7 @@ class RequestSwitcherModal extends PureComponent {
|
||||
<div className="form-control form-control--outlined no-margin">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Fuzzy filter by request name, folder, url, method, or query parameters"
|
||||
placeholder="Filter by name or folder"
|
||||
ref={this._setInputRef}
|
||||
value={searchString}
|
||||
onChange={this._handleChange}
|
||||
@ -284,7 +311,7 @@ class RequestSwitcherModal extends PureComponent {
|
||||
<Button onClick={this._activateRequest} value={r} className={buttonClasses}>
|
||||
{requestGroup && (
|
||||
<div className="pull-right faint italic">
|
||||
{requestGroup.name}
|
||||
{this._groupOf(r).join(' / ')}
|
||||
|
||||
<i className="fa fa-folder-o"/>
|
||||
</div>
|
||||
@ -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;
|
||||
|
@ -52,7 +52,7 @@ class SidebarFilter extends PureComponent {
|
||||
<input
|
||||
ref={this._setInputRef}
|
||||
type="text"
|
||||
placeholder="Filter by name, folder, url"
|
||||
placeholder="Filter"
|
||||
defaultValue={this.props.filter}
|
||||
onChange={this._handleOnChange}
|
||||
/>
|
||||
|
@ -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);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
5
packages/insomnia-app/flow-typed/reselect.js
vendored
Normal file
5
packages/insomnia-app/flow-typed/reselect.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
declare module 'reselect' {
|
||||
declare module.exports: {
|
||||
createSelector: Function
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user