Skip to content

Commit

Permalink
Merge branch 'next' into feature/body-types
Browse files Browse the repository at this point in the history
  • Loading branch information
eliihen committed Jul 24, 2017
2 parents 51cc78e + 9a178f5 commit 69e77d3
Show file tree
Hide file tree
Showing 33 changed files with 585 additions and 181 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
![RESTED](https://github.com/esphen/RESTED/raw/master/images/rested-logo-full.png)
![RESTED](https://github.com/esphen/RESTED/raw/master/doc/images/rested-logo-full.png)

A REST client for the rest of us.

Expand All @@ -8,7 +8,8 @@ _Note: This is the source code, the extension download is [here](https://addons.
[![Coverage Status](https://coveralls.io/repos/github/esphen/RESTED/badge.svg?branch=next)](https://coveralls.io/github/esphen/RESTED?branch=next)
[![Join the chat at https://gitter.im/RESTEDclient](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/RESTEDclient?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

**RESTED** is a new take on rest clients for browsers.
**RESTED** is a new take on REST clients for browsers.

It is designed to be easy to use to let you work as effective as possible.
It features all the most commonly used HTTP methods, setting headers, beautiful themes,
saving requests in your browser, and more.
Expand All @@ -21,7 +22,7 @@ it is also awesomely easy to contribute to the project! Everything is
javascript and html using React.js and Redux, so come join! All contributions
welcome.

![Image of RESTED](https://github.com/esphen/RESTED/raw/master/images/rested-app.png)
![Image of RESTED](https://github.com/esphen/RESTED/raw/master/doc/images/rested-app.png)

## How to contribute
In order to work on this project, you're going to need a few things:
Expand Down Expand Up @@ -57,8 +58,7 @@ If you need to empty and reset the database, enter
the entire database and force a clean install on refresh.

**Please develop on the next branch.**
This is where all the magic happens, and all the development on the react
rewrite takes place.
This is where all the magic happens.

### Tests

Expand Down
3 changes: 2 additions & 1 deletion firefox/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "RESTED",
"version": "2.0.0",
"version": "2.0.4",
"description": "A REST client for the rest of us",
"homepage_url": "https://github.com/esphen/RESTED",
"contributors": [
Expand Down Expand Up @@ -38,6 +38,7 @@
},
"permissions": [
"<all_urls>",
"webRequest",
"storage"
]
}
3 changes: 2 additions & 1 deletion google-chrome/manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "RESTED",
"version": "2.0.0",
"version": "2.0.4",
"description": "A REST client for the rest of us",
"homepage_url": "https://github.com/esphen/RESTED",
"manifest_version": 2,
Expand All @@ -26,6 +26,7 @@
},
"permissions": [
"<all_urls>",
"webRequest",
"storage"
]
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"description": "A REST client for the rest of us",
"author": "Espen Henriksen",
"license": "MIT",
"version": "2.0.0",
"version": "2.0.4",
"main": "./main.js",
"permissions": {
"multiprocess": true
Expand Down
8 changes: 8 additions & 0 deletions scripts/build-source-archive.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash
# Execute from the root of the git repo

rm -rf node_modules RESTED.* dist/rested* coverage
cd ..
zip -r -9 RESTED/RESTED.src.zip RESTED
cd RESTED

1 change: 1 addition & 0 deletions src/components/App/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import './GlobalStyles';

import { LeftCol, RightCol } from './StyledComponents';


/*
* This must be a React.Component because DragDropContext
* attaches a ref to the component, which as we know will
Expand Down
10 changes: 7 additions & 3 deletions src/components/Request/HeaderNameAutosuggest.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { PropTypes } from 'react';
import { FormControl } from 'react-bootstrap';
import classNames from 'classnames';
import Autosuggest from 'react-autosuggest';

import headers from 'constants/commonHeaders';
Expand Down Expand Up @@ -38,10 +38,14 @@ const renderSuggestion = suggestion => (
</div>
);

const renderInputComponent = inputProps => (
<FormControl type="text" {...inputProps} />
const renderInputComponent = ({ className, ...rest }) => (
<input className={classNames(className, 'form-control')} {...rest} />
);

renderInputComponent.propTypes = {
className: PropTypes.string,
};

export default class HeaderNameAutosuggest extends React.PureComponent {
static propTypes = {
input: PropTypes.shape({}).isRequired,
Expand Down
9 changes: 9 additions & 0 deletions src/components/Request/Titlebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ function Titlebar(props) {
<IconButton
onClick={() => {
if (formPristine || formInvalid) {
/* eslint-disable */
// Debugging for #98
console.log(
'Not adding request because ' +
`formPristine=${formPristine} || formInvalid=${formInvalid}`,
props,
);
/* eslint-enable */

// Set URL as touched to give feedback to user
props.touch('request', 'url');
return;
Expand Down
4 changes: 1 addition & 3 deletions src/components/Request/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import flow from 'lodash.flow';
import * as requestActions from 'store/request/actions';
import * as collectionsActions from 'store/collections/actions';
import { isEditMode } from 'store/config/selectors';
import requestValidation from 'utils/requestValidation';
import { DEFAULT_REQUEST } from 'constants/constants';

import Titlebar from './Titlebar';
Expand Down Expand Up @@ -52,7 +51,7 @@ function Request(props) {
names={['basicAuth.username', 'basicAuth.password']}
component={BasicAuthField}
/>
{['POST', 'PUT', 'PATCH', 'CUSTOM'].includes(formValues.method) && (
{!['GET', 'HEAD'].includes(formValues.method) && (
<BodyField />
)}
</Form>
Expand All @@ -72,7 +71,6 @@ Request.propTypes = {

const formOptions = {
form: requestForm,
validate: requestValidation,
};

const mapStateToProps = state => ({
Expand Down
18 changes: 16 additions & 2 deletions src/components/Response/Headers.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
import React from 'react';
import React, { PropTypes } from 'react';
import Highlight from 'react-highlight';

import Collapse from 'components/Collapsable';
import { responseShape } from 'propTypes/response';

function Headers({ headers }) {
function Headers({ headers, expanded }) {
if (expanded) {
return (
<div>
<h4>Headers</h4>
<Highlight className="http">
{headers.reduce((prev, header) => (
`${prev ? `${prev}\n` : ''}${header.name}: ${header.value}`
), '')}
</Highlight>
</div>
);
}

return (
<Collapse
title="Headers"
Expand All @@ -21,6 +34,7 @@ function Headers({ headers }) {

Headers.propTypes = {
headers: responseShape.headers,
expanded: PropTypes.bool.isRequired,
};

export default Headers;
Expand Down
64 changes: 64 additions & 0 deletions src/components/Response/Redirect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React, { PropTypes } from 'react';
import responsePropTypes, { responseShape } from 'propTypes/response';

import { StyledResponse, StyledHeader, Status } from './StyledComponents';
import Headers from './Headers';

function Titlebar({ url, time, onClick }) {
return (
<StyledHeader expandable onClick={onClick}>
<h3>
Redirect ({(time / 1000).toFixed(3)}s) - <a href={url} className="text-muted">{url}</a>
</h3>
</StyledHeader>
);
}

Titlebar.propTypes = {
url: responseShape.url,
time: responseShape.time,
onClick: PropTypes.func.isRequired,
};

function Redirect(props) {
const {
response,
headers,
isExpanded,
setExpanded,
} = props;

if (!response || !headers) return null;

const { method, url, time } = response;

return (
<StyledResponse
collapsible
expanded={isExpanded}
header={<Titlebar method={method} url={url} time={time} onClick={setExpanded} />}
>
<h3>
<Status
green={response.statusCode >= 200 && response.statusCode < 300}
red={response.statusCode >= 400 && response.statusCode < 600}
>
{response.statusCode}
</Status>
<small> {response.statusLine.replace(/.*\d{3} /, '')}</small>
</h3>

<Headers expanded headers={headers} />
</StyledResponse>
);
}

Redirect.propTypes = {
response: responsePropTypes,
headers: responseShape.headers,
isExpanded: PropTypes.bool.isRequired,
setExpanded: PropTypes.func.isRequired,
};

export default Redirect;

133 changes: 133 additions & 0 deletions src/components/Response/Response.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import { Alert } from 'react-bootstrap';
import Highlight from 'react-highlight';
import formatXml from 'xml-formatter';

import * as Actions from 'store/request/actions';
import { isDisabledHighlighting, isWrapResponse } from 'store/options/selectors';
import responsePropTypes, { responseShape } from 'propTypes/response';
import getContentType from 'utils/contentType';
import approximateSizeFromLength from 'utils/approximateSizeFromLength';

import { StyledResponse, StyledHeader, Status } from './StyledComponents';
import Headers from './Headers';
import RenderedResponse from './RenderedResponse';

function Titlebar({ url, time }) {
return (
<StyledHeader>
<h3>
Response ({time}) - <a href={url} className="text-muted">{url}</a>
</h3>
</StyledHeader>
);
}

Titlebar.propTypes = {
url: responseShape.url,
time: responseShape.time,
};

export function Response(props) {
const {
response,
highlightingDisabled,
wrapResponse,
redirectChain,
interceptedResponse,
} = props;

if (!response || !interceptedResponse) return null;

const { method, url, totalTime } = response;
let { body } = response;

let time;
if (redirectChain.length > 0) {
time = `${(interceptedResponse.time / 1000).toFixed(3)}s, total time ${totalTime / 1000}s`;
} else {
time = `${totalTime / 1000}s`;
}

const contentLength = interceptedResponse.responseHeaders.find(header => (
header.name.toLowerCase() === 'content-length'
));
const contentType = interceptedResponse.responseHeaders.find(header => (
header.name.toLowerCase() === 'content-type'
));

const contentSize = contentLength
? Number(contentLength.value)
: approximateSizeFromLength(body);
const type = getContentType(contentType && contentType.value);

try {
if (type.json) {
body = JSON.stringify(JSON.parse(body), null, 2);
} else if (type.xml) {
body = formatXml(body);
}
} catch (e) {
// eslint-disable-next-line no-console
console.warn('Encountered an error while formatting response as ' +
`${contentType && contentType.value}. Falling back to plain text`, e);
}

return (
<StyledResponse
wrapResponse={wrapResponse}
header={<Titlebar method={method} url={url} time={time} />}
>
<h3>
<Status
green={response.status >= 200 && response.status < 300}
red={response.status >= 400 && response.status < 600}
>
{response.status}
</Status>
<small> {response.statusText}</small>
</h3>

<Headers headers={interceptedResponse.responseHeaders} />
{type.html && <RenderedResponse html={body} />}

{!highlightingDisabled && contentSize < 20000
? (
<Highlight>
{body}
</Highlight>
) : (
<span>
{contentSize >= 20000 && (
<Alert bsStyle="warning">
The size of the response is greater than 20KB, syntax
highlighting has been disabled for performance reasons.
</Alert>
)}

<code><pre>
{body}
</pre></code>
</span>
)
}
</StyledResponse>
);
}

Response.propTypes = {
response: responsePropTypes,
highlightingDisabled: PropTypes.bool.isRequired,
wrapResponse: PropTypes.bool.isRequired,
redirectChain: PropTypes.arrayOf().isRequired,
interceptedResponse: PropTypes.shape({}),
};

const mapStateToProps = state => ({
highlightingDisabled: isDisabledHighlighting(state),
wrapResponse: isWrapResponse(state),
});

export default connect(mapStateToProps, Actions)(Response);

2 changes: 2 additions & 0 deletions src/components/Response/StyledComponents.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export const LoadingSpinner = styled(Fonticon)`
`;

export const StyledHeader = styled.div`
${props => props.expandable && 'cursor: pointer;'}
h3 {
font-size: 15px;
margin: 4px 0;
Expand Down
Loading

0 comments on commit 69e77d3

Please sign in to comment.