mirror of
https://github.com/Kong/insomnia
synced 2024-11-07 14:19:58 +00:00
Updated stuff
This commit is contained in:
parent
56c5015fc3
commit
103d41f5fb
@ -37,7 +37,7 @@ function buildRequest (request) {
|
||||
}
|
||||
|
||||
export function addRequest (name = 'My Request') {
|
||||
return (dispatch, getState) => {
|
||||
return (dispatch) => {
|
||||
dispatch(loadStart());
|
||||
const request = buildRequest({name});
|
||||
dispatch({type: types.REQUEST_ADD, request});
|
||||
|
30
app/components/RequestBodyEditor.js
Normal file
30
app/components/RequestBodyEditor.js
Normal file
@ -0,0 +1,30 @@
|
||||
import React, {Component, PropTypes} from 'react';
|
||||
import CodeEditor from './base/Editor'
|
||||
|
||||
class RequestBodyEditor extends Component {
|
||||
shouldComponentUpdate (nextProps) {
|
||||
return this.props.request !== nextProps.request;
|
||||
}
|
||||
|
||||
render () {
|
||||
const {request, onChange, className} = this.props;
|
||||
return (
|
||||
<CodeEditor
|
||||
value={request.body}
|
||||
className={className}
|
||||
onChange={onChange}
|
||||
options={{mode: request._mode}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
RequestBodyEditor.propTypes = {
|
||||
request: PropTypes.shape({
|
||||
body: PropTypes.string.isRequired,
|
||||
_mode: PropTypes.string.isRequired
|
||||
}).isRequired,
|
||||
onChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default RequestBodyEditor;
|
@ -1,53 +1,56 @@
|
||||
import React, {PropTypes} from 'react'
|
||||
import Dropdown from '../components/Dropdown'
|
||||
import Dropdown from './base/Dropdown'
|
||||
|
||||
const Sidebar = (props) => (
|
||||
<aside id="sidebar" className="pane">
|
||||
<header className="pane__header bg-primary">
|
||||
<h1>
|
||||
<Dropdown right={true}>
|
||||
<a href="#" className="pane__header__content">
|
||||
<i className="fa fa-angle-down pull-right"></i>
|
||||
{props.loading ? <i className="fa fa-refresh fa-spin pull-right"></i> : ''}
|
||||
Insomnia
|
||||
</a>
|
||||
<ul className="bg-super-light">
|
||||
<li><button>hello</button></li>
|
||||
<li><button>hello</button></li>
|
||||
<li><button>hello</button></li>
|
||||
<li><button>hello</button></li>
|
||||
<li><button>hello</button></li>
|
||||
</ul>
|
||||
</Dropdown>
|
||||
</h1>
|
||||
</header>
|
||||
<div className="pane__body grid-v hide-scrollbars bg-dark">
|
||||
<ul className="sidebar-items">
|
||||
<li className="grid">
|
||||
<div className="form-control col">
|
||||
<input type="text" placeholder="Filter Requests"/>
|
||||
</div>
|
||||
<button className="btn" onClick={(e) => props.addRequest()}>
|
||||
<i className="fa fa-plus-circle"></i>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<ul className="sidebar-items row">
|
||||
{props.requests.map((request) => {
|
||||
const isActive = request.id === props.activeRequest.id;
|
||||
return (
|
||||
<li key={request.id} className={'sidebar-item ' + (isActive ? 'active': '')}>
|
||||
<a href="#" onClick={() => {props.activateRequest(request.id)}}>{request.name}</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
<div className="grid-v">
|
||||
<header className="pane__header bg-primary">
|
||||
<h1>
|
||||
<Dropdown right={true}>
|
||||
<a href="#" className="pane__header__content">
|
||||
<i className="fa fa-angle-down pull-right"></i>
|
||||
{props.loading ? <i className="fa fa-refresh fa-spin pull-right"></i> : ''}
|
||||
Insomnia
|
||||
</a>
|
||||
<ul className="bg-super-light">
|
||||
<li><button>hello</button></li>
|
||||
<li><button>hello</button></li>
|
||||
<li><button>hello</button></li>
|
||||
<li><button>hello</button></li>
|
||||
<li><button>hello</button></li>
|
||||
</ul>
|
||||
</Dropdown>
|
||||
</h1>
|
||||
</header>
|
||||
<div className="pane__body hide-scrollbars bg-dark">
|
||||
<ul className="sidebar-items">
|
||||
<li className="grid">
|
||||
<div className="form-control col">
|
||||
<input type="text" placeholder="Filter Requests"/>
|
||||
</div>
|
||||
<button className="btn" onClick={(e) => props.addRequest()}>
|
||||
<i className="fa fa-plus-circle"></i>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<ul className="sidebar-items">
|
||||
{props.requests.map((request) => {
|
||||
const isActive = request.id === props.activeRequest.id;
|
||||
return (
|
||||
<li key={request.id} className={'sidebar-item ' + (isActive ? 'active': '')}>
|
||||
<a href="#" onClick={() => {props.activateRequest(request.id)}}>{request.name}</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
|
||||
Sidebar.propTypes = {
|
||||
activateRequest: PropTypes.func.isRequired,
|
||||
addRequest: PropTypes.func.isRequired,
|
||||
requests: PropTypes.array.isRequired,
|
||||
activeRequest: PropTypes.object,
|
||||
loading: PropTypes.bool.isRequired
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, {Component, PropTypes} from 'react'
|
||||
import Input from '../components/Input';
|
||||
import Dropdown from '../components/Dropdown';
|
||||
import Input from './base/Input';
|
||||
import Dropdown from './base/Dropdown';
|
||||
import {METHODS} from '../constants/global';
|
||||
|
||||
class UrlInput extends Component {
|
||||
|
@ -3,34 +3,39 @@ import React, {Component, PropTypes} from 'react';
|
||||
class Dropdown extends Component {
|
||||
constructor () {
|
||||
super();
|
||||
this.state = {open: false};
|
||||
this.state = {
|
||||
open: false
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
// Capture clicks outside the component and close the dropdown
|
||||
// TODO: Remove this listener when component unmounts
|
||||
document.addEventListener('click', (e) => {
|
||||
if (!this.refs.container.contains(e.target)) {
|
||||
e.preventDefault();
|
||||
this.setState({open: false});
|
||||
}
|
||||
});
|
||||
document.addEventListener('click', this._clickEvenCallback.bind(this));
|
||||
}
|
||||
|
||||
handleClick (e) {
|
||||
_clickEvenCallback (e) {
|
||||
if (!this.refs.container.contains(e.target)) {
|
||||
e.preventDefault();
|
||||
this.setState({open: false});
|
||||
}
|
||||
}
|
||||
|
||||
_handleClick (e) {
|
||||
e.preventDefault();
|
||||
this.setState({open: !this.state.open});
|
||||
}
|
||||
|
||||
render () {
|
||||
const {initialValue, value} = this.props;
|
||||
const classes = ['dropdown'];
|
||||
|
||||
this.state.open && classes.push('dropdown--open');
|
||||
this.props.right && classes.push('dropdown--right');
|
||||
|
||||
return (
|
||||
<div ref="container"
|
||||
className={'dropdown ' +
|
||||
(this.state.open ? 'dropdown--open ' : ' ') +
|
||||
(this.props.right ? 'dropdown--right ' : ' ')
|
||||
}
|
||||
onClick={this.handleClick.bind(this)}>
|
||||
className={classes.join(' ')}
|
||||
onClick={this._handleClick.bind(this)}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
)
|
@ -3,7 +3,7 @@ import {getDOMNode} from 'react-dom';
|
||||
import CodeMirror from 'codemirror';
|
||||
|
||||
// Modes
|
||||
import 'codemirror/mode/css/css';
|
||||
import '../../../node_modules/codemirror/mode/css/css';
|
||||
import 'codemirror/mode/htmlmixed/htmlmixed';
|
||||
import 'codemirror/mode/javascript/javascript';
|
||||
|
||||
@ -20,6 +20,17 @@ import 'codemirror/addon/fold/xml-fold';
|
||||
import 'codemirror/addon/fold/foldgutter';
|
||||
import 'codemirror/addon/fold/foldgutter.css';
|
||||
|
||||
// TODO: Figure out how to lint (json-lint doesn't build in webpack environment)
|
||||
// import 'codemirror/addon/lint/lint';
|
||||
// import 'codemirror/addon/lint/json-lint';
|
||||
// import 'codemirror/addon/lint/html-lint';
|
||||
// import 'codemirror/addon/lint/lint.css';
|
||||
// import * as jsonlint from 'jsonlint';
|
||||
// import * as htmlhint from 'htmlhint';
|
||||
|
||||
// window.jsonlint = jsonlint;
|
||||
// window.htmlhint = htmlhint;
|
||||
|
||||
// CSS Themes
|
||||
import 'codemirror/theme/material.css'
|
||||
import 'codemirror/theme/railscasts.css'
|
||||
@ -32,7 +43,7 @@ import 'codemirror/theme/seti.css'
|
||||
import 'codemirror/theme/monokai.css'
|
||||
|
||||
// App styles
|
||||
import '../css/components/editor.scss';
|
||||
import '../../css/components/editor.scss';
|
||||
|
||||
const DEFAULT_DEBOUNCE_MILLIS = 500;
|
||||
|
||||
@ -40,7 +51,12 @@ const BASE_CODEMIRROR_OPTIONS = {
|
||||
theme: 'monokai',
|
||||
lineNumbers: true,
|
||||
foldGutter: true,
|
||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
|
||||
// lint: true,
|
||||
gutters: [
|
||||
'CodeMirror-linenumbers',
|
||||
'CodeMirror-foldgutter',
|
||||
'CodeMirror-lint-markers'
|
||||
],
|
||||
cursorScrollMargin: 80,
|
||||
extraKeys: {
|
||||
"Ctrl-Q": function (cm) {
|
||||
@ -60,13 +76,11 @@ class Editor extends Component {
|
||||
var textareaNode = this.refs.textarea;
|
||||
|
||||
this.codeMirror = CodeMirror.fromTextArea(textareaNode, BASE_CODEMIRROR_OPTIONS);
|
||||
this.codeMirror.on('change', this.codemirrorValueChanged.bind(this));
|
||||
this.codeMirror.on('focus', this.focusChanged.bind(this, true));
|
||||
this.codeMirror.on('blur', this.focusChanged.bind(this, false));
|
||||
this.codeMirror.on('paste', this.codemirrorValueChanged.bind(this));
|
||||
this.codeMirror.on('change', this._codemirrorValueChanged.bind(this));
|
||||
this.codeMirror.on('paste', this._codemirrorValueChanged.bind(this));
|
||||
this._currentCodemirrorValue = this.props.defaultValue || this.props.value || '';
|
||||
this.codemirrorSetValue(this._currentCodemirrorValue);
|
||||
this.codemirrorSetOptions(this.props.options);
|
||||
this._codemirrorSetValue(this._currentCodemirrorValue);
|
||||
this._codemirrorSetOptions(this.props.options);
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
@ -77,35 +91,48 @@ class Editor extends Component {
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (this.codeMirror && nextProps.value !== undefined && this._currentCodemirrorValue !== nextProps.value) {
|
||||
this.codemirrorSetValue(nextProps.value);
|
||||
// Don't update if no CodeMirror instance
|
||||
if (!this.codeMirror) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't update if no value passed
|
||||
if (nextProps.value === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't update if same value passed again
|
||||
if (this._currentCodemirrorValue === nextProps.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the new value
|
||||
this._codemirrorSetValue(nextProps.value);
|
||||
|
||||
// Reset any options that may have changed
|
||||
this.codemirrorSetOptions(nextProps.options);
|
||||
this._codemirrorSetOptions(nextProps.options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus the cursor to the editor
|
||||
*/
|
||||
focus () {
|
||||
if (this.codeMirror) {
|
||||
this.codeMirror.focus();
|
||||
}
|
||||
}
|
||||
|
||||
focusChanged (focused) {
|
||||
this.setState({isFocused: focused});
|
||||
this.props.onFocusChange && this.props.onFocusChange(focused);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set options on the CodeMirror editor while also sanitizing them
|
||||
* Sets options on the CodeMirror editor while also sanitizing them
|
||||
* @param options
|
||||
*/
|
||||
codemirrorSetOptions (options) {
|
||||
_codemirrorSetOptions (options) {
|
||||
if (options.mode === 'json') {
|
||||
options.mode = 'application/json';
|
||||
}
|
||||
|
||||
if (options.mode === 'application/json') {
|
||||
// ld+json looks better because keys are a different color
|
||||
options.mode = 'application/ld+json';
|
||||
}
|
||||
|
||||
@ -118,7 +145,7 @@ class Editor extends Component {
|
||||
* Wrapper function to add extra behaviour to our onChange event
|
||||
* @param doc CodeMirror document
|
||||
*/
|
||||
codemirrorValueChanged (doc) {
|
||||
_codemirrorValueChanged (doc) {
|
||||
// Update our cached value
|
||||
var newValue = doc.getValue();
|
||||
this._currentCodemirrorValue = newValue;
|
||||
@ -138,10 +165,10 @@ class Editor extends Component {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the CodeMirror value without triggering the onChange event
|
||||
* Sets the CodeMirror value without triggering the onChange event
|
||||
* @param code the code to set in the editor
|
||||
*/
|
||||
codemirrorSetValue (code) {
|
||||
_codemirrorSetValue (code) {
|
||||
this._ignoreNextChange = true;
|
||||
this.codeMirror.setValue(code);
|
||||
}
|
||||
@ -149,10 +176,12 @@ class Editor extends Component {
|
||||
render () {
|
||||
return (
|
||||
<div className={`editor ${this.props.className || ''}`}>
|
||||
<textarea name={this.props.path}
|
||||
ref='textarea'
|
||||
defaultValue={this.props.value}
|
||||
autoComplete='off'></textarea>
|
||||
<textarea
|
||||
name={this.props.path}
|
||||
ref='textarea'
|
||||
defaultValue={this.props.value}
|
||||
autoComplete='off'>
|
||||
</textarea>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -3,7 +3,8 @@ import {connect} from 'react-redux'
|
||||
import {bindActionCreators} from 'redux'
|
||||
import {Tab, Tabs, TabList, TabPanel} from 'react-tabs';
|
||||
|
||||
import CodeEditor from '../components/CodeEditor'
|
||||
import CodeEditor from '../components/base/Editor'
|
||||
import RequestBodyEditor from '../components/RequestBodyEditor'
|
||||
import UrlInput from '../components/UrlInput'
|
||||
import Sidebar from '../components/Sidebar'
|
||||
|
||||
@ -14,8 +15,7 @@ import * as GlobalActions from '../actions/global'
|
||||
Tabs.setUseDefaultStyles(false);
|
||||
|
||||
class App extends Component {
|
||||
renderPageBody() {
|
||||
const {actions, activeRequest} = this.props;
|
||||
renderPageBody (actions, activeRequest) {
|
||||
|
||||
if (!activeRequest) {
|
||||
return <div></div>;
|
||||
@ -24,15 +24,16 @@ class App extends Component {
|
||||
const updateRequestBody = actions.updateRequestBody.bind(null, activeRequest.id);
|
||||
const updateRequestUrl = actions.updateRequestUrl.bind(null, activeRequest.id);
|
||||
const updateRequestMethod = actions.updateRequestMethod.bind(null, activeRequest.id);
|
||||
|
||||
|
||||
return (
|
||||
<div className="grid grid-collapse">
|
||||
<section id="request" className="pane col grid-v">
|
||||
<header className="pane__header bg-super-light">
|
||||
<UrlInput onUrlChange={updateRequestUrl}
|
||||
onMethodChange={updateRequestMethod}
|
||||
method={activeRequest.method}
|
||||
urlValue={activeRequest.url}/>
|
||||
<UrlInput
|
||||
onUrlChange={updateRequestUrl}
|
||||
onMethodChange={updateRequestMethod}
|
||||
method={activeRequest.method}
|
||||
urlValue={activeRequest.url}/>
|
||||
</header>
|
||||
<div className="pane__body grid-v">
|
||||
<Tabs selectedIndex={0} className="grid-v">
|
||||
@ -43,10 +44,11 @@ class App extends Component {
|
||||
<Tab><button className="btn">Headers</button></Tab>
|
||||
</TabList>
|
||||
<TabPanel className="grid-v">
|
||||
<CodeEditor value={activeRequest.body}
|
||||
className="grid-v"
|
||||
onChange={updateRequestBody}
|
||||
options={{mode: activeRequest._mode}}/>
|
||||
<RequestBodyEditor
|
||||
className="grid-v"
|
||||
onChange={updateRequestBody}
|
||||
request={activeRequest}
|
||||
options={{mode: activeRequest._mode}}/>
|
||||
</TabPanel>
|
||||
<TabPanel className="grid-v">Params</TabPanel>
|
||||
<TabPanel className="grid-v">Basic Auth</TabPanel>
|
||||
@ -57,8 +59,8 @@ class App extends Component {
|
||||
<section id="response" className="pane col grid-v">
|
||||
<header className="pane__header text-center bg-light">
|
||||
<div className="pane__header__content">
|
||||
<div className="tag success"><strong>200</strong> SUCCESS</div>
|
||||
<div className="tag"><strong>GET</strong> https://google.com</div>
|
||||
<div className="tag success"><strong>200</strong> SUCCESS</div>
|
||||
<div className="tag"><strong>GET</strong> https://google.com</div>
|
||||
</div>
|
||||
</header>
|
||||
<div className="pane__body grid-v">
|
||||
@ -71,19 +73,21 @@ class App extends Component {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
render () {
|
||||
const {actions, loading, activeRequest, allRequests} = this.props;
|
||||
const {actions, loading, requests} = this.props;
|
||||
const activeRequest = requests.all.find(r => r.id === requests.active);
|
||||
|
||||
return (
|
||||
<div className="grid bg-dark">
|
||||
<Sidebar
|
||||
activateRequest={actions.activateRequest}
|
||||
addRequest={actions.addRequest}
|
||||
loading={loading}
|
||||
activeRequest={activeRequest}
|
||||
requests={allRequests}/>
|
||||
loading={loading}
|
||||
requests={requests.all}/>
|
||||
<div className="col">
|
||||
{this.renderPageBody()}
|
||||
{this.renderPageBody(actions, activeRequest)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@ -91,16 +95,23 @@ class App extends Component {
|
||||
}
|
||||
|
||||
App.propTypes = {
|
||||
allRequests: PropTypes.array.isRequired,
|
||||
activeRequest: PropTypes.object,
|
||||
actions: PropTypes.shape({
|
||||
activateRequest: PropTypes.func.isRequired,
|
||||
updateRequestBody: PropTypes.func.isRequired,
|
||||
updateRequestUrl: PropTypes.func.isRequired,
|
||||
updateRequestMethod: PropTypes.func.isRequired
|
||||
}).isRequired,
|
||||
requests: PropTypes.shape({
|
||||
all: PropTypes.array.isRequired,
|
||||
active: PropTypes.string // "required" but can be null
|
||||
}).isRequired,
|
||||
loading: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
function mapStateToProps (state) {
|
||||
return {
|
||||
actions: state.actions,
|
||||
allRequests: state.requests.all,
|
||||
activeRequest: state.requests.all.find(r => r.id === state.requests.active),
|
||||
requests: state.requests,
|
||||
loading: state.loading
|
||||
};
|
||||
}
|
||||
|
@ -32,6 +32,9 @@
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
|
||||
/* Normal Overrides */
|
||||
cursor: text; // Show text cursor everywhere (not just in .Codemirror-lines)
|
||||
}
|
||||
|
||||
.CodeMirror-lines {
|
||||
|
@ -37,8 +37,8 @@ export default function (state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case types.REQUEST_ADD:
|
||||
all = requestsReducer(state.all, action);
|
||||
return Object.assign({}, state, {all, active});
|
||||
active = action.request.id;
|
||||
return Object.assign({}, state, {all, active});
|
||||
case types.REQUEST_UPDATE:
|
||||
all = requestsReducer(state.all, action);
|
||||
return Object.assign({}, state, {all});
|
||||
|
@ -10,6 +10,8 @@
|
||||
"dependencies": {
|
||||
"classnames": "^2.2.3",
|
||||
"codemirror": "^5.12.0",
|
||||
"htmlhint": "^0.9.12",
|
||||
"jsonlint": "^1.6.2",
|
||||
"jsonschema": "^1.1.0",
|
||||
"react": "^0.14.7",
|
||||
"react-dom": "^0.14.7",
|
||||
|
@ -2,6 +2,8 @@ var path = require('path');
|
||||
var webpack = require('webpack');
|
||||
|
||||
module.exports = {
|
||||
target: 'web',
|
||||
devtool: 'source-map',
|
||||
context: path.join(__dirname, '../app'),
|
||||
entry: [
|
||||
'./index.js',
|
||||
|
@ -7,6 +7,8 @@ base.entry = [
|
||||
'webpack/hot/only-dev-server'
|
||||
].concat(base.entry);
|
||||
|
||||
|
||||
base.devtool = 'eval'; // Fastest form of source maps
|
||||
base.debug = true;
|
||||
base.devtool = 'inline-source-maps';
|
||||
base.output.path = path.join(base.output.path, '/dev');
|
||||
|
Loading…
Reference in New Issue
Block a user