Merge pull request #69 from guardicore/feature/add-config-import-export
Feature/add config import export
This commit is contained in:
commit
05ddc592ec
|
@ -64,6 +64,7 @@
|
||||||
"bootstrap": "^3.3.7",
|
"bootstrap": "^3.3.7",
|
||||||
"core-js": "^2.5.1",
|
"core-js": "^2.5.1",
|
||||||
"fetch": "^1.1.0",
|
"fetch": "^1.1.0",
|
||||||
|
"js-file-download": "^0.4.1",
|
||||||
"normalize.css": "^4.0.0",
|
"normalize.css": "^4.0.0",
|
||||||
"prop-types": "^15.5.10",
|
"prop-types": "^15.5.10",
|
||||||
"react": "^15.6.1",
|
"react": "^15.6.1",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Form from 'react-jsonschema-form';
|
import Form from 'react-jsonschema-form';
|
||||||
import {Col, Nav, NavItem} from 'react-bootstrap';
|
import {Col, Nav, NavItem} from 'react-bootstrap';
|
||||||
|
import fileDownload from 'js-file-download';
|
||||||
|
|
||||||
class ConfigurePageComponent extends React.Component {
|
class ConfigurePageComponent extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -14,8 +15,7 @@ class ConfigurePageComponent extends React.Component {
|
||||||
this.state = {
|
this.state = {
|
||||||
schema: {},
|
schema: {},
|
||||||
configuration: {},
|
configuration: {},
|
||||||
saved: false,
|
lastAction: 'none',
|
||||||
reset: false,
|
|
||||||
sections: [],
|
sections: [],
|
||||||
selectedSection: 'basic',
|
selectedSection: 'basic',
|
||||||
allMonkeysAreDead: true
|
allMonkeysAreDead: true
|
||||||
|
@ -52,8 +52,7 @@ class ConfigurePageComponent extends React.Component {
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(res => {
|
.then(res => {
|
||||||
this.setState({
|
this.setState({
|
||||||
saved: true,
|
lastAction: 'saved',
|
||||||
reset: false,
|
|
||||||
schema: res.schema,
|
schema: res.schema,
|
||||||
configuration: res.configuration
|
configuration: res.configuration
|
||||||
});
|
});
|
||||||
|
@ -92,8 +91,7 @@ class ConfigurePageComponent extends React.Component {
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(res => {
|
.then(res => {
|
||||||
this.setState({
|
this.setState({
|
||||||
reset: true,
|
lastAction: 'reset',
|
||||||
saved: false,
|
|
||||||
schema: res.schema,
|
schema: res.schema,
|
||||||
configuration: res.configuration
|
configuration: res.configuration
|
||||||
});
|
});
|
||||||
|
@ -101,6 +99,32 @@ class ConfigurePageComponent extends React.Component {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onReadFile = (event) => {
|
||||||
|
try {
|
||||||
|
this.setState({
|
||||||
|
configuration: JSON.parse(event.target.result),
|
||||||
|
selectedSection: 'basic',
|
||||||
|
lastAction: 'import_success'
|
||||||
|
});
|
||||||
|
this.currentSection = 'basic';
|
||||||
|
this.currentFormData = {};
|
||||||
|
} catch(SyntaxError) {
|
||||||
|
this.setState({lastAction: 'import_failure'});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
exportConfig = () => {
|
||||||
|
this.updateConfigSection();
|
||||||
|
fileDownload(JSON.stringify(this.state.configuration, null, 2), 'monkey.conf');
|
||||||
|
};
|
||||||
|
|
||||||
|
importConfig = (event) => {
|
||||||
|
let reader = new FileReader();
|
||||||
|
reader.onload = this.onReadFile;
|
||||||
|
reader.readAsText(event.target.files[0]);
|
||||||
|
event.target.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
updateMonkeysRunning = () => {
|
updateMonkeysRunning = () => {
|
||||||
fetch('/api')
|
fetch('/api')
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
|
@ -160,22 +184,45 @@ class ConfigurePageComponent extends React.Component {
|
||||||
Reset to defaults
|
Reset to defaults
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{ this.state.reset ?
|
</div>
|
||||||
|
</Form>
|
||||||
|
: ''}
|
||||||
|
<div className="text-center">
|
||||||
|
<button onClick={() => document.getElementById('uploadInputInternal').click()}
|
||||||
|
className="btn btn-info btn-lg" style={{margin: '5px'}}>
|
||||||
|
Import Config
|
||||||
|
</button>
|
||||||
|
<input id="uploadInputInternal" type="file" accept=".conf" onChange={this.importConfig} style={{display: 'none'}} />
|
||||||
|
<button type="button" onClick={this.exportConfig} className="btn btn-info btn-lg" style={{margin: '5px'}}>
|
||||||
|
Export config
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{ this.state.lastAction === 'reset' ?
|
||||||
<div className="alert alert-success">
|
<div className="alert alert-success">
|
||||||
<i className="glyphicon glyphicon-ok-sign" style={{'marginRight': '5px'}}/>
|
<i className="glyphicon glyphicon-ok-sign" style={{'marginRight': '5px'}}/>
|
||||||
Configuration reset successfully.
|
Configuration reset successfully.
|
||||||
</div>
|
</div>
|
||||||
: ''}
|
: ''}
|
||||||
{ this.state.saved ?
|
{ this.state.lastAction === 'saved' ?
|
||||||
<div className="alert alert-success">
|
<div className="alert alert-success">
|
||||||
<i className="glyphicon glyphicon-ok-sign" style={{'marginRight': '5px'}}/>
|
<i className="glyphicon glyphicon-ok-sign" style={{'marginRight': '5px'}}/>
|
||||||
Configuration saved successfully.
|
Configuration saved successfully.
|
||||||
</div>
|
</div>
|
||||||
: ''}
|
: ''}
|
||||||
|
{ this.state.lastAction === 'import_failure' ?
|
||||||
|
<div className="alert alert-danger">
|
||||||
|
<i className="glyphicon glyphicon-exclamation-sign" style={{'marginRight': '5px'}}/>
|
||||||
|
Failed importing configuration. Invalid config file.
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
|
||||||
: ''}
|
: ''}
|
||||||
|
{ this.state.lastAction === 'import_success' ?
|
||||||
|
<div className="alert alert-success">
|
||||||
|
<i className="glyphicon glyphicon-ok-sign" style={{'marginRight': '5px'}}/>
|
||||||
|
Configuration imported successfully.
|
||||||
|
</div>
|
||||||
|
: ''}
|
||||||
|
</div>
|
||||||
|
|
||||||
</Col>
|
</Col>
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue