Skip to content

Commit

Permalink
Pre-config for header, endpoint and smdUrl. Also, ErrorBoundaries add…
Browse files Browse the repository at this point in the history
…ed, Backward compatibility with auto init by using #json-rpc-root selector in html
  • Loading branch information
mikhail-eremin committed Jul 27, 2020
1 parent bc38a8f commit ebb955f
Show file tree
Hide file tree
Showing 21 changed files with 265 additions and 81 deletions.
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,23 @@
SMD Box is UI for human-readable displaying of JSON-RPC SMD schemas from remote url, allowing you to call RPC methods live, view and log results.

## Getting started
Smdbox script exposes it's initialization to window.smdbox variable. Call window.smdbox() to initialize smdbox with default options, which are:
```javascript
const defaultOptions = {
endpoint: null, // api endpoint url
smdUrl: null, // smd scheme url
headers: {}, // headers added to each request smdbox makes
selector: '#json-rpc-root', // element to which smdbox is inserted
};
```
You can override any of this options to pre-fill project options.

* Run:
For backward-compatibility with previous versions there's a possibility to initialize smdbox without any calls - just leave this block in html (no options can be passed to init this way):
```html
<div id="json-rpc-root"></div>
```

* Build:
* `yarn run dev` — watches the project with continuous rebuild at localhost:4500
* `yarn run prod` — builds minified project for production
* `yarn run dist` — same as 'prod', but assets are made without hash (e.g. for deploys from github)
Expand All @@ -14,4 +29,4 @@ SMD Box is UI for human-readable displaying of JSON-RPC SMD schemas from remote

When project is set up you're able to choose methods from list at left sidebar, view method's description, it's input and output params, and run selected method on remote server to see results.

History of successfull calls and their input/output are shown in "History" window (click History at top navigation).
History of successfull calls and their input/output are shown in "History" window (click History at top navigation).
2 changes: 1 addition & 1 deletion dist/app.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions dist/app.js

Large diffs are not rendered by default.

12 changes: 9 additions & 3 deletions dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,14 @@
<title>SMD Box</title>
<!--<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css">-->
<link rel="stylesheet" href="https://bootswatch.com/3/paper/bootstrap.min.css">
<link href="/app.css" rel="stylesheet"></head>
<link href="/app.css" rel="stylesheet"><script type="text/javascript" src="/app.js"></script></head>
<body>
<div id="json-rpc-root"></div>
<script type="text/javascript" src="/app.js"></script></body>
<!-- USE THIS BLOCK TO AUTO INIT SMDBOX WITHOUT CALLS <div id="json-rpc-root"></div>-->
<div id="smdbox-root"></div>
<script>
if (window.smdbox) {
window.smdbox({ selector: '#smdbox-root' })
}
</script>
</body>
</html>
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "smdbox",
"version": "1.0.2",
"version": "1.0.3",
"main": "src/index.jsx",
"repository": "https://gitlab.semrush.net/m.eremin/smdbox",
"author": "Semrush",
Expand All @@ -22,7 +22,7 @@
"axios": "0.18.1",
"bem-cl": "1.0.2",
"copy-to-clipboard": "3.0.6",
"lodash": "4.17.4",
"lodash": "4.17.19",
"prop-types": "15.6.0",
"react": "16.12.0",
"react-bootstrap": "0.33.1",
Expand Down
10 changes: 9 additions & 1 deletion src/assets/html/index.dev.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@
<link rel="stylesheet" href="https://bootswatch.com/3/paper/bootstrap.min.css">
</head>
<body>
<div id="json-rpc-root"></div>
<!-- USE THIS BLOCK TO AUTO INIT SMDBOX WITHOUT CALLS <div id="json-rpc-root"></div>-->
<div id="smdbox-root"></div>
<script>
if (window.smdbox) {
window.smdbox({
selector: '#smdbox-root',
})
}
</script>
</body>
</html>
8 changes: 7 additions & 1 deletion src/assets/html/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
<link rel="stylesheet" href="https://bootswatch.com/3/paper/bootstrap.min.css">
</head>
<body>
<div id="json-rpc-root"></div>
<!-- USE THIS BLOCK TO AUTO INIT SMDBOX WITHOUT CALLS <div id="json-rpc-root"></div>-->
<div id="smdbox-root"></div>
<script>
if (window.smdbox) {
window.smdbox({ selector: '#smdbox-root' })
}
</script>
</body>
</html>
98 changes: 50 additions & 48 deletions src/components/Application/index.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import bemCl from 'bem-cl';

