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';
|
// @flow
|
||||||
import PropTypes from 'prop-types';
|
import * as React from 'react';
|
||||||
import autobind from 'autobind-decorator';
|
import autobind from 'autobind-decorator';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import {buildQueryStringFromParams, joinUrlAndQueryString} from 'insomnia-url';
|
|
||||||
import Button from '../base/button';
|
import Button from '../base/button';
|
||||||
import Modal from '../base/modal';
|
import Modal from '../base/modal';
|
||||||
import ModalHeader from '../base/modal-header';
|
import ModalHeader from '../base/modal-header';
|
||||||
@ -10,10 +9,35 @@ import ModalBody from '../base/modal-body';
|
|||||||
import MethodTag from '../tags/method-tag';
|
import MethodTag from '../tags/method-tag';
|
||||||
import * as models from '../../../models';
|
import * as models from '../../../models';
|
||||||
import {fuzzyMatchAll} from '../../../common/misc';
|
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
|
@autobind
|
||||||
class RequestSwitcherModal extends PureComponent {
|
class RequestSwitcherModal extends React.PureComponent<Props, State> {
|
||||||
constructor (props) {
|
modal: ?Modal;
|
||||||
|
_input: ?HTMLInputElement;
|
||||||
|
|
||||||
|
constructor (props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
@ -27,7 +51,7 @@ class RequestSwitcherModal extends PureComponent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleKeydown (e) {
|
_handleKeydown (e: KeyboardEvent) {
|
||||||
const keyCode = e.keyCode;
|
const keyCode = e.keyCode;
|
||||||
|
|
||||||
if (keyCode === 38 || (keyCode === 9 && e.shiftKey)) {
|
if (keyCode === 38 || (keyCode === 9 && e.shiftKey)) {
|
||||||
@ -46,15 +70,15 @@ class RequestSwitcherModal extends PureComponent {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
_setModalRef (n) {
|
_setModalRef (n: ?Modal) {
|
||||||
this.modal = n;
|
this.modal = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
_setInputRef (n) {
|
_setInputRef (n: ?HTMLInputElement) {
|
||||||
this._input = n;
|
this._input = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
_setActiveIndex (activeIndex) {
|
_setActiveIndex (activeIndex: number) {
|
||||||
const maxIndex = this.state.matchedRequests.length + this.state.matchedWorkspaces.length;
|
const maxIndex = this.state.matchedRequests.length + this.state.matchedWorkspaces.length;
|
||||||
if (activeIndex < 0) {
|
if (activeIndex < 0) {
|
||||||
activeIndex = this.state.matchedRequests.length - 1;
|
activeIndex = this.state.matchedRequests.length - 1;
|
||||||
@ -80,7 +104,9 @@ class RequestSwitcherModal extends PureComponent {
|
|||||||
// Activate the workspace if there is one
|
// Activate the workspace if there is one
|
||||||
const index = activeIndex - matchedRequests.length;
|
const index = activeIndex - matchedRequests.length;
|
||||||
const workspace = matchedWorkspaces[index];
|
const workspace = matchedWorkspaces[index];
|
||||||
this._activateWorkspace(workspace);
|
if (workspace) {
|
||||||
|
this._activateWorkspace(workspace);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Create request if no match
|
// Create request if no match
|
||||||
this._createRequestFromSearch();
|
this._createRequestFromSearch();
|
||||||
@ -101,66 +127,64 @@ class RequestSwitcherModal extends PureComponent {
|
|||||||
this._activateRequest(request);
|
this._activateRequest(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
_activateWorkspace (workspace) {
|
_activateWorkspace (workspace: Workspace) {
|
||||||
if (!workspace) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.handleSetActiveWorkspace(workspace._id);
|
this.props.handleSetActiveWorkspace(workspace._id);
|
||||||
this.modal.hide();
|
this.modal && this.modal.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
_activateRequest (request) {
|
_activateRequest (request: ?Request) {
|
||||||
if (!request) {
|
if (!request) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.activateRequest(request._id);
|
this.props.activateRequest(request._id);
|
||||||
this.modal.hide();
|
this.modal && this.modal.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleChange (e) {
|
_handleChange (e: SyntheticEvent<HTMLInputElement>) {
|
||||||
this._handleChangeValue(e.target.value);
|
this._handleChangeValue(e.currentTarget.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Return array of path segments for given request or folder */
|
||||||
* Appends path of ancestor groups, delimited by forward slashes
|
_groupOf (requestOrRequestGroup: Request | RequestGroup): Array<string> {
|
||||||
* E.g. Folder1/Folder2/Folder3
|
|
||||||
*/
|
|
||||||
_groupOf (requestOrRequestGroup) {
|
|
||||||
const {workspaceChildren} = this.props;
|
const {workspaceChildren} = this.props;
|
||||||
const requestGroups = workspaceChildren.filter(d => d.type === models.requestGroup.type);
|
const requestGroups = workspaceChildren.filter(d => d.type === models.requestGroup.type);
|
||||||
const matchedGroups = requestGroups.filter(g => g._id === requestOrRequestGroup.parentId);
|
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) {
|
if (matchedGroups.length === 0) {
|
||||||
return currentGroupName;
|
return [currentGroupName];
|
||||||
}
|
}
|
||||||
|
|
||||||
const parentGroup = this._groupOf(matchedGroups[0]);
|
// Still has more parents
|
||||||
const parentGroupText = parentGroup ? `${parentGroup}/` : '';
|
if (currentGroupName) {
|
||||||
const group = `${parentGroupText}${currentGroupName}`;
|
return [currentGroupName, ...this._groupOf(matchedGroups[0])];
|
||||||
|
}
|
||||||
|
|
||||||
return group;
|
// It's the child
|
||||||
|
return this._groupOf(matchedGroups[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
_isMatch (searchStrings) {
|
_isMatch (searchStrings: string): (Request) => boolean {
|
||||||
return (request) => {
|
return (request: Request): boolean => {
|
||||||
let finalUrl = request.url;
|
// Disable URL filtering until we have proper UI to show this
|
||||||
if (request.parameters) {
|
// let finalUrl = request.url;
|
||||||
finalUrl = joinUrlAndQueryString(
|
// if (request.parameters) {
|
||||||
finalUrl,
|
// finalUrl = joinUrlAndQueryString(
|
||||||
buildQueryStringFromParams(request.parameters));
|
// finalUrl,
|
||||||
}
|
// buildQueryStringFromParams(request.parameters));
|
||||||
|
// }
|
||||||
|
|
||||||
// Match request attributes
|
// Match request attributes
|
||||||
const matchesAttributes = fuzzyMatchAll(searchStrings,
|
const matchesAttributes = fuzzyMatchAll(searchStrings, [
|
||||||
[
|
request.name,
|
||||||
request.name,
|
// finalUrl,
|
||||||
finalUrl,
|
// request.method,
|
||||||
request.method,
|
this._groupOf(request).join('/')
|
||||||
this._groupOf(request)
|
]);
|
||||||
]);
|
|
||||||
|
|
||||||
// Match exact Id
|
// Match exact Id
|
||||||
const matchesId = request._id === searchStrings;
|
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 {workspaceChildren, workspaces} = this.props;
|
||||||
const {workspaceId, activeRequestParentId} = this.props;
|
const {workspaceId, activeRequestParentId} = this.props;
|
||||||
|
|
||||||
@ -218,16 +242,18 @@ class RequestSwitcherModal extends PureComponent {
|
|||||||
|
|
||||||
async show () {
|
async show () {
|
||||||
await this._handleChangeValue('');
|
await this._handleChangeValue('');
|
||||||
this.modal.show();
|
this.modal && this.modal.show();
|
||||||
setTimeout(() => this._input.focus(), 100);
|
setTimeout(() => {
|
||||||
|
this._input && this._input.focus();
|
||||||
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
hide () {
|
hide () {
|
||||||
this.modal.hide();
|
this.modal && this.modal.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle () {
|
toggle () {
|
||||||
if (this.modal.isOpen()) {
|
if (this.modal && this.modal.isOpen()) {
|
||||||
this.hide();
|
this.hide();
|
||||||
} else {
|
} else {
|
||||||
this.show();
|
this.show();
|
||||||
@ -248,14 +274,15 @@ class RequestSwitcherModal extends PureComponent {
|
|||||||
return (
|
return (
|
||||||
<Modal ref={this._setModalRef} dontFocus tall>
|
<Modal ref={this._setModalRef} dontFocus tall>
|
||||||
<ModalHeader hideCloseButton>
|
<ModalHeader hideCloseButton>
|
||||||
<div className="pull-right txt-sm pad-right">
|
<div className="pull-right txt-sm pad-right tall">
|
||||||
<span className="monospace">tab</span> or
|
<span className="vertically-center">
|
||||||
|
<div>
|
||||||
<span className="monospace">↑ ↓</span> to navigate
|
<span className="monospace">tab</span> or
|
||||||
|
<span className="monospace">↑↓</span> to navigate
|
||||||
<span className="monospace">↵</span> to select
|
<span className="monospace">↵</span> to select
|
||||||
|
<span className="monospace">esc</span> to dismiss
|
||||||
<span className="monospace">esc</span> to dismiss
|
</div>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>Quick Switch</div>
|
<div>Quick Switch</div>
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
@ -264,7 +291,7 @@ class RequestSwitcherModal extends PureComponent {
|
|||||||
<div className="form-control form-control--outlined no-margin">
|
<div className="form-control form-control--outlined no-margin">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Fuzzy filter by request name, folder, url, method, or query parameters"
|
placeholder="Filter by name or folder"
|
||||||
ref={this._setInputRef}
|
ref={this._setInputRef}
|
||||||
value={searchString}
|
value={searchString}
|
||||||
onChange={this._handleChange}
|
onChange={this._handleChange}
|
||||||
@ -284,7 +311,7 @@ class RequestSwitcherModal extends PureComponent {
|
|||||||
<Button onClick={this._activateRequest} value={r} className={buttonClasses}>
|
<Button onClick={this._activateRequest} value={r} className={buttonClasses}>
|
||||||
{requestGroup && (
|
{requestGroup && (
|
||||||
<div className="pull-right faint italic">
|
<div className="pull-right faint italic">
|
||||||
{requestGroup.name}
|
{this._groupOf(r).join(' / ')}
|
||||||
|
|
||||||
<i className="fa fa-folder-o"/>
|
<i className="fa fa-folder-o"/>
|
||||||
</div>
|
</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;
|
export default RequestSwitcherModal;
|
||||||
|
@ -52,7 +52,7 @@ class SidebarFilter extends PureComponent {
|
|||||||
<input
|
<input
|
||||||
ref={this._setInputRef}
|
ref={this._setInputRef}
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Filter by name, folder, url"
|
placeholder="Filter"
|
||||||
defaultValue={this.props.filter}
|
defaultValue={this.props.filter}
|
||||||
onChange={this._handleOnChange}
|
onChange={this._handleOnChange}
|
||||||
/>
|
/>
|
||||||
|
@ -113,13 +113,16 @@ export const selectSidebarChildren = createSelector(
|
|||||||
const hasMatchedChildren = child.children.find(c => c.hidden === false);
|
const hasMatchedChildren = child.children.find(c => c.hidden === false);
|
||||||
|
|
||||||
// Try to match request attributes
|
// 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, [
|
const hasMatchedAttributes = fuzzyMatchAll(sidebarFilter, [
|
||||||
name,
|
name,
|
||||||
url,
|
// url,
|
||||||
method,
|
method,
|
||||||
...(parameters ? parameters.map(p => `${p.name}=${p.value}`) : []),
|
// ...(parameters ? parameters.map(p => `${p.name}=${p.value}`) : []),
|
||||||
...parentNames
|
...parentNames
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -191,11 +194,7 @@ export const selectUnseenWorkspaces = createSelector(
|
|||||||
const {workspaces, workspaceMetas} = entities;
|
const {workspaces, workspaceMetas} = entities;
|
||||||
return workspaces.filter(workspace => {
|
return workspaces.filter(workspace => {
|
||||||
const meta = workspaceMetas.find(m => m.parentId === workspace._id);
|
const meta = workspaceMetas.find(m => m.parentId === workspace._id);
|
||||||
if (meta && !meta.hasSeen) {
|
return !!(meta && !meta.hasSeen);
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
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