diff --git a/app/components/RequestBodyEditor.js b/app/components/RequestBodyEditor.js index c9c09e16b0..a3e7165933 100644 --- a/app/components/RequestBodyEditor.js +++ b/app/components/RequestBodyEditor.js @@ -3,18 +3,17 @@ import Editor from './base/Editor' class RequestBodyEditor extends Component { render () { - const {request, onChange, className} = this.props; - const mode = request.contentType || 'text/plain'; + const {body, contentType, requestId, onChange, className} = this.props; return ( @@ -23,10 +22,13 @@ class RequestBodyEditor extends Component { } RequestBodyEditor.propTypes = { - request: PropTypes.shape({ - body: PropTypes.string.isRequired - }).isRequired, - onChange: PropTypes.func.isRequired + // Functions + onChange: PropTypes.func.isRequired, + + // Other + requestId: PropTypes.string.isRequired, + body: PropTypes.string.isRequired, + contentType: PropTypes.string.isRequired }; export default RequestBodyEditor; diff --git a/app/components/RequestPane.js b/app/components/RequestPane.js new file mode 100644 index 0000000000..f5350d3993 --- /dev/null +++ b/app/components/RequestPane.js @@ -0,0 +1,132 @@ +import React, {Component, PropTypes} from 'react' +import {Tab, Tabs, TabList, TabPanel} from 'react-tabs' + +import KeyValueEditor from '../components/base/KeyValueEditor' +import Dropdown from '../components/base/Dropdown' + +import RequestBodyEditor from '../components/RequestBodyEditor' +import RequestAuthEditor from '../components/RequestAuthEditor' +import RequestUrlBar from '../components/RequestUrlBar' + +class RequestPane extends Component { + render () { + const { + request, + sendRequest, + updateRequestUrl, + updateRequestMethod, + updateRequestBody, + updateRequestParams, + updateRequestAuthentication, + updateRequestHeaders + } = this.props; + + if (!request) { + return ( +
+
+
+
+ ) + } + + return ( +
+
+
+ sendRequest(request)} + onUrlChange={updateRequestUrl} + onMethodChange={updateRequestMethod} + url={request.url} + method={request.method} + /> +
+ + + + + + +
    +
  • +
  • +
  • +
  • +
+
+
+ + + + + + +
+ + + + +
+ +
+
+ +
+
+ + +
+ + +
+
+
+
+
+
+ ) + } +} + +RequestPane.propTypes = { + // Functions + sendRequest: PropTypes.func.isRequired, + updateRequestUrl: PropTypes.func.isRequired, + updateRequestMethod: PropTypes.func.isRequired, + updateRequestBody: PropTypes.func.isRequired, + updateRequestParams: PropTypes.func.isRequired, + updateRequestAuthentication: PropTypes.func.isRequired, + updateRequestHeaders: PropTypes.func.isRequired, + + // Other + request: PropTypes.object +}; + +export default RequestPane; diff --git a/app/components/RequestUrlBar.js b/app/components/RequestUrlBar.js index c21f616bc2..44aa46d8b9 100644 --- a/app/components/RequestUrlBar.js +++ b/app/components/RequestUrlBar.js @@ -4,36 +4,40 @@ import Dropdown from './base/Dropdown'; import {METHODS} from '../lib/constants'; class UrlInput extends Component { + _handleFormSubmit (e) { + e.preventDefault(); + this.props.sendRequest(); + } + render () { - const {sendRequest, onUrlChange, onMethodChange, request} = this.props; + const {onUrlChange, onMethodChange, uniquenessKey, url, method} = this.props; return (
    - {METHODS.map((method) => ( -
  • - + {METHODS.map(m => ( +
  • +
  • ))}
{e.preventDefault(); sendRequest(request)}}> + onSubmit={this._handleFormSubmit.bind(this)}> -   
@@ -45,10 +49,9 @@ UrlInput.propTypes = { sendRequest: PropTypes.func.isRequired, onUrlChange: PropTypes.func.isRequired, onMethodChange: PropTypes.func.isRequired, - request: PropTypes.shape({ - url: PropTypes.string.isRequired, - method: PropTypes.string.isRequired - }).isRequired + uniquenessKey: PropTypes.string.isRequired, + url: PropTypes.string.isRequired, + method: PropTypes.string.isRequired }; export default UrlInput; diff --git a/app/components/ResponsePane.js b/app/components/ResponsePane.js new file mode 100644 index 0000000000..5011b9f895 --- /dev/null +++ b/app/components/ResponsePane.js @@ -0,0 +1,91 @@ +import React, {Component, PropTypes} from 'react' +import {Tab, Tabs, TabList, TabPanel} from 'react-tabs' + +import StatusTag from '../components/StatusTag' +import Editor from '../components/base/Editor' +import SizeTag from '../components/SizeTag' +import TimeTag from '../components/TimeTag' + +class ResponsePane extends Component { + render () { + const { + response + } = this.props; + + if (!response) { + return ( +
+
+
+
+ ) + } + + return ( +
+
+
+ {!response ? null : ( +
+ + + +
+ )} +
+ + + + + + + + + + + + + +
+
+ {!response ? null : response.headers.map((h, i) => ( +
+
{h.name}
+
{h.value}
+
+ ))} +
+
+
+
+
+
+ ) + } +} + +ResponsePane.propTypes = { + response: PropTypes.object +}; + +export default ResponsePane; diff --git a/app/components/Sidebar.js b/app/components/Sidebar.js index e492fc1244..e336bbe056 100644 --- a/app/components/Sidebar.js +++ b/app/components/Sidebar.js @@ -1,10 +1,9 @@ import React, {Component, PropTypes} from 'react' import classnames from 'classnames' import WorkspaceDropdown from './../containers/WorkspaceDropdown' -import RequestActionsDropdown from './../containers/RequestActionsDropdown' import RequestGroupActionsDropdown from './../containers/RequestGroupActionsDropdown' import DebouncingInput from './base/DebouncingInput' -import MethodTag from './MethodTag' +import SidebarRequestRow from './SidebarRequestRow' class Sidebar extends Component { onFilterChange (value) { @@ -13,25 +12,25 @@ class Sidebar extends Component { renderRequestGroupRow (requestGroup = null) { const { - activeFilter, - activeRequest, + filter, + activeRequestId, addRequestToRequestGroup, toggleRequestGroup, requests, - workspace + workspaceId } = this.props; let filteredRequests = requests.filter( r => { // TODO: Move this to a lib file - if (!activeFilter) { + if (!filter) { return true; } const requestGroupName = requestGroup ? requestGroup.name : ''; const toMatch = `${requestGroupName}✌${r.method}✌${r.name}`.toLowerCase(); - const matchTokens = activeFilter.toLowerCase().split(' '); + const matchTokens = filter.toLowerCase().split(' '); for (let i = 0; i < matchTokens.length; i++) { let token = `${matchTokens[i]}`; if (toMatch.indexOf(token) === -1) { @@ -44,7 +43,7 @@ class Sidebar extends Component { ); if (!requestGroup) { - filteredRequests = filteredRequests.filter(r => r.parentId === workspace._id); + filteredRequests = filteredRequests.filter(r => r.parentId === workspaceId); return filteredRequests.map(request => this.renderRequestRow(request)); } @@ -52,11 +51,11 @@ class Sidebar extends Component { filteredRequests = filteredRequests.filter(r => r.parentId === requestGroup._id); // Don't show folder if it was not in the filter - if (activeFilter && !filteredRequests.length) { + if (filter && !filteredRequests.length) { return null; } - const isActive = activeRequest && filteredRequests.find(r => r._id == activeRequest._id); + const isActive = activeRequestId && filteredRequests.find(r => r._id == activeRequestId); let folderIconClass = 'fa-folder'; let expanded = !requestGroup.collapsed; @@ -97,36 +96,22 @@ class Sidebar extends Component { } renderRequestRow (request = null, requestGroup = null) { - const {activeRequest, activateRequest} = this.props; - const isActive = request && activeRequest && request._id === activeRequest._id; - + const {activeRequestId, activateRequest} = this.props; + const isActive = request && activeRequestId && request._id === activeRequestId; + return ( -
  • -
    -
    - {request ? ( - - ) : ( - - )} -
    - {request ? ( - - ) : null} -
    -
  • - ); + + ) } render () { - const {activeFilter, requestGroups} = this.props; + const {filter, requestGroups} = this.props; return (
    @@ -145,7 +130,7 @@ class Sidebar extends Component { type="text" placeholder="Filter Items" debounceMillis={300} - value={activeFilter} + value={filter} onChange={this.onFilterChange.bind(this)}/> @@ -156,15 +141,20 @@ class Sidebar extends Component { } Sidebar.propTypes = { + // Functions activateRequest: PropTypes.func.isRequired, + toggleRequestGroup: PropTypes.func.isRequired, addRequestToRequestGroup: PropTypes.func.isRequired, changeFilter: PropTypes.func.isRequired, - toggleRequestGroup: PropTypes.func.isRequired, - activeFilter: PropTypes.string, + + // Other requests: PropTypes.array.isRequired, requestGroups: PropTypes.array.isRequired, - workspace: PropTypes.object.isRequired, - activeRequest: PropTypes.object + workspaceId: PropTypes.string.isRequired, + + // Optional + filter: PropTypes.string, + activeRequestId: PropTypes.string }; export default Sidebar; diff --git a/app/components/SidebarRequestRow.js b/app/components/SidebarRequestRow.js new file mode 100644 index 0000000000..4ddb4b97fd --- /dev/null +++ b/app/components/SidebarRequestRow.js @@ -0,0 +1,47 @@ +import React, {Component, PropTypes} from 'react' +import RequestActionsDropdown from './../containers/RequestActionsDropdown' +import MethodTag from './MethodTag' + +class SidebarRequestRow extends Component { + render () { + const {request, requestGroup, isActive, activateRequest} = this.props; + + return ( +
  • +
    +
    + {request ? ( + + ) : ( + + )} +
    + {request ? ( + + ) : null} +
    +
  • + ); + } +} + +SidebarRequestRow.propTypes = { + // Functions + activateRequest: PropTypes.func.isRequired, + + // Other + request: PropTypes.object.isRequired, + isActive: PropTypes.bool.isRequired, + + // Optional + requestGroup: PropTypes.object +}; + +export default SidebarRequestRow; diff --git a/app/containers/App.js b/app/containers/App.js index 894fd0462b..0d6e61157b 100644 --- a/app/containers/App.js +++ b/app/containers/App.js @@ -1,32 +1,20 @@ import React, {Component, PropTypes} from 'react' import {connect} from 'react-redux' import {bindActionCreators} from 'redux' -import {Tab, Tabs, TabList, TabPanel} from 'react-tabs' -import Editor from '../components/base/Editor' import Prompts from './Prompts' -import KeyValueEditor from '../components/base/KeyValueEditor' -import Dropdown from '../components/base/Dropdown' -import RequestBodyEditor from '../components/RequestBodyEditor' -import RequestAuthEditor from '../components/RequestAuthEditor' -import RequestUrlBar from '../components/RequestUrlBar' -import StatusTag from '../components/StatusTag' -import SizeTag from '../components/SizeTag' -import TimeTag from '../components/TimeTag' -import Sidebar from '../components/Sidebar' import EnvironmentEditModal from '../components/EnvironmentEditModal' +import RequestPane from '../components/RequestPane' +import ResponsePane from '../components/ResponsePane' +import Sidebar from '../components/Sidebar' import * as GlobalActions from '../redux/modules/global' import * as RequestGroupActions from '../redux/modules/requestGroups' import * as RequestActions from '../redux/modules/requests' import * as ModalActions from '../redux/modules/modals' -import * as TabActions from '../redux/modules/tabs' import * as db from '../database' -// Don't inject component styles (use our own) -Tabs.setUseDefaultStyles(false); - class App extends Component { constructor (props) { super(props); @@ -36,194 +24,44 @@ class App extends Component { } } - _renderRequestPanel (actions, activeRequest, tabs) { - if (!activeRequest) { - return ( -
    -
    -
    -
    - ) - } - - return ( -
    -
    -
    - {db.update(activeRequest, {url})}} - onMethodChange={method => {db.update(activeRequest, {method})}} - request={activeRequest} - /> -
    - actions.tabs.select('request', i)} - selectedIndex={tabs.request || 0}> - - - - - -
      -
    • -
    • -
    • -
    • -
    -
    -
    - - - - - - -
    - - {db.update(activeRequest, {body})}} - request={activeRequest}/> - - -
    - {db.update(activeRequest, {params})}} - /> -
    -
    - -
    -
    - - {db.update(activeRequest, {authentication})}} - /> -
    - - {db.update(activeRequest, {headers})}} - /> -
    -
    -
    -
    -
    -
    - ) - } - - _renderResponsePanel (actions, activeResponse, tabs) { - if (!activeResponse) { - return ( -
    -
    -
    -
    - ) - } - - return ( -
    -
    -
    - {!activeResponse ? null : ( -
    - - - -
    - )} -
    - actions.tabs.select('response', i)} - selectedIndex={tabs.response || 0}> - - - - - - - - - - - - -
    -
    - {!activeResponse ? null : activeResponse.headers.map((h, i) => ( -
    -
    {h.name}
    -
    {h.value}
    -
    - ))} -
    -
    -
    -
    -
    -
    - ) - } - render () { - const {actions, tabs, modals, workspaces} = this.props; + const {actions, modals, workspaces} = this.props; const {requests, requestGroups, responses} = workspaces; + const activeRequest = requests.active; const activeResponse = activeRequest ? responses[activeRequest._id] : undefined; return (
    db.requestCreate({parentId: requestGroup._id})} toggleRequestGroup={requestGroup => db.update(requestGroup, {collapsed: !requestGroup.collapsed})} - activeRequest={activeRequest} - activeFilter={requests.filter} + activeRequestId={activeRequest._id} + filter={requests.filter} requestGroups={requestGroups.all.sort((a, b) => a._id > b._id ? -1 : 1)} - requests={requests.all.sort((a, b) => a._id > b._id ? -1 : 1)}/> + requests={requests.all.sort((a, b) => a._id > b._id ? -1 : 1)} + />
    - {this._renderRequestPanel(actions, activeRequest, tabs)} - {this._renderResponsePanel(actions, activeResponse, tabs)} + db.update(activeRequest, {body})} + updateRequestUrl={url => db.update(activeRequest, {url})} + updateRequestMethod={method => db.update(activeRequest, {method})} + updateRequestParams={params => db.update(activeRequest, {params})} + updateRequestAuthentication={authentication => db.update(activeRequest, {authentication})} + updateRequestHeaders={headers => db.update(activeRequest, {headers})} + /> +
    + + {modals.map(m => { if (m.id === EnvironmentEditModal.defaultProps.id) { return ( @@ -246,21 +84,14 @@ class App extends Component { App.propTypes = { actions: PropTypes.shape({ requests: PropTypes.shape({ - update: PropTypes.func.isRequired, - remove: PropTypes.func.isRequired, send: PropTypes.func.isRequired, changeFilter: PropTypes.func.isRequired }), requestGroups: PropTypes.shape({ - remove: PropTypes.func.isRequired, - update: PropTypes.func.isRequired, toggle: PropTypes.func.isRequired }), modals: PropTypes.shape({ hide: PropTypes.func.isRequired - }), - tabs: PropTypes.shape({ - select: PropTypes.func.isRequired }) }).isRequired, workspaces: PropTypes.shape({ @@ -274,7 +105,6 @@ App.propTypes = { active: PropTypes.object }).isRequired }).isRequired, - tabs: PropTypes.object.isRequired, modals: PropTypes.array.isRequired }; @@ -282,7 +112,6 @@ function mapStateToProps (state) { return { actions: state.actions, workspaces: state.workspaces, - tabs: state.tabs, modals: state.modals }; } @@ -291,7 +120,6 @@ function mapDispatchToProps (dispatch) { return { actions: { global: bindActionCreators(GlobalActions, dispatch), - tabs: bindActionCreators(TabActions, dispatch), modals: bindActionCreators(ModalActions, dispatch), requestGroups: bindActionCreators(RequestGroupActions, dispatch), requests: bindActionCreators(RequestActions, dispatch) diff --git a/app/database/index.js b/app/database/index.js index 320c4686c5..df8c5ba6b5 100644 --- a/app/database/index.js +++ b/app/database/index.js @@ -13,7 +13,7 @@ export const TYPE_RESPONSE = 'Response'; let db = new PouchDB('insomnia.db', {adapter: 'websql'}); // For browser console debugging -global.db = db; +// global.db = db; let changeListeners = {}; diff --git a/app/index.js b/app/index.js index 4c097a008f..484af0ac2e 100644 --- a/app/index.js +++ b/app/index.js @@ -1,6 +1,7 @@ import React from 'react' import {render} from 'react-dom' import {Provider} from 'react-redux' +import {Tabs} from 'react-tabs' import createStore from './redux/create' import App from './containers/App' @@ -12,6 +13,9 @@ import './css/lib/fontawesome/css/font-awesome.css' import {initStore} from './redux/initstore' import {initDB} from './database' +// Don't inject component styles (use our own) +Tabs.setUseDefaultStyles(false); + export const store = createStore(); console.log('-- Loading App --'); diff --git a/app/redux/modules/entities.js b/app/redux/modules/entities.js index 83276b7efa..770a83ea12 100644 --- a/app/redux/modules/entities.js +++ b/app/redux/modules/entities.js @@ -37,7 +37,7 @@ const workspaces = generateEntityReducer( ); const requestGroups = generateEntityReducer( - 'requestGroup', + 'requestGroup', requestGroupFns.REQUEST_GROUP_UPDATE, requestGroupFns.REQUEST_GROUP_DELETE ); diff --git a/app/redux/reducer.js b/app/redux/reducer.js index cb91d6a940..d0ed39b34a 100644 --- a/app/redux/reducer.js +++ b/app/redux/reducer.js @@ -1,7 +1,6 @@ import {combineReducers} from 'redux' import workspaces from './modules/workspaces' -import tabs from './modules/tabs' import global from './modules/global' import modals from './modules/modals' import entities from './modules/entities' @@ -10,6 +9,5 @@ export default combineReducers({ workspaces, modals, global, - tabs, entities });