Better errors inside environment editors (#257)

This commit is contained in:
Gregory Schier 2017-05-25 11:31:36 -07:00 committed by GitHub
parent dcf7778472
commit 0c2b02c7fc
7 changed files with 91 additions and 40 deletions

View File

@ -1,5 +1,5 @@
import * as querystring from '../../common/querystring';
import {getBasicAuthHeader} from '../../common/misc';
import {getBasicAuthHeader, setDefaultProtocol} from '../../common/misc';
import * as c from './constants';
import {responseToObject} from './misc';
@ -38,7 +38,15 @@ export default async function (accessTokenUrl,
headers: headers
};
const response = await window.fetch(accessTokenUrl, config);
const url = setDefaultProtocol(accessTokenUrl);
let response;
try {
response = await window.fetch(url, config);
} catch (err) {
throw new Error(`Failed to fetch access token at URL "${url}"`);
}
const body = await response.text();
const results = responseToObject(body, [
c.P_ACCESS_TOKEN,

View File

@ -5,7 +5,40 @@ import {DEBOUNCE_MILLIS} from '../../../common/constants';
@autobind
class EnvironmentEditor extends PureComponent {
constructor (props) {
super(props);
this.state = {
error: null,
warning: null
};
}
_handleChange () {
let error = null;
let warning = null;
let value = null;
// Check for JSON parse errors
try {
value = this.getValue();
} catch (err) {
error = err.message;
}
// Check for invalid key names
if (value) {
for (const key of Object.keys(value)) {
if (!key.match(/^[a-zA-Z_$][0-9a-zA-Z_$]*$/)) {
warning = `"${key}" must only contain letters, numbers, and underscores`;
break;
}
}
}
if (this.state.error !== error || this.state.warning !== warning) {
this.setState({error, warning});
}
this.props.didChange();
}
@ -18,12 +51,7 @@ class EnvironmentEditor extends PureComponent {
}
isValid () {
try {
return this.getValue() !== undefined;
} catch (e) {
// Failed to parse JSON
return false;
}
return !this.state.error;
}
render () {
@ -38,22 +66,28 @@ class EnvironmentEditor extends PureComponent {
...props
} = this.props;
const {error, warning} = this.state;
return (
<CodeEditor
ref={this._setEditorRef}
autoPrettify
fontSize={editorFontSize}
indentSize={editorIndentSize}
lineWrapping={lineWrapping}
keyMap={editorKeyMap}
onChange={this._handleChange}
debounceMillis={DEBOUNCE_MILLIS * 6}
defaultValue={JSON.stringify(environment)}
render={render}
getRenderContext={getRenderContext}
mode="application/json"
{...props}
/>
<div className="environment-editor">
<CodeEditor
ref={this._setEditorRef}
autoPrettify
fontSize={editorFontSize}
indentSize={editorIndentSize}
lineWrapping={lineWrapping}
keyMap={editorKeyMap}
onChange={this._handleChange}
debounceMillis={DEBOUNCE_MILLIS * 6}
defaultValue={JSON.stringify(environment)}
render={render}
getRenderContext={getRenderContext}
mode="application/json"
{...props}
/>
{error && <p className="notice error margin">{error}</p>}
{(!error && warning) && <p className="notice warning margin">{warning}</p>}
</div>
);
}
}

View File

@ -133,7 +133,7 @@ class WorkspaceEnvironmentsEditModal extends PureComponent {
_didChange () {
const isValid = this._envEditor.isValid();
if (this.state.isValid === isValid) {
if (this.state.isValid !== isValid) {
this.setState({isValid});
}

View File

@ -241,12 +241,12 @@ class RequestPane extends PureComponent {
</Tab>
<Tab onClick={this._trackTabQuery}>
<button>
Query {numParameters ? <span className="bubble">{numParameters}</span> : null}
Query {numParameters > 0 && <span className="bubble">{numParameters}</span>}
</button>
</Tab>
<Tab onClick={this._trackTabHeaders}>
<button>
Header {numHeaders ? <span className="bubble">{numHeaders}</span> : null}
Header {numHeaders > 0 && <span className="bubble">{numHeaders}</span>}
</button>
</Tab>
</TabList>

View File

@ -90,9 +90,9 @@ class ResponsePane extends PureComponent {
const {body, timeline, encoding} = this.state.response;
const headers = timeline
.filter(v => v.name === 'HEADER_IN')
.map(v => v.value)
.join('');
.filter(v => v.name === 'HEADER_IN')
.map(v => v.value)
.join('');
const bodyBuffer = new Buffer(body, encoding);
const fullResponse = `${headers}${bodyBuffer}`;
@ -249,8 +249,11 @@ class ResponsePane extends PureComponent {
</Tab>
<Tab>
<Button onClick={this._trackTab} value="Headers">
Header {response.headers.length ? (
<span className="bubble">{response.headers.length}</span>) : null}
Header
{' '}
{response.headers.length > 0 && (
<span className="bubble">{response.headers.length}</span>
)}
</Button>
</Tab>
<Tab>
@ -259,7 +262,7 @@ class ResponsePane extends PureComponent {
<span className="bubble">{cookieHeaders.length}</span>) : null}
</Button>
</Tab>
{response.timeline && response.timeline.length && (
{(response.timeline && response.timeline.length > 0) && (
<Tab>
<Button onClick={this._trackTab} value="Timeline">Timeline</Button>
</Tab>
@ -305,15 +308,15 @@ class ResponsePane extends PureComponent {
/>
</div>
</TabPanel>
{(response.timeline && response.timeline.length) && (
{(response.timeline && response.timeline.length > 0) && (
<TabPanel>
<ResponseTimelineViewer
key={response._id}
timeline={response.timeline || []}
editorLineWrapping={editorLineWrapping}
editorFontSize={editorFontSize}
editorIndentSize={editorIndentSize}
/>
<ResponseTimelineViewer
key={response._id}
timeline={response.timeline || []}
editorLineWrapping={editorLineWrapping}
editorFontSize={editorFontSize}
editorIndentSize={editorIndentSize}
/>
</TabPanel>
)}
</Tabs>

View File

@ -0,0 +1,5 @@
.environment-editor {
display: grid;
grid-template-rows: 1fr auto;
height: 100%;
}

View File

@ -24,6 +24,7 @@
@import 'components/dropdown';
@import 'components/editable';
@import 'components/environment-modal';
@import 'components/environment-editor';
@import 'components/header-editor';
@import 'components/key-value-editor';
@import 'components/method-dropdown';