Changed environmente editor to JSON editor

This commit is contained in:
Gregory Schier 2016-07-22 14:35:49 -07:00
parent 7dce5ce3c3
commit 40aa0d037b
8 changed files with 197 additions and 150 deletions

View File

@ -1,50 +1,47 @@
import React, {PropTypes} from 'react';
import Link from './base/Link';
import Editor from './base/Editor';
import Modal from './base/Modal';
import ModalBody from './base/ModalBody';
import ModalHeader from './base/ModalHeader';
import ModalFooter from './base/ModalFooter';
import KeyValueEditor from './base/KeyValueEditor';
import ModalComponent from './lib/ModalComponent';
class EnvironmentEditModal extends ModalComponent {
constructor (props) {
super(props);
this.requestGroup = null;
this.state = {
pairs: [],
uniquenessKey: ''
environmentJSON: '{}',
requestGroup: null
}
}
_saveChanges () {
const environment = this._mapPairsToData(this.state.pairs);
this.props.onChange(Object.assign({}, this.requestGroup, {environment}));
const {requestGroup, environmentJSON} = this.state;
let environment;
try {
environment = JSON.parse(environmentJSON);
} catch (e) {
// That's OK. The user will (hopefully) fix the problem
console.warn('Failed to parse environment JSON', e);
return;
}
this.props.onChange(Object.assign({}, requestGroup, {environment}));
this.hide();
}
_keyValueChange (pairs) {
this.setState({pairs});
}
_mapPairsToData (pairs) {
return pairs.reduce((prev, curr) => {
return Object.assign({}, prev, {[curr.name]: curr.value});
}, {});
}
_mapDataToPairs (data) {
return Object.keys(data).map(key => ({name: key, value: data[key]}));
_handleChange (environmentJSON) {
this.setState({environmentJSON});
}
_update (requestGroup) {
this.requestGroup = requestGroup;
this.setState({
pairs: this._mapDataToPairs(requestGroup.environment),
uniquenessKey: requestGroup._id
})
const environmentJSON = JSON.stringify(requestGroup.environment, null, '\t');
this.setState({environmentJSON, requestGroup});
}
show (requestGroup) {
@ -58,26 +55,30 @@ class EnvironmentEditModal extends ModalComponent {
}
render () {
const {uniquenessKey, pairs} = this.state;
const {environmentJSON} = this.state;
return (
<Modal ref="modal" top={true} {...this.props}>
<ModalHeader>Environment Variables</ModalHeader>
<ModalBody>
<KeyValueEditor onChange={this._keyValueChange.bind(this)}
uniquenessKey={uniquenessKey}
pairs={pairs}
namePlaceholder="BASE_URL"
valuePlaceholder="https://api.insomnia.com/v1"/>
<div className="pad-bottom">
<Editor
onChange={this._handleChange.bind(this)}
value={environmentJSON}
lightTheme={true}
mode="application/json"
/>
</div>
</ModalBody>
<ModalFooter>
<div className="pull-right">
<button className="btn" onClick={this._saveChanges.bind(this)}>Save</button>
</div>
<div className="pad txt-sm">
This data can be used for&nbsp;
<Link href="https://mozilla.github.io/nunjucks/templating.html">Nunjucks Templating</Link>&nbsp;
in your requests.
<div className="pad faint italic txt-sm tall">
* this data can be used for&nbsp;
<Link href="https://mozilla.github.io/nunjucks/templating.html">
Nunjucks Templating
</Link> in your requests
</div>
</ModalFooter>
</Modal>

View File

@ -3,10 +3,10 @@ import React, {Component, PropTypes} from 'react';
class ResponseBodyWebview extends Component {
_setBody () {
const {body, contentType, url} = this.props;
const {webview} = this.refs;
const {webView} = this.refs;
const newBody = body.replace('<head>', `<head><base href="${url}">`);
webview.loadURL(`data:${contentType},${encodeURIComponent(newBody)}`);
webView.loadURL(`data:${contentType},${encodeURIComponent(newBody)}`);
}
componentDidUpdate () {
@ -26,19 +26,19 @@ class ResponseBodyWebview extends Component {
}
componentDidMount () {
const {webview} = this.refs;
const {webView} = this.refs;
const cb = () => {
webview.removeEventListener('dom-ready', cb);
webView.removeEventListener('dom-ready', cb);
this._setBody();
};
webview.addEventListener('dom-ready', cb);
webView.addEventListener('dom-ready', cb);
}
render () {
return (
<webview ref="webview" src="about:blank"></webview>
<webview ref="webView" src="about:blank"></webview>
);
}
}

View File

@ -223,12 +223,16 @@ class Editor extends Component {
}
render () {
const {value, readOnly, fontSize} = this.props;
const {value, readOnly, fontSize, lightTheme} = this.props;
const classes = classnames(
'editor',
this.props.className,
{'editor--readonly': readOnly}
{
'editor--readonly': readOnly,
'editor--light-theme': !!lightTheme,
'editor--dark-theme': !lightTheme
}
);
return (
@ -253,7 +257,8 @@ Editor.propTypes = {
fontSize: PropTypes.number,
value: PropTypes.string,
prettify: PropTypes.bool,
className: PropTypes.any
className: PropTypes.any,
lightTheme: PropTypes.bool
};
export default Editor;

View File

@ -57,7 +57,7 @@ class RequestGroupActionsDropdown extends Component {
</button>
</li>
<li>
<button onClick={e => EnvironmentEditModal.show()}>
<button onClick={e => EnvironmentEditModal.show(requestGroup)}>
<i className="fa fa-code"></i> Environment
</button>
</li>

View File

@ -21,7 +21,7 @@
.CodeMirror-scrollbar-filler,
.CodeMirror-gutter-filler {
// Let the background behind show through
background-color: $bg-super-dark !important;
background-color: transparent !important;
border: 0;
}
@ -82,114 +82,143 @@
}
/* Based on Sublime Text's Monokai theme */
.editor:not(.editor--light-theme) {
.cm-s-default.CodeMirror {
color: #f8f8f2;
}
.cm-s-default.CodeMirror {
color: #f8f8f2;
.cm-s-default div.CodeMirror-selected {
//background: #49483E;
background: $hl-xl;
}
.cm-s-default .CodeMirror-line::selection, .cm-s-default .CodeMirror-line > span::selection, .cm-s-default .CodeMirror-line > span > span::selection {
//background: rgba(73, 72, 62, .99);
}
.cm-s-default .CodeMirror-line::-moz-selection, .cm-s-default .CodeMirror-line > span::-moz-selection, .cm-s-default .CodeMirror-line > span > span::-moz-selection {
//background: rgba(73, 72, 62, .99);
}
.cm-s-default .CodeMirror-gutters {
//background: #272822;
border-right: 0px;
}
.cm-s-default .CodeMirror-guttermarker {
color: white;
}
.cm-s-default .CodeMirror-guttermarker-subtle {
color: #d0d0d0;
}
.cm-s-default .CodeMirror-linenumber {
color: #d0d0d0;
}
.cm-s-default .CodeMirror-cursor {
border-left: 1px solid #f8f8f0;
}
.cm-s-default span.cm-comment {
color: #75715e;
}
.cm-s-default span.cm-atom {
color: lighten($surprise, 5);
}
.cm-s-default span.cm-number {
color: lighten($surprise, 5);
}
.cm-s-default span.cm-property, .cm-s-default span.cm-attribute {
color: lighten($success, 5);
}
.cm-s-default span.cm-keyword {
color: #f92672;
}
.cm-s-default span.cm-builtin {
color: #66d9ef;
}
.cm-s-default span.cm-string {
color: lighten($notice, 5);
}
.cm-s-default span.cm-variable {
color: #f8f8f2;
}
.cm-s-default span.cm-variable-2 {
color: #9effff;
}
.cm-s-default span.cm-variable-3 {
color: #66d9ef;
}
.cm-s-default span.cm-def {
color: #fd971f;
}
.cm-s-default span.cm-bracket {
color: #f8f8f2;
}
.cm-s-default span.cm-tag {
color: #f92672;
}
.cm-s-default span.cm-header {
color: lighten($surprise, 5);
}
.cm-s-default span.cm-link {
color: lighten($surprise, 5);
}
.cm-s-default span.cm-error {
background: #f92672;
color: #f8f8f0;
}
.cm-s-default .CodeMirror-activeline-background {
background: $hl-md;
}
.cm-s-default .CodeMirror-matchingbracket {
text-decoration: underline;
color: white !important;
}
}
.cm-s-default div.CodeMirror-selected {
background: #49483E;
}
.editor--light-theme {
.cm-s-default span {
color: $hl;
}
.cm-s-default .CodeMirror-line::selection, .cm-s-default .CodeMirror-line > span::selection, .cm-s-default .CodeMirror-line > span > span::selection {
background: rgba(73, 72, 62, .99);
}
.cm-s-default span.cm-string {
color: saturate(darken($notice, 30), 100);
}
.cm-s-default .CodeMirror-line::-moz-selection, .cm-s-default .CodeMirror-line > span::-moz-selection, .cm-s-default .CodeMirror-line > span > span::-moz-selection {
background: rgba(73, 72, 62, .99);
}
.cm-s-default span.cm-property, .cm-s-default span.cm-attribute {
color: saturate(darken($success, 15), 100);
}
.cm-s-default .CodeMirror-gutters {
background: #272822;
border-right: 0px;
}
.cm-s-default span.cm-atom,
.cm-s-default span.cm-number {
color: saturate(darken($surprise, 30), 100);
}
.cm-s-default .CodeMirror-guttermarker {
color: white;
}
.cm-s-default .CodeMirror-activeline-background {
background: $hl-md;
}
.cm-s-default .CodeMirror-guttermarker-subtle {
color: #d0d0d0;
}
.cm-s-default .CodeMirror-linenumber {
color: #d0d0d0;
}
.cm-s-default .CodeMirror-cursor {
border-left: 1px solid #f8f8f0;
}
.cm-s-default span.cm-comment {
color: #75715e;
}
.cm-s-default span.cm-atom {
color: lighten($surprise, 5);
}
.cm-s-default span.cm-number {
color: lighten($surprise, 5);
}
.cm-s-default span.cm-property, .cm-s-default span.cm-attribute {
color: lighten($success, 5);
}
.cm-s-default span.cm-keyword {
color: #f92672;
}
.cm-s-default span.cm-builtin {
color: #66d9ef;
}
.cm-s-default span.cm-string {
color: lighten($notice, 5);
}
.cm-s-default span.cm-variable {
color: #f8f8f2;
}
.cm-s-default span.cm-variable-2 {
color: #9effff;
}
.cm-s-default span.cm-variable-3 {
color: #66d9ef;
}
.cm-s-default span.cm-def {
color: #fd971f;
}
.cm-s-default span.cm-bracket {
color: #f8f8f2;
}
.cm-s-default span.cm-tag {
color: #f92672;
}
.cm-s-default span.cm-header {
color: lighten($surprise, 5);
}
.cm-s-default span.cm-link {
color: lighten($surprise, 5);
}
.cm-s-default span.cm-error {
background: #f92672;
color: #f8f8f0;
}
.cm-s-default .CodeMirror-activeline-background {
background: #373831;
}
.cm-s-default .CodeMirror-matchingbracket {
text-decoration: underline;
color: white !important;
.cm-s-default .CodeMirror-matchingbracket {
text-decoration: underline;
}
}

View File

@ -230,7 +230,7 @@
}
.form-control {
padding: 0;
padding: 0 $padding-xs 0 0;
width: 100%;
input {
padding: $padding-xs;

View File

@ -69,7 +69,11 @@ webview {
table {
td {
padding-top: 0.25em;
padding-top: $padding-sm;
&:not(:last-child) {
padding-right: $padding-lg;
}
}
th {
@ -156,6 +160,11 @@ i.fa {
padding-top: $padding-md;
}
.pad-bottom {
box-sizing: border-box;
padding-bottom: $padding-md;
}
.no-pad-bottom {
padding-bottom: 0;
}

View File

@ -18,7 +18,10 @@ function buildRequestConfig (request, patch = {}) {
timeout: -1,
// Unzip gzipped responses
gzip: true
gzip: true,
// Time the request
time: true
};
// Set the URL, including the query parameters
@ -71,7 +74,7 @@ function actuallySend (request, settings) {
contentType: networkResponse.headers['content-type'],
url: config.url, // TODO: Handle redirects somehow
elapsedTime: networkResponse.elapsedTime,
bytes: networkResponse.connection.bytesRead,
bytesRead: networkResponse.connection.bytesRead,
body: networkResponse.body,
headers: Object.keys(networkResponse.headers).map(name => {
const value = networkResponse.headers[name];