import ErrorBoundary from 'components/ErrorBoundary';
import Project from 'containers/Project';
import MethodViewer from 'containers/MethodViewer';
import History from 'containers/History';
Expand Down Expand Up @@ -39,55 +39,57 @@ class Application extends React.Component {

render() {
return (
<div className={b()}>
<nav className="navbar navbar-inverse navbar-static-top">
<div className="container-fluid">
<div className="navbar-header">
<a className="navbar-brand" href="#">SMDbox</a>
<ErrorBoundary>
<div className={b()}>
<nav className="navbar navbar-inverse navbar-static-top">
<div className="container-fluid">
<div className="navbar-header">
<a className="navbar-brand" href="#">SMDbox</a>
</div>
{ this.props.isProjectCreated &&
<ul className="nav navbar-nav navbar-right">
<li><a onClick={this.showHistory}>History</a></li>
<li><a onClick={this.props.openSettings}>Settings</a></li>
<li><a onClick={this.props.clearProject}>Exit</a></li>
</ul>
}
</div>
{ this.props.isProjectCreated &&
<ul className="nav navbar-nav navbar-right">
<li><a onClick={this.showHistory}>History</a></li>
<li><a onClick={this.props.openSettings}>Settings</a></li>
<li><a onClick={this.props.clearProject}>Exit</a></li>
</ul>
}
</div>
</nav>
{
!this.props.isProjectCreated ?
<Grid style={{ paddingTop: '15px' }}>
<Project />
</Grid> :
<Grid fluid>
<Row>
<Col md={3} className={b('content-column').toString()}>
<Sidebar />
</Col>
<Col md={9} className={b('content-column').toString()}>
<MethodViewer />
</Col>
</Row>
<Modal show={this.props.settingsOpen} onHide={this.hideSettings}>
<Modal.Header closeButton>
<Modal.Title>Project settings</Modal.Title>
</Modal.Header>
<Modal.Body>
<Project mode="settings" onSubmit={this.hideSettings} />
</Modal.Body>
</Modal>
</nav>
{
!this.props.isProjectCreated ?
<Grid style={{ paddingTop: '15px' }}>
<Project />
</Grid> :
<Grid fluid>
<Row>
<Col md={3} className={b('content-column').toString()}>
<Sidebar />
</Col>
<Col md={9} className={b('content-column').toString()}>
<MethodViewer />
</Col>
</Row>
<Modal show={this.props.settingsOpen} onHide={this.hideSettings}>
<Modal.Header closeButton>
<Modal.Title>Project settings</Modal.Title>
</Modal.Header>
<Modal.Body>
<Project mode="settings" onSubmit={this.hideSettings} />
</Modal.Body>
</Modal>

<Modal show={this.state.showHistory} onHide={this.hideHistory} bsSize="large">
<Modal.Header closeButton>
<Modal.Title>Request history</Modal.Title>
</Modal.Header>
<Modal.Body>
<History />
</Modal.Body>
</Modal>
</Grid>
}
</div>
<Modal show={this.state.showHistory} onHide={this.hideHistory} bsSize="large">
<Modal.Header closeButton>
<Modal.Title>Request history</Modal.Title>
</Modal.Header>
<Modal.Body>
<History />
</Modal.Body>
</Modal>
</Grid>
}
</div>
</ErrorBoundary>
);
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/components/CrashScreen/CrashScreen.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.sb-crashscreen {
text-align: center;
padding: 80px;
}
32 changes: 32 additions & 0 deletions src/components/CrashScreen/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button } from 'react-bootstrap';
import bemCl from 'bem-cl';
import './CrashScreen.scss';
const b = bemCl('sb-crashscreen');

class CrashScreen extends React.Component {
static propTypes = {
clearProject: PropTypes.func.isRequired,
}
onReset = () => {
this.props.clearProject();
}
render() {
return (
<div className={b()}>
<h1>OOPS! Everything crashed</h1>
<h2>No one knows why</h2>
<h3>Fortunately, you have this magic button</h3>
<p>
<br />
<Button bsSize="large" type="submit" bsStyle="success" onClick={this.onReset}>
Clear project cache and restart
</Button>
</p>
</div>
);
}
}

export default CrashScreen;
28 changes: 28 additions & 0 deletions src/components/ErrorBoundary/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import CrashScreen from 'containers/CrashScreen';

class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}

