Skip to content
This repository has been archived by the owner on Feb 26, 2020. It is now read-only.

Commit

Permalink
Import config (#39)
Browse files Browse the repository at this point in the history
* Import config

* Grumbles (performance)

* Fix list field; update account.password type

List field: previous code undefined the removed element in the
array, but didn't remove it; showed "undefined" as a result in
the Preview, etc.
  • Loading branch information
axelchalon authored and tomusdrw committed Mar 27, 2018
1 parent 242b96e commit fa51ade
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 37 deletions.
5 changes: 5 additions & 0 deletions package-lock.json

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

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"material-design-lite": "^1.3.0",
"prop-types": "^15.6.1",
"react": "^16.2.0",
"react-dom": "^16.2.0"
"react-dom": "^16.2.0",
"toml": "^2.3.3"
},
"scripts": {
"start": "react-scripts start",
Expand Down
14 changes: 13 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,18 @@ class App extends Component {
});
};

handleError = (error) => {
this.setState({
modal: {
visible: true,
title: 'Error',
content: (
<p>{error}</p>
)
}
});
};

render () {
const {settings, defaults, preset, modal} = this.state;

Expand All @@ -166,7 +178,7 @@ class App extends Component {
</div>
<div className='mdl-cell mdl-cell--4-col mdl-cell--12-col-tablet'>
<Presets preset={preset} defaults={defaults} onChange={this.handlePreset} />
<Preview settings={settings} defaults={defaults} />
<Preview settings={settings} defaults={defaults} onChange={this.handleChange} onError={this.handleError} />
</div>
</div>
</main>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ class Editor extends Component {
if (ev.target.value !== '') {
newValue[idx] = ev.target.value;
} else {
delete newValue[idx];
newValue.splice(idx, 1);
}
this.change(section, prop)(newValue);
}}
Expand Down
1 change: 1 addition & 0 deletions src/components/Importer.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.import input { display: none; }
79 changes: 79 additions & 0 deletions src/components/Importer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';

import toml from 'toml';

import './Importer.css';

import {mix, clone} from '../util';

class Importer extends PureComponent {

static propTypes = {
defaults: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired,
onError: PropTypes.func.isRequired
};

constructor (props) {
super(props);
this.handleFileChange = this.handleFileChange.bind(this);
this.handleClick = this.handleClick.bind(this);
}

handleFileChange (ev) {
const file = ev.target.files[0];
const domTarget = ev.target;
domTarget.value = '';

if (!window.confirm('Do you want to overwrite current config?')) {
return;
}

if (file.name.match(/.*\.toml$/)) {
var reader = new window.FileReader();

reader.onload = _ => {
let importedData;

try {
importedData = toml.parse(reader.result);
} catch (err) {
this.props.onError(`Couldn't parse configuration file. ${err.toString()}`);
return;
}

const data = mix(clone(this.props.defaults), importedData);
domTarget.blur();
this.props.onChange(data);
};

reader.readAsText(file);
} else {
this.props.onError('Please import a .toml configuration file.');
}
}

handleClick () {
this.refs.fileInput.click();
}

render () {
return (
<button
className='mdl-button mdl-button--icon mdl-js-button mdl-js-ripple-efect import'
onClick={this.handleClick}>

<input
type='file'
ref='fileInput'
onChange={this.handleFileChange} />

<i className='material-icons' id='upload'>file_upload</i>
<span className='mdl-tooltip' htmlFor='upload'>Load Config File</span>
</button>
);
}
}

export default Importer;
18 changes: 2 additions & 16 deletions src/components/Presets/Presets.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,12 @@ import Item from '../Item';
import mining from './mining.json';
import ports from './ports.json';

import {mix, clone} from '../../util';

function toVal (val) {
return { name: val, value: val };
}

function mix (a, b) {
if (typeof a !== 'object' || typeof b !== 'object') {
return b || a;
}

Object.keys(a).forEach(key => {
a[key] = mix(a[key], b[key]);
});

return a;
}

const presets = {
'None': null,
'Defaults': null,
Expand Down Expand Up @@ -79,8 +69,4 @@ class Presets extends PureComponent {
}
}

function clone (val) {
return JSON.parse(JSON.stringify(val));
}

export default Presets;
9 changes: 7 additions & 2 deletions src/components/Preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import './Preview.css';

import Importer from './Importer';

import { joinPath, basePath } from '../system';
import data from '../data.compiled.json';
// TODO [ToDr] move to some common?
Expand All @@ -11,7 +13,9 @@ import {fillDescription} from './Editor';
class Preview extends Component {
static propTypes = {
settings: PropTypes.object.isRequired,
defaults: PropTypes.object.isRequired
defaults: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired,
onError: PropTypes.func.isRequired
};

generateConfig = () => {
Expand Down Expand Up @@ -44,6 +48,7 @@ class Preview extends Component {
<textarea className='preview-editor' readOnly value={toToml(settings, defaults)} />
</div>
<div className='mdl-card__menu'>
<Importer defaults={defaults} onChange={this.props.onChange} onError={this.props.onError} />
<a
className='mdl-button mdl-button--icon mdl-js-button mdl-js-ripple-efect'
target='_blank'
Expand All @@ -54,7 +59,7 @@ class Preview extends Component {
<button
className='mdl-button mdl-button--icon mdl-js-button mdl-js-ripple-efect'
onClick={this.generateConfig}>
<i className='material-icons' id='download'>cloud download</i>
<i className='material-icons' id='download'>cloud_download</i>
<span className='mdl-tooltip' htmlFor='download'>Download Config File</span>
</button>
</div>
Expand Down
30 changes: 16 additions & 14 deletions src/data.compiled.json
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,11 @@
},
"password": {
"name": "Password File",
"type": "string",
"type": "string[]",
"description": "File at {} should contain passwords to unlock your accounts. One password per line.",
"default": ""
"default": [
""
]
},
"keys_iterations": {
"name": "Keys deriving iterations",
Expand Down Expand Up @@ -706,6 +708,12 @@
"description": "Secret Store. Requires a special build of Parity."
},
"ipfs": {
"enable": {
"name": "Enable",
"type": "bool",
"description": "Enable IPFS-compatible HTTP API.",
"default": false
},
"port": {
"name": "Port",
"type": "number",
Expand Down Expand Up @@ -733,15 +741,15 @@
]
},
"section": "IPFS API (since 1.7)",
"enable": {
"name": "Enable",
"type": "bool",
"description": "Enable IPFS-compatible HTTP API.",
"default": false
},
"description": "IPFS-compatible API for blockchain data."
},
"dapps": {
"disable": {
"name": "Disable",
"type": "bool",
"description": "Disable the Dapps server (e.g. status page).",
"default": false
},
"path": {
"name": "Dapps Path",
"type": "path",
Expand Down Expand Up @@ -784,12 +792,6 @@
"deprecated": true
},
"section": "Dapps Server",
"disable": {
"name": "Disable",
"type": "bool",
"description": "Disable the Dapps server (e.g. status page).",
"default": false
},
"port": {
"name": "Port",
"type": "number",
Expand Down
7 changes: 5 additions & 2 deletions src/data.extra.json
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,7 @@
"password": {
"name": "Password File",
"description": "File at {} should contain passwords to unlock your accounts. One password per line.",
"default": "",
"type": "string"
"default": [""]
},
"keys_iterations": {
"name": "Keys deriving iterations",
Expand Down Expand Up @@ -483,6 +482,8 @@
"ipfs": {
"section": "IPFS API (since 1.7)",
"description": "IPFS-compatible API for blockchain data.",
"enable": {
},
"port": {
"name": "Port",
"description": "Secret Store will be running on port {}."
Expand All @@ -504,6 +505,8 @@
"dapps": {
"section": "Dapps Server",
"description": "Run and customize the web Dapps Server.",
"disable": {
},
"path": {
"name": "Dapps Path",
"type": "path"
Expand Down
15 changes: 15 additions & 0 deletions src/util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export function mix (a, b) {
if (typeof a !== 'object' || typeof b !== 'object' || Array.isArray(a) || Array.isArray(b)) {
return typeof b === 'undefined' ? a : b;
}

Object.keys(a).forEach(key => {
a[key] = mix(a[key], b[key]);
});

return a;
}

export function clone (val) {
return JSON.parse(JSON.stringify(val));
}

0 comments on commit fa51ade

Please sign in to comment.