static getDerivedStateFromError() {
return { hasError: true };
}

componentDidCatch(error, errorInfo) {
console.error(error, errorInfo);
}

render() {
if (this.state.hasError) {
// Можно отрендерить запасной UI произвольного вида
return <CrashScreen />;
}

return this.props.children;
}
}

export default ErrorBoundary;
23 changes: 18 additions & 5 deletions src/components/Project/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,26 @@ class Project extends React.Component {

this.state = {
endpoint: this.props.endpoint || '',
smdUrl: this.props.smdUrl || '',
headers: map(this.props.headers, (value = '', key = '') => ({ key, value }))
};

this.fetchSmd = debounce(this.fetchSmd.bind(this), 800);

// if endpoint is set initially - preload scheme
if (this.state.endpoint !== '' && !props.created) {
this.fetchSmd(this.state.smdUrl);
}
}


componentWillReceiveProps({ endpoint }) {
componentWillReceiveProps({ endpoint, smdUrl }) {
if (endpoint !== this.props.endpoint) {
this.setState({ endpoint });
}
if (smdUrl !== this.props.smdUrl) {
this.setState({ smdUrl });
}
}

fetchSmd(url, isRefresh = false) {
Expand All @@ -66,6 +75,7 @@ class Project extends React.Component {
e.preventDefault();
this.props.create({
endpoint: this.state.endpoint,
smdUrl: this.state.smdUrl,
headers: reduce(this.state.headers, (res, header) => {
if (header.key && header.value) { res[header.key] = header.value; }
return res;
Expand Down Expand Up @@ -98,7 +108,9 @@ class Project extends React.Component {
}

handleChangeUrl = (e) => {
this.fetchSmd(e.nativeEvent.target.value);
this.setState({ smdUrl: e.nativeEvent.target.value }, () => {
this.fetchSmd(this.state.smdUrl);
});
}

handleChangeHeaderName = (index, value) => {
Expand Down Expand Up @@ -134,13 +146,14 @@ class Project extends React.Component {
{ mode !== modes.SETTINGS &&
<div>
<h4>SMD scheme *
{
this.props.fetchingSchema && <span className={b.createProject('loading')}> <i className="glyphicon glyphicon-refresh" /></span>
}
{
this.props.fetchingSchema && <span className={b.createProject('loading')}> <i className="glyphicon glyphicon-refresh" /></span>
}
</h4>
<FormGroup validationState={this.getFormValidationState()}>
<FormControl
placeholder="Enter SMD scheme url"
value={this.state.smdUrl}
onChange={this.handleChangeUrl}
/>
</FormGroup>
Expand Down
12 changes: 12 additions & 0 deletions src/containers/CrashScreen/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { connect } from 'react-redux';
import CrashScreen from 'components/CrashScreen';
import { clearProjectWithDbReset as clearProject } from '../Project/actions';

export default connect(
() => ({

}),
{
clearProject,
}
)(CrashScreen);
1 change: 1 addition & 0 deletions src/containers/Project/actionTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const FETCH_SUCCESS = 'PROJECT/FETCH_SUCCESS';
export const FETCH_REQUEST = 'PROJECT/FETCH_REQUEST';
export const FETCH_ERROR = 'PROJECT/FETCH_ERROR';
export const CLEAR = 'PROJECT/CLEAR';
export const CLEAR_WITH_DB = 'PROJECT/CLEAR_WITH_DB';
export const SAVE_TO_HISTORY = 'PROJECT/SAVE_TO_HISTORY';
export const OPEN_SETTINGS = 'PROJECT/OPEN_SETTINGS';
export const CLOSE_SETTINGS = 'PROJECT/CLOSE_SETTINGS';
Expand Down
5 changes: 5 additions & 0 deletions src/containers/Project/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ export function clearProject() {
};
}

export function clearProjectWithDbReset() {
return {
type: ACTION_TYPES.CLEAR_WITH_DB
};
}

export function openSettings() {
return {
Expand Down
Loading

0 comments on commit ebb955f

Please sign in to comment.