Update the Console dapp (#5602)
* Init Console Dapp structure * Watches and status * First REPL and display * Attaching console * Selectable autocomplete * working console // Display objects nicely * Multilines in Console Dapps * Better UI * Eval on window object * Save console gistory * Adding views * Add settings to the console dapp * Add / remove Watches * Add Snippets Cmponent * Semi Working Snippets * Working Snippets * Adding CodeMirror features * Removing old Console * Add Static folder
This commit is contained in:
parent
3ff72794e5
commit
84cab18120
@ -196,11 +196,13 @@
|
|||||||
"react": "15.4.2",
|
"react": "15.4.2",
|
||||||
"react-ace": "4.1.0",
|
"react-ace": "4.1.0",
|
||||||
"react-addons-css-transition-group": "15.4.2",
|
"react-addons-css-transition-group": "15.4.2",
|
||||||
|
"react-codemirror": "^0.3.0",
|
||||||
"react-copy-to-clipboard": "4.2.3",
|
"react-copy-to-clipboard": "4.2.3",
|
||||||
"react-dom": "15.4.2",
|
"react-dom": "15.4.2",
|
||||||
"react-dropzone": "3.7.3",
|
"react-dropzone": "3.7.3",
|
||||||
"react-element-to-jsx-string": "6.0.0",
|
"react-element-to-jsx-string": "6.0.0",
|
||||||
"react-event-listener": "0.4.1",
|
"react-event-listener": "0.4.1",
|
||||||
|
"react-inspector": "paritytech/react-inspector",
|
||||||
"react-intl": "2.1.5",
|
"react-intl": "2.1.5",
|
||||||
"react-markdown": "2.4.4",
|
"react-markdown": "2.4.4",
|
||||||
"react-portal": "3.0.0",
|
"react-portal": "3.0.0",
|
||||||
|
59
js/src/dapps/console.js
Normal file
59
js/src/dapps/console.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import { AppContainer } from 'react-hot-loader';
|
||||||
|
|
||||||
|
import 'codemirror/addon/dialog/dialog';
|
||||||
|
import 'codemirror/addon/dialog/dialog.css';
|
||||||
|
import 'codemirror/addon/hint/javascript-hint';
|
||||||
|
import 'codemirror/addon/hint/show-hint';
|
||||||
|
import 'codemirror/addon/hint/show-hint.css';
|
||||||
|
import 'codemirror/addon/search/match-highlighter';
|
||||||
|
import 'codemirror/addon/search/search';
|
||||||
|
import 'codemirror/addon/search/searchcursor';
|
||||||
|
import 'codemirror/keymap/sublime';
|
||||||
|
import 'codemirror/lib/codemirror.css';
|
||||||
|
import 'codemirror/mode/javascript/javascript';
|
||||||
|
// Custom codemirror style
|
||||||
|
import './console/codemirror.css';
|
||||||
|
|
||||||
|
import Application from './console/Application';
|
||||||
|
|
||||||
|
import '../../assets/fonts/Roboto/font.css';
|
||||||
|
import '../../assets/fonts/RobotoMono/font.css';
|
||||||
|
import './style.css';
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<AppContainer>
|
||||||
|
<Application />
|
||||||
|
</AppContainer>,
|
||||||
|
document.querySelector('#container')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (module.hot) {
|
||||||
|
module.hot.accept('./console/Application/index.js', () => {
|
||||||
|
require('./console/Application/index.js');
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<AppContainer>
|
||||||
|
<Application />
|
||||||
|
</AppContainer>,
|
||||||
|
document.querySelector('#container')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
65
js/src/dapps/console/Application/application.css
Normal file
65
js/src/dapps/console/Application/application.css
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
/* This file is part of Parity.
|
||||||
|
/*
|
||||||
|
/* Parity is free software: you can redistribute it and/or modify
|
||||||
|
/* it under the terms of the GNU General Public License as published by
|
||||||
|
/* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
/* (at your option) any later version.
|
||||||
|
/*
|
||||||
|
/* Parity is distributed in the hope that it will be useful,
|
||||||
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
/* GNU General Public License for more details.
|
||||||
|
/*
|
||||||
|
/* You should have received a copy of the GNU General Public License
|
||||||
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.app {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
font-size: 11px;
|
||||||
|
height: 100vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea,
|
||||||
|
input {
|
||||||
|
font-family: dejavu sans mono, monospace;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
code,
|
||||||
|
pre {
|
||||||
|
font-family: dejavu sans mono, monospace;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.eval {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
font-family: dejavu sans mono, monospace;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
display: flex;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
font-family: dejavu sans mono, monospace;
|
||||||
|
}
|
94
js/src/dapps/console/Application/application.js
Normal file
94
js/src/dapps/console/Application/application.js
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
import { api } from '../parity';
|
||||||
|
|
||||||
|
import Console from '../Console';
|
||||||
|
import Header from '../Header';
|
||||||
|
import Input from '../Input';
|
||||||
|
import Settings from '../Settings';
|
||||||
|
import Snippets from '../Snippets';
|
||||||
|
import Watches from '../Watches';
|
||||||
|
|
||||||
|
import ApplicationStore from './application.store';
|
||||||
|
import WatchesStore from '../Watches/watches.store';
|
||||||
|
|
||||||
|
import styles from './application.css';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class Application extends Component {
|
||||||
|
application = ApplicationStore.get();
|
||||||
|
watches = WatchesStore.get();
|
||||||
|
|
||||||
|
componentWillMount () {
|
||||||
|
this.watches.add('time', () => new Date());
|
||||||
|
this.watches.add('blockNumber', api.eth.blockNumber, api);
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<div className={ styles.app }>
|
||||||
|
<div className={ styles.header }>
|
||||||
|
<Header />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{ this.renderView() }
|
||||||
|
|
||||||
|
<div className={ styles.status }>
|
||||||
|
<Watches />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderView () {
|
||||||
|
const { view } = this.application;
|
||||||
|
|
||||||
|
if (view === 'console') {
|
||||||
|
return (
|
||||||
|
<div className={ styles.view }>
|
||||||
|
<div className={ styles.eval }>
|
||||||
|
<Console />
|
||||||
|
</div>
|
||||||
|
<div className={ styles.input }>
|
||||||
|
<Input />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view === 'settings') {
|
||||||
|
return (
|
||||||
|
<div className={ styles.view }>
|
||||||
|
<Settings />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view === 'snippets') {
|
||||||
|
return (
|
||||||
|
<div className={ styles.view }>
|
||||||
|
<Snippets />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
42
js/src/dapps/console/Application/application.store.js
Normal file
42
js/src/dapps/console/Application/application.store.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { action, observable } from 'mobx';
|
||||||
|
|
||||||
|
let instance;
|
||||||
|
|
||||||
|
export default class ApplicationStore {
|
||||||
|
@observable view = this.views[0].id;
|
||||||
|
|
||||||
|
views = [
|
||||||
|
{ label: 'Console', id: 'console' },
|
||||||
|
{ label: 'Snippets', id: 'snippets' },
|
||||||
|
{ label: 'Settings', id: 'settings' }
|
||||||
|
];
|
||||||
|
|
||||||
|
static get () {
|
||||||
|
if (!instance) {
|
||||||
|
instance = new ApplicationStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
setView (view) {
|
||||||
|
this.view = view;
|
||||||
|
}
|
||||||
|
}
|
17
js/src/dapps/console/Application/index.js
Normal file
17
js/src/dapps/console/Application/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
export default from './application';
|
55
js/src/dapps/console/Autocomplete/autocomplete.css
Normal file
55
js/src/dapps/console/Autocomplete/autocomplete.css
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
/* This file is part of Parity.
|
||||||
|
/*
|
||||||
|
/* Parity is free software: you can redistribute it and/or modify
|
||||||
|
/* it under the terms of the GNU General Public License as published by
|
||||||
|
/* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
/* (at your option) any later version.
|
||||||
|
/*
|
||||||
|
/* Parity is distributed in the hope that it will be useful,
|
||||||
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
/* GNU General Public License for more details.
|
||||||
|
/*
|
||||||
|
/* You should have received a copy of the GNU General Public License
|
||||||
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.container {
|
||||||
|
background: #f8f8f8;
|
||||||
|
box-shadow: 0 0.125em 0.25em rgba(0, 0, 0, 0.5);
|
||||||
|
font-family: dejavu sans mono, monospace;
|
||||||
|
left: 20px;
|
||||||
|
position: absolute;
|
||||||
|
max-height: 300px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
background-color: white;
|
||||||
|
padding: 0.25em 0.25em 0.25em 0.35em;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
background-color: rgb(64, 115, 244);
|
||||||
|
|
||||||
|
&,
|
||||||
|
.proto {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover:not(.selected) {
|
||||||
|
background-color: rgb(230, 236, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
.proto {
|
||||||
|
color: gray;
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
}
|
96
js/src/dapps/console/Autocomplete/autocomplete.js
Normal file
96
js/src/dapps/console/Autocomplete/autocomplete.js
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
|
||||||
|
import AutocompleteStore from './autocomplete.store';
|
||||||
|
|
||||||
|
import styles from './autocomplete.css';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class Autocomplete extends Component {
|
||||||
|
autocompleteStore = AutocompleteStore.get();
|
||||||
|
|
||||||
|
render () {
|
||||||
|
if (!this.autocompleteStore.show) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={ styles.container }
|
||||||
|
style={ this.autocompleteStore.position }
|
||||||
|
>
|
||||||
|
{ this.renderAutocompletes() }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAutocompletes () {
|
||||||
|
const { selected, values } = this.autocompleteStore;
|
||||||
|
const displayedProto = {};
|
||||||
|
|
||||||
|
return values.map((autocomplete, index) => {
|
||||||
|
const { name, prototypeName } = autocomplete;
|
||||||
|
const onClick = () => this.handleClick(index);
|
||||||
|
const setRef = (node) => this.setRef(index, node);
|
||||||
|
|
||||||
|
const proto = !displayedProto[prototypeName]
|
||||||
|
? (
|
||||||
|
<span className={ styles.proto }>
|
||||||
|
{ prototypeName }
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (!displayedProto[prototypeName]) {
|
||||||
|
displayedProto[prototypeName] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const classes = [ styles.item ];
|
||||||
|
|
||||||
|
if (index === selected) {
|
||||||
|
classes.push(styles.selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={ classes.join(' ') }
|
||||||
|
key={ index }
|
||||||
|
onClick={ onClick }
|
||||||
|
ref={ setRef }
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
{ name }
|
||||||
|
</span>
|
||||||
|
{ proto }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClick = (index) => {
|
||||||
|
this.autocompleteStore.select(index);
|
||||||
|
};
|
||||||
|
|
||||||
|
setRef = (index, node) => {
|
||||||
|
const element = ReactDOM.findDOMNode(node);
|
||||||
|
|
||||||
|
this.autocompleteStore.setElement(index, element);
|
||||||
|
};
|
||||||
|
}
|
234
js/src/dapps/console/Autocomplete/autocomplete.store.js
Normal file
234
js/src/dapps/console/Autocomplete/autocomplete.store.js
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { action, observable } from 'mobx';
|
||||||
|
|
||||||
|
import { evaluate } from '../utils';
|
||||||
|
|
||||||
|
let instance;
|
||||||
|
|
||||||
|
export default class AutocompleteStore {
|
||||||
|
@observable values = [];
|
||||||
|
@observable position = {};
|
||||||
|
@observable show = false;
|
||||||
|
@observable selected = null;
|
||||||
|
|
||||||
|
elements = {};
|
||||||
|
inputNode = null;
|
||||||
|
lastObject = null;
|
||||||
|
lastObjectPropertyNames = [];
|
||||||
|
|
||||||
|
static get () {
|
||||||
|
if (!instance) {
|
||||||
|
instance = new AutocompleteStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasSelected () {
|
||||||
|
return this.selected !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCache () {
|
||||||
|
this.lastObject = null;
|
||||||
|
this.lastObjectPropertyNames = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
focus (offset = 1) {
|
||||||
|
if (this.values.length === 0) {
|
||||||
|
this.selected = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selected = this.selected === null
|
||||||
|
? (
|
||||||
|
offset === 1
|
||||||
|
? 0
|
||||||
|
: this.values.length - 1
|
||||||
|
)
|
||||||
|
: (this.values.length + this.selected + offset) % (this.values.length);
|
||||||
|
|
||||||
|
if (this.isVisible(this.selected)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const element = this.elements[this.selected];
|
||||||
|
|
||||||
|
if (!element) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
element.scrollIntoView(offset === -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
focusOnInput () {
|
||||||
|
if (!this.inputNode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.inputNode.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
hide () {
|
||||||
|
this.show = false;
|
||||||
|
this.selected = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
isVisible (index) {
|
||||||
|
const element = this.elements[index];
|
||||||
|
|
||||||
|
if (!element) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const eBoundings = element.getBoundingClientRect();
|
||||||
|
const pBoundings = element.parentElement.getBoundingClientRect();
|
||||||
|
|
||||||
|
if (eBoundings.top < pBoundings.top || eBoundings.bottom > pBoundings.bottom) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
select (inputStore, _index = this.selected) {
|
||||||
|
const index = _index === null
|
||||||
|
? 0
|
||||||
|
: _index;
|
||||||
|
|
||||||
|
if (!this.values[index]) {
|
||||||
|
console.warn(`autocomplete::select has been called on AutocompleteStore with wrong value ${index}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { name } = this.values[index];
|
||||||
|
const { input } = inputStore;
|
||||||
|
const objects = input.split('.');
|
||||||
|
|
||||||
|
objects[objects.length - 1] = name;
|
||||||
|
const nextInput = objects.join('.');
|
||||||
|
|
||||||
|
this.hide();
|
||||||
|
this.focusOnInput();
|
||||||
|
return inputStore.updateInput(nextInput, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
setElement (index, element) {
|
||||||
|
this.elements[index] = element;
|
||||||
|
}
|
||||||
|
|
||||||
|
setInputNode (node) {
|
||||||
|
this.inputNode = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
setPosition () {
|
||||||
|
if (!this.inputNode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputBoundings = this.inputNode.getBoundingClientRect();
|
||||||
|
const bodyBoundings = document.body.getBoundingClientRect();
|
||||||
|
|
||||||
|
// display on bottom of input
|
||||||
|
if (inputBoundings.top < bodyBoundings.height / 2) {
|
||||||
|
const nextPosition = {
|
||||||
|
top: 20
|
||||||
|
};
|
||||||
|
|
||||||
|
this.position = nextPosition;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// display on top of input
|
||||||
|
const nextPosition = {
|
||||||
|
bottom: inputBoundings.height
|
||||||
|
};
|
||||||
|
|
||||||
|
this.position = nextPosition;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
setValues (values) {
|
||||||
|
this.values = values;
|
||||||
|
this.selected = null;
|
||||||
|
const show = values.length > 0;
|
||||||
|
|
||||||
|
// Reveal autocomplete
|
||||||
|
if (!this.show && show) {
|
||||||
|
this.setPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.show = show;
|
||||||
|
}
|
||||||
|
|
||||||
|
update (input) {
|
||||||
|
if (input.length === 0) {
|
||||||
|
return this.setValues([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const objects = input.split('.');
|
||||||
|
const suffix = objects.pop().toLowerCase();
|
||||||
|
const prefix = objects.join('.');
|
||||||
|
const object = prefix.length > 0
|
||||||
|
? prefix
|
||||||
|
: 'window';
|
||||||
|
|
||||||
|
if (object !== this.lastObject) {
|
||||||
|
const evalResult = evaluate(object);
|
||||||
|
|
||||||
|
if (evalResult.error) {
|
||||||
|
this.lastObjectProperties = [];
|
||||||
|
} else {
|
||||||
|
this.lastObjectProperties = getAllProperties(evalResult.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastObject = object;
|
||||||
|
}
|
||||||
|
|
||||||
|
const autocompletes = this.lastObjectProperties.filter((property) => {
|
||||||
|
return property.name.toLowerCase().includes(suffix);
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.setValues(autocompletes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAllProperties (object) {
|
||||||
|
const propertyNames = {};
|
||||||
|
|
||||||
|
while (object) {
|
||||||
|
const prototypeName = object && object.constructor && object.constructor.name || '';
|
||||||
|
|
||||||
|
Object.getOwnPropertyNames(object)
|
||||||
|
.sort()
|
||||||
|
.forEach((name) => {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(propertyNames, name)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
propertyNames[name] = { name, prototypeName };
|
||||||
|
});
|
||||||
|
|
||||||
|
object = Object.getPrototypeOf(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.values(propertyNames);
|
||||||
|
}
|
17
js/src/dapps/console/Autocomplete/index.js
Normal file
17
js/src/dapps/console/Autocomplete/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
export default from './autocomplete';
|
58
js/src/dapps/console/Console/console.css
Normal file
58
js/src/dapps/console/Console/console.css
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
/* This file is part of Parity.
|
||||||
|
/*
|
||||||
|
/* Parity is free software: you can redistribute it and/or modify
|
||||||
|
/* it under the terms of the GNU General Public License as published by
|
||||||
|
/* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
/* (at your option) any later version.
|
||||||
|
/*
|
||||||
|
/* Parity is distributed in the hope that it will be useful,
|
||||||
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
/* GNU General Public License for more details.
|
||||||
|
/*
|
||||||
|
/* You should have received a copy of the GNU General Public License
|
||||||
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.result {
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
display: flex;
|
||||||
|
font-family: dejavu sans mono, monospace;
|
||||||
|
padding: 0.35em 0.25em;
|
||||||
|
|
||||||
|
&.error {
|
||||||
|
background-color: hsl(0, 100%, 97%);
|
||||||
|
|
||||||
|
.text {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.warn {
|
||||||
|
background-color: hsl(50, 100%, 95%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.type {
|
||||||
|
font-weight: bold !important;
|
||||||
|
font-size: 8pt;
|
||||||
|
padding: 0 0.5em 0 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time {
|
||||||
|
color: gray;
|
||||||
|
padding: 0 1em 0 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.token {
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text .token:not(:first-child) {
|
||||||
|
margin-left: 0.5em;
|
||||||
|
}
|
118
js/src/dapps/console/Console/console.js
Normal file
118
js/src/dapps/console/Console/console.js
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import { ObjectInspector } from 'react-inspector';
|
||||||
|
|
||||||
|
import ConsoleStore from './console.store';
|
||||||
|
import SettingsStore from '../Settings/settings.store';
|
||||||
|
|
||||||
|
import styles from './console.css';
|
||||||
|
|
||||||
|
const ICONS = {
|
||||||
|
debug: ' ',
|
||||||
|
error: '✖',
|
||||||
|
info: 'ℹ',
|
||||||
|
input: '>',
|
||||||
|
log: ' ',
|
||||||
|
result: '<',
|
||||||
|
warn: '⚠'
|
||||||
|
};
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class Console extends Component {
|
||||||
|
consoleStore = ConsoleStore.get();
|
||||||
|
settingsStore = SettingsStore.get();
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<div ref={ this.setRef }>
|
||||||
|
{ this.renderResults() }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderResults () {
|
||||||
|
const { logs } = this.consoleStore;
|
||||||
|
|
||||||
|
return logs.map((data, index) => {
|
||||||
|
const { type, timestamp } = data;
|
||||||
|
const values = this.consoleStore.logValues[index];
|
||||||
|
const classes = [ styles.result, styles[type] ];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={ classes.join(' ') }
|
||||||
|
key={ index }
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={ styles.type }
|
||||||
|
dangerouslySetInnerHTML={ { __html: ICONS[type] || '' } }
|
||||||
|
/>
|
||||||
|
{ this.renderTimestamp(timestamp) }
|
||||||
|
<span className={ styles.text }>
|
||||||
|
{
|
||||||
|
values.map((value, valueIndex) => (
|
||||||
|
<span
|
||||||
|
className={ styles.token }
|
||||||
|
key={ valueIndex }
|
||||||
|
>
|
||||||
|
{ this.toString(value) }
|
||||||
|
</span>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTimestamp (timestamp) {
|
||||||
|
const { displayTimestamps } = this.settingsStore;
|
||||||
|
|
||||||
|
if (!displayTimestamps) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className={ styles.time }>
|
||||||
|
{ new Date(timestamp).toISOString().slice(11, 23) }
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
setRef = (node) => {
|
||||||
|
const element = ReactDOM.findDOMNode(node);
|
||||||
|
|
||||||
|
this.consoleStore.setNode(element);
|
||||||
|
};
|
||||||
|
|
||||||
|
toString (value) {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value instanceof Error) {
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ObjectInspector data={ value } />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
126
js/src/dapps/console/Console/console.store.js
Normal file
126
js/src/dapps/console/Console/console.store.js
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { action, observable } from 'mobx';
|
||||||
|
|
||||||
|
import AutocompleteStore from '../Autocomplete/autocomplete.store';
|
||||||
|
import { evaluate } from '../utils';
|
||||||
|
|
||||||
|
let instance;
|
||||||
|
|
||||||
|
export default class ConsoleStore {
|
||||||
|
@observable logs = [];
|
||||||
|
|
||||||
|
autocompleteStore = AutocompleteStore.get();
|
||||||
|
logValues = [];
|
||||||
|
node = null;
|
||||||
|
|
||||||
|
constructor () {
|
||||||
|
this.attachConsole();
|
||||||
|
}
|
||||||
|
|
||||||
|
static get () {
|
||||||
|
if (!instance) {
|
||||||
|
instance = new ConsoleStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
attachConsole () {
|
||||||
|
['debug', 'error', 'info', 'log', 'warn'].forEach((level) => {
|
||||||
|
const old = window.console[level].bind(window.console);
|
||||||
|
|
||||||
|
window.console[level] = (...args) => {
|
||||||
|
old(...args);
|
||||||
|
this.log({ type: level, values: args });
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
clear () {
|
||||||
|
this.logs = [];
|
||||||
|
this.logValues = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
evaluate (input) {
|
||||||
|
this.log({ type: 'input', value: input });
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
const { result, error } = evaluate(input);
|
||||||
|
let value = error || result;
|
||||||
|
const type = error
|
||||||
|
? 'error'
|
||||||
|
: 'result';
|
||||||
|
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
value = `"${value}"`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value && typeof value === 'object' && typeof value.then === 'function') {
|
||||||
|
return value
|
||||||
|
.then((result) => {
|
||||||
|
this.log({ type: 'result', value: result });
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.log({ type: 'error', value: error });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.log({ type, value });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
log ({ type, value, values }) {
|
||||||
|
this.logs.push({
|
||||||
|
type,
|
||||||
|
timestamp: Date.now()
|
||||||
|
});
|
||||||
|
|
||||||
|
if (values) {
|
||||||
|
this.logValues.push(values);
|
||||||
|
} else {
|
||||||
|
this.logValues.push([ value ]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.autocompleteStore.setPosition();
|
||||||
|
this.scroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
setNode (node) {
|
||||||
|
this.node = node;
|
||||||
|
this.scroll();
|
||||||
|
}
|
||||||
|
|
||||||
|
scroll () {
|
||||||
|
if (!this.node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (this.node.children.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scroll to the last child
|
||||||
|
this.node
|
||||||
|
.children[this.node.children.length - 1]
|
||||||
|
.scrollIntoView(false);
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
}
|
17
js/src/dapps/console/Console/index.js
Normal file
17
js/src/dapps/console/Console/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
export default from './console';
|
51
js/src/dapps/console/Header/header.css
Normal file
51
js/src/dapps/console/Header/header.css
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
/* This file is part of Parity.
|
||||||
|
/*
|
||||||
|
/* Parity is free software: you can redistribute it and/or modify
|
||||||
|
/* it under the terms of the GNU General Public License as published by
|
||||||
|
/* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
/* (at your option) any later version.
|
||||||
|
/*
|
||||||
|
/* Parity is distributed in the hope that it will be useful,
|
||||||
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
/* GNU General Public License for more details.
|
||||||
|
/*
|
||||||
|
/* You should have received a copy of the GNU General Public License
|
||||||
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.container {
|
||||||
|
background-color: #f3f3f3;
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 0 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabs {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab {
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
color: #333;
|
||||||
|
cursor: default;
|
||||||
|
display: flex;
|
||||||
|
height: 24px;
|
||||||
|
line-height: 15px;
|
||||||
|
margin-top: 2px;
|
||||||
|
padding: 2px 6px 2px 4px;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&.active:hover {
|
||||||
|
background-color: #e5e5e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: white;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
65
js/src/dapps/console/Header/header.js
Normal file
65
js/src/dapps/console/Header/header.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
import ApplicationStore from '../Application/application.store';
|
||||||
|
|
||||||
|
import styles from './header.css';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class Header extends Component {
|
||||||
|
application = ApplicationStore.get();
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<div className={ styles.container }>
|
||||||
|
<div className={ styles.tabs }>
|
||||||
|
{ this.renderTabs() }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTabs () {
|
||||||
|
const { view } = this.application;
|
||||||
|
|
||||||
|
return this.application.views.map((tab) => {
|
||||||
|
const { label, id } = tab;
|
||||||
|
const classes = [ styles.tab ];
|
||||||
|
const onClick = () => this.handleClickTab(id);
|
||||||
|
|
||||||
|
if (id === view) {
|
||||||
|
classes.push(styles.active);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={ classes.join(' ') }
|
||||||
|
key={ id }
|
||||||
|
onClick={ onClick }
|
||||||
|
>
|
||||||
|
{ label }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClickTab = (id) => {
|
||||||
|
this.application.setView(id);
|
||||||
|
};
|
||||||
|
}
|
17
js/src/dapps/console/Header/index.js
Normal file
17
js/src/dapps/console/Header/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
export default from './header';
|
17
js/src/dapps/console/Input/index.js
Normal file
17
js/src/dapps/console/Input/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
export default from './input';
|
46
js/src/dapps/console/Input/input.css
Normal file
46
js/src/dapps/console/Input/input.css
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
/* This file is part of Parity.
|
||||||
|
/*
|
||||||
|
/* Parity is free software: you can redistribute it and/or modify
|
||||||
|
/* it under the terms of the GNU General Public License as published by
|
||||||
|
/* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
/* (at your option) any later version.
|
||||||
|
/*
|
||||||
|
/* Parity is distributed in the hope that it will be useful,
|
||||||
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
/* GNU General Public License for more details.
|
||||||
|
/*
|
||||||
|
/* You should have received a copy of the GNU General Public License
|
||||||
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.type {
|
||||||
|
color: #59f;
|
||||||
|
font-weight: bold !important;
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 0 0.5em 0 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputContainer {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
border: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
color: black;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 11px;
|
||||||
|
resize: none;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
border-top: 1px solid lightgray;
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
padding: 0.25em;
|
||||||
|
position: relative;
|
||||||
|
}
|
145
js/src/dapps/console/Input/input.js
Normal file
145
js/src/dapps/console/Input/input.js
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import keycode from 'keycode';
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
|
||||||
|
import Autocomplete from '../Autocomplete';
|
||||||
|
|
||||||
|
import AutocompleteStore from '../Autocomplete/autocomplete.store';
|
||||||
|
import ConsoleStore from '../Console/console.store';
|
||||||
|
import InputStore from './input.store';
|
||||||
|
import SettingsStore from '../Settings/settings.store';
|
||||||
|
|
||||||
|
import styles from './input.css';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class Input extends Component {
|
||||||
|
autocompleteStore = AutocompleteStore.get();
|
||||||
|
consoleStore = ConsoleStore.get();
|
||||||
|
inputStore = InputStore.get();
|
||||||
|
settingsStore = SettingsStore.get();
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { input } = this.inputStore;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.container }>
|
||||||
|
<Autocomplete />
|
||||||
|
<span className={ styles.type }>></span>
|
||||||
|
<div className={ styles.inputContainer }>
|
||||||
|
<textarea
|
||||||
|
autoFocus
|
||||||
|
className={ styles.input }
|
||||||
|
onChange={ this.handleChange }
|
||||||
|
onKeyDown={ this.handleKeyDown }
|
||||||
|
ref={ this.setRef }
|
||||||
|
rows={ input.split('\n').length }
|
||||||
|
type='text'
|
||||||
|
value={ input }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleChange = (event) => {
|
||||||
|
const { value } = event.target;
|
||||||
|
|
||||||
|
this.inputStore.updateInput(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleKeyDown = (event) => {
|
||||||
|
const { executeOnEnter } = this.settingsStore;
|
||||||
|
const { input } = this.inputStore;
|
||||||
|
const codeName = keycode(event);
|
||||||
|
const multilines = input.split('\n').length > 1;
|
||||||
|
|
||||||
|
// Clear console with CTRL+L
|
||||||
|
if (codeName === 'l' && event.ctrlKey) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
return this.consoleStore.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (codeName === 'esc') {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
return this.autocompleteStore.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (codeName === 'enter') {
|
||||||
|
if (event.shiftKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not execute on enter: execute on
|
||||||
|
// enter + CTRL
|
||||||
|
if (!executeOnEnter && !event.ctrlKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
if (this.autocompleteStore.hasSelected) {
|
||||||
|
return this.autocompleteStore.select(this.inputStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.length > 0) {
|
||||||
|
return this.inputStore.execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (codeName === 'up' && !multilines) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
if (this.autocompleteStore.show) {
|
||||||
|
return this.autocompleteStore.focus(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.inputStore.selectHistory(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (codeName === 'down' && !multilines) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
if (this.autocompleteStore.show) {
|
||||||
|
return this.autocompleteStore.focus(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.inputStore.selectHistory(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (codeName === 'left' && this.autocompleteStore.show) {
|
||||||
|
return this.autocompleteStore.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (codeName === 'right' && this.autocompleteStore.show) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
return this.autocompleteStore.select(this.inputStore);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
setRef = (node) => {
|
||||||
|
this.inputStore.setInputNode(ReactDOM.findDOMNode(node));
|
||||||
|
};
|
||||||
|
}
|
124
js/src/dapps/console/Input/input.store.js
Normal file
124
js/src/dapps/console/Input/input.store.js
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { action, observable } from 'mobx';
|
||||||
|
import store from 'store';
|
||||||
|
|
||||||
|
import AutocompleteStore from '../Autocomplete/autocomplete.store';
|
||||||
|
import ConsoleStore from '../Console/console.store';
|
||||||
|
|
||||||
|
const LS_HISTORY_KEY = '_console::history';
|
||||||
|
const MAX_HISTORY_LINES = 5;
|
||||||
|
|
||||||
|
let instance;
|
||||||
|
|
||||||
|
export default class InputStore {
|
||||||
|
@observable input = '';
|
||||||
|
|
||||||
|
autocompleteStore = AutocompleteStore.get();
|
||||||
|
consoleStore = ConsoleStore.get();
|
||||||
|
history = [];
|
||||||
|
historyOffset = null;
|
||||||
|
inputNode = null;
|
||||||
|
lastInput = '';
|
||||||
|
|
||||||
|
constructor () {
|
||||||
|
this.loadHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
static get () {
|
||||||
|
if (!instance) {
|
||||||
|
instance = new InputStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
setInputNode (node) {
|
||||||
|
this.inputNode = node;
|
||||||
|
this.autocompleteStore.setInputNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
updateInput (nextValue = '', updateAutocomplete = true) {
|
||||||
|
this.input = nextValue;
|
||||||
|
const multilines = nextValue.split('\n').length > 1;
|
||||||
|
|
||||||
|
if (updateAutocomplete && !multilines) {
|
||||||
|
this.autocompleteStore.update(nextValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
selectHistory (_offset) {
|
||||||
|
// No history
|
||||||
|
if (this.history.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.historyOffset === null) {
|
||||||
|
// Can't go down if no history selected
|
||||||
|
if (_offset === 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.historyOffset = this.history.length - 1;
|
||||||
|
this.lastInput = this.input;
|
||||||
|
return this.updateInput(this.history[this.historyOffset], false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_offset === 1 && this.historyOffset === this.history.length - 1) {
|
||||||
|
this.historyOffset = null;
|
||||||
|
return this.updateInput(this.lastInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.historyOffset = Math.max(0, this.historyOffset + _offset);
|
||||||
|
const nextInput = this.history[this.historyOffset];
|
||||||
|
|
||||||
|
this.updateInput(nextInput, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
execute () {
|
||||||
|
const { input } = this;
|
||||||
|
|
||||||
|
this.pushToHistory(input);
|
||||||
|
this.consoleStore.evaluate(input);
|
||||||
|
this.updateInput('');
|
||||||
|
this.historyOffset = null;
|
||||||
|
this.autocompleteStore.clearCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
pushToHistory (input) {
|
||||||
|
// Don't stack twice the same input in
|
||||||
|
// history
|
||||||
|
if (this.history[this.history.length - 1] !== input) {
|
||||||
|
this.history.push(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.saveHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadHistory () {
|
||||||
|
this.history = store.get(LS_HISTORY_KEY) || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
saveHistory () {
|
||||||
|
if (this.history.length > MAX_HISTORY_LINES) {
|
||||||
|
this.history = this.history.slice(-1 * MAX_HISTORY_LINES);
|
||||||
|
}
|
||||||
|
|
||||||
|
store.set(LS_HISTORY_KEY, this.history.slice());
|
||||||
|
}
|
||||||
|
}
|
17
js/src/dapps/console/Settings/index.js
Normal file
17
js/src/dapps/console/Settings/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
export default from './settings';
|
32
js/src/dapps/console/Settings/settings.css
Normal file
32
js/src/dapps/console/Settings/settings.css
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
/* This file is part of Parity.
|
||||||
|
/*
|
||||||
|
/* Parity is free software: you can redistribute it and/or modify
|
||||||
|
/* it under the terms of the GNU General Public License as published by
|
||||||
|
/* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
/* (at your option) any later version.
|
||||||
|
/*
|
||||||
|
/* Parity is distributed in the hope that it will be useful,
|
||||||
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
/* GNU General Public License for more details.
|
||||||
|
/*
|
||||||
|
/* You should have received a copy of the GNU General Public License
|
||||||
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex: 0 0 50%;
|
||||||
|
flex-direction: row;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
}
|
70
js/src/dapps/console/Settings/settings.js
Normal file
70
js/src/dapps/console/Settings/settings.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
import SettingsStore from './settings.store';
|
||||||
|
|
||||||
|
import styles from './settings.css';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class Settings extends Component {
|
||||||
|
settingsStore = SettingsStore.get();
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { displayTimestamps, executeOnEnter } = this.settingsStore;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.container }>
|
||||||
|
<div className={ styles.option }>
|
||||||
|
<input
|
||||||
|
checked={ executeOnEnter }
|
||||||
|
id='executeOnEnter'
|
||||||
|
onChange={ this.handleExecuteOnEnterChange }
|
||||||
|
type='checkbox'
|
||||||
|
/>
|
||||||
|
<label htmlFor='executeOnEnter'>
|
||||||
|
Execute on <code>Enter</code>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className={ styles.option }>
|
||||||
|
<input
|
||||||
|
checked={ displayTimestamps }
|
||||||
|
id='displayTimestamps'
|
||||||
|
onChange={ this.handleDisplayTimestampsChange }
|
||||||
|
type='checkbox'
|
||||||
|
/>
|
||||||
|
<label htmlFor='displayTimestamps'>
|
||||||
|
Show timestamps
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDisplayTimestampsChange = (event) => {
|
||||||
|
const { checked } = event.target;
|
||||||
|
|
||||||
|
this.settingsStore.setDisplayTimestamps(checked);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleExecuteOnEnterChange = (event) => {
|
||||||
|
const { checked } = event.target;
|
||||||
|
|
||||||
|
this.settingsStore.setExecuteOnEnter(checked);
|
||||||
|
};
|
||||||
|
}
|
71
js/src/dapps/console/Settings/settings.store.js
Normal file
71
js/src/dapps/console/Settings/settings.store.js
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { action, observable } from 'mobx';
|
||||||
|
import store from 'store';
|
||||||
|
|
||||||
|
const LS_SETTINGS_KEY = '_console::settings';
|
||||||
|
|
||||||
|
let instance;
|
||||||
|
|
||||||
|
export default class SettingsStore {
|
||||||
|
@observable displayTimestamps = true;
|
||||||
|
@observable executeOnEnter = true;
|
||||||
|
|
||||||
|
constructor () {
|
||||||
|
this.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
static get () {
|
||||||
|
if (!instance) {
|
||||||
|
instance = new SettingsStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
load () {
|
||||||
|
const settings = store.get(LS_SETTINGS_KEY) || {};
|
||||||
|
const { executeOnEnter, displayTimestamps } = settings;
|
||||||
|
|
||||||
|
if (executeOnEnter !== undefined) {
|
||||||
|
this.setExecuteOnEnter(executeOnEnter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (displayTimestamps !== undefined) {
|
||||||
|
this.setDisplayTimestamps(displayTimestamps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
save () {
|
||||||
|
const { executeOnEnter, displayTimestamps } = this;
|
||||||
|
const settings = { executeOnEnter, displayTimestamps };
|
||||||
|
|
||||||
|
store.set(LS_SETTINGS_KEY, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
setDisplayTimestamps (value) {
|
||||||
|
this.displayTimestamps = value;
|
||||||
|
this.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
setExecuteOnEnter (value) {
|
||||||
|
this.executeOnEnter = value;
|
||||||
|
this.save();
|
||||||
|
}
|
||||||
|
}
|
17
js/src/dapps/console/Snippets/index.js
Normal file
17
js/src/dapps/console/Snippets/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
export default from './snippets';
|
122
js/src/dapps/console/Snippets/snippets.css
Normal file
122
js/src/dapps/console/Snippets/snippets.css
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
/* This file is part of Parity.
|
||||||
|
/*
|
||||||
|
/* Parity is free software: you can redistribute it and/or modify
|
||||||
|
/* it under the terms of the GNU General Public License as published by
|
||||||
|
/* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
/* (at your option) any later version.
|
||||||
|
/*
|
||||||
|
/* Parity is distributed in the hope that it will be useful,
|
||||||
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
/* GNU General Public License for more details.
|
||||||
|
/*
|
||||||
|
/* You should have received a copy of the GNU General Public License
|
||||||
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
border-right: 1px solid lightgray;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add {
|
||||||
|
align-items: center;
|
||||||
|
background-color: #fcfcfc;
|
||||||
|
border-bottom: 1px solid lightgray;
|
||||||
|
cursor: default;
|
||||||
|
display: flex;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
|
||||||
|
.plus {
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold !important;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.list {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.console {
|
||||||
|
border-top: 1px solid lightgray;
|
||||||
|
max-height: 200px;
|
||||||
|
flex: 0 0 0;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
overflow: auto;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> * {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.CodeMirror) {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.file {
|
||||||
|
align-items: center;
|
||||||
|
cursor: default;
|
||||||
|
display: flex;
|
||||||
|
padding: 0.5em 0.5em 0.5em 1em;
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgb(230, 236, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pristine {
|
||||||
|
font-size: 20px;
|
||||||
|
margin-right: 3px;
|
||||||
|
height: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove {
|
||||||
|
cursor: default;
|
||||||
|
display: inline-flex;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-left: -0.25em;
|
||||||
|
margin-right: 0.25em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputContainer {
|
||||||
|
background-color: white;
|
||||||
|
border: solid 1px #d8d8d8;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
padding: 3px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
border: none;
|
||||||
|
font: 11px Arial;
|
||||||
|
width: 100%;
|
||||||
|
}
|
221
js/src/dapps/console/Snippets/snippets.js
Normal file
221
js/src/dapps/console/Snippets/snippets.js
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import keycode from 'keycode';
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import CodeMirror from 'react-codemirror';
|
||||||
|
import EventListener from 'react-event-listener';
|
||||||
|
|
||||||
|
import Console from '../Console';
|
||||||
|
import SnippetsStore from './snippets.store';
|
||||||
|
|
||||||
|
import styles from './snippets.css';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class Snippets extends Component {
|
||||||
|
snippetsStore = SnippetsStore.get();
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { code } = this.snippetsStore;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.container }>
|
||||||
|
<EventListener
|
||||||
|
onKeyDown={ this.handleKeyDown }
|
||||||
|
target='window'
|
||||||
|
/>
|
||||||
|
<div className={ styles.panel }>
|
||||||
|
<div
|
||||||
|
className={ styles.add }
|
||||||
|
onClick={ this.handleAddFile }
|
||||||
|
>
|
||||||
|
<span className={ styles.plus }>+</span>
|
||||||
|
<span>New Snippet</span>
|
||||||
|
</div>
|
||||||
|
<div className={ styles.list }>
|
||||||
|
{ this.renderFiles() }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={ styles.code }>
|
||||||
|
<CodeMirror
|
||||||
|
ref={ this.setRef }
|
||||||
|
onChange={ this.handleChange }
|
||||||
|
options={ {
|
||||||
|
autofocus: true,
|
||||||
|
extraKeys: {
|
||||||
|
'Ctrl-Space': 'autocomplete'
|
||||||
|
},
|
||||||
|
keyMap: 'sublime',
|
||||||
|
highlightSelectionMatches: {
|
||||||
|
delay: 0,
|
||||||
|
showToken: false
|
||||||
|
},
|
||||||
|
lineNumbers: true,
|
||||||
|
mode: 'javascript'
|
||||||
|
} }
|
||||||
|
value={ code }
|
||||||
|
/>
|
||||||
|
<div className={ styles.console }>
|
||||||
|
<Console />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderFiles () {
|
||||||
|
const { files } = this.snippetsStore;
|
||||||
|
|
||||||
|
return files
|
||||||
|
.values()
|
||||||
|
.sort((fa, fb) => fa.name.localeCompare(fb.name))
|
||||||
|
.map((file) => this.renderFile(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
renderFile (file) {
|
||||||
|
const { nextName, renaming, selected } = this.snippetsStore;
|
||||||
|
const { id, name } = file;
|
||||||
|
const classes = [ styles.file ];
|
||||||
|
|
||||||
|
if (renaming === id) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={ classes.join(' ') }
|
||||||
|
key={ id }
|
||||||
|
>
|
||||||
|
<EventListener
|
||||||
|
onClick={ this.handleSaveName }
|
||||||
|
target='window'
|
||||||
|
/>
|
||||||
|
<div className={ styles.inputContainer }>
|
||||||
|
<input
|
||||||
|
autoFocus
|
||||||
|
className={ styles.input }
|
||||||
|
onClick={ this.stopPropagation }
|
||||||
|
onChange={ this.handleNameChange }
|
||||||
|
onKeyDown={ this.handleRenameKeyDown }
|
||||||
|
type='text'
|
||||||
|
value={ nextName }
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClick = () => this.handleSelectFile(id);
|
||||||
|
const onDoubleClick = () => this.handleRenameFile(id);
|
||||||
|
const onRemove = (event) => this.handleRemove(id, event);
|
||||||
|
|
||||||
|
if (selected === id) {
|
||||||
|
classes.push(styles.selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={ classes.join(' ') }
|
||||||
|
key={ id }
|
||||||
|
onClick={ onClick }
|
||||||
|
onDoubleClick={ onDoubleClick }
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={ styles.remove }
|
||||||
|
onClick={ onRemove }
|
||||||
|
title={ `Remove ${name}` }
|
||||||
|
>
|
||||||
|
✖
|
||||||
|
</span>
|
||||||
|
<span className={ styles.pristine }>
|
||||||
|
{
|
||||||
|
file.isPristine
|
||||||
|
? null
|
||||||
|
: '*'
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
{ name }
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleAddFile = () => {
|
||||||
|
this.snippetsStore.create();
|
||||||
|
};
|
||||||
|
|
||||||
|
handleSaveName = (event) => {
|
||||||
|
this.snippetsStore.saveName();
|
||||||
|
return event;
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChange = (value) => {
|
||||||
|
this.snippetsStore.edit(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleKeyDown = (event) => {
|
||||||
|
const codeName = keycode(event);
|
||||||
|
|
||||||
|
if (codeName === 's' && event.ctrlKey) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
return this.snippetsStore.save();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleNameChange = (event) => {
|
||||||
|
const { value } = event.target;
|
||||||
|
|
||||||
|
this.snippetsStore.updateName(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleRemove = (id, event) => {
|
||||||
|
this.snippetsStore.remove(id);
|
||||||
|
event.stopPropagation();
|
||||||
|
};
|
||||||
|
|
||||||
|
handleRenameFile = (id) => {
|
||||||
|
this.snippetsStore.startRename(id);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleRenameKeyDown = (event) => {
|
||||||
|
const codeName = keycode(event);
|
||||||
|
|
||||||
|
if (codeName === 'enter') {
|
||||||
|
return this.snippetsStore.saveName();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (codeName === 'esc') {
|
||||||
|
return this.snippetsStore.cancelRename();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
handleSelectFile = (id) => {
|
||||||
|
this.snippetsStore.select(id);
|
||||||
|
};
|
||||||
|
|
||||||
|
setRef = (node) => {
|
||||||
|
const codeMirror = node
|
||||||
|
? node.getCodeMirror()
|
||||||
|
: null;
|
||||||
|
|
||||||
|
this.snippetsStore.setCodeMirror(codeMirror);
|
||||||
|
};
|
||||||
|
|
||||||
|
stopPropagation = (event) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
};
|
||||||
|
}
|
249
js/src/dapps/console/Snippets/snippets.store.js
Normal file
249
js/src/dapps/console/Snippets/snippets.store.js
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import keycode from 'keycode';
|
||||||
|
import { action, computed, map, observable, transaction } from 'mobx';
|
||||||
|
import store from 'store';
|
||||||
|
|
||||||
|
import { evaluate } from '../utils';
|
||||||
|
|
||||||
|
const LS_SNIPPETS_KEY = '_console::snippets';
|
||||||
|
|
||||||
|
let instance;
|
||||||
|
|
||||||
|
export default class SnippetsStore {
|
||||||
|
@observable files = map();
|
||||||
|
@observable nextName = null;
|
||||||
|
@observable renaming = null;
|
||||||
|
@observable selected = null;
|
||||||
|
|
||||||
|
codeMirror = null;
|
||||||
|
|
||||||
|
constructor () {
|
||||||
|
this.load();
|
||||||
|
}
|
||||||
|
|
||||||
|
static get () {
|
||||||
|
if (!instance) {
|
||||||
|
instance = new SnippetsStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@computed
|
||||||
|
get code () {
|
||||||
|
if (!this.selected) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.files.get(this.selected).content;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
cancelRename () {
|
||||||
|
if (!this.renaming || !this.nextName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.renaming = null;
|
||||||
|
this.nextName = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCodeHistory () {
|
||||||
|
if (this.codeMirror) {
|
||||||
|
this.codeMirror.doc.clearHistory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
create () {
|
||||||
|
const id = this.getNewId();
|
||||||
|
const file = {
|
||||||
|
content: '',
|
||||||
|
isPristine: false,
|
||||||
|
name: `Snippet #${id}`,
|
||||||
|
id
|
||||||
|
};
|
||||||
|
|
||||||
|
transaction(() => {
|
||||||
|
this.files.set(id, file);
|
||||||
|
this.select(id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
edit (value) {
|
||||||
|
if (!this.selected) {
|
||||||
|
this.create();
|
||||||
|
}
|
||||||
|
|
||||||
|
const file = this.files.get(this.selected);
|
||||||
|
|
||||||
|
file.content = value;
|
||||||
|
this.updateFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
evaluate () {
|
||||||
|
const code = this.code;
|
||||||
|
|
||||||
|
if (!code) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { result, error } = evaluate(code);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
console.error(error);
|
||||||
|
} else {
|
||||||
|
console.log(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getFromStorage () {
|
||||||
|
return store.get(LS_SNIPPETS_KEY) || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
getNewId () {
|
||||||
|
if (this.files.size === 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ids = this.files.values().map((file) => file.id);
|
||||||
|
|
||||||
|
return Math.max(...ids) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
load () {
|
||||||
|
const files = this.getFromStorage();
|
||||||
|
|
||||||
|
transaction(() => {
|
||||||
|
files.forEach((file) => {
|
||||||
|
this.files.set(file.id, file);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
remove (id) {
|
||||||
|
transaction(() => {
|
||||||
|
if (id === this.selected) {
|
||||||
|
this.selected = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.files.delete(id);
|
||||||
|
|
||||||
|
const files = this.getFromStorage()
|
||||||
|
.filter((f) => f.id !== id);
|
||||||
|
|
||||||
|
return store.set(LS_SNIPPETS_KEY, files);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
save (_file) {
|
||||||
|
let file;
|
||||||
|
|
||||||
|
if (!_file) {
|
||||||
|
if (!this.selected) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
file = this.files.get(this.selected);
|
||||||
|
} else {
|
||||||
|
file = _file;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.savedContent = file.content;
|
||||||
|
this.updateFile(file);
|
||||||
|
this.saveToStorage(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveName () {
|
||||||
|
if (!this.renaming || !this.nextName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const file = this.files.get(this.renaming);
|
||||||
|
|
||||||
|
file.name = this.nextName;
|
||||||
|
|
||||||
|
this.save(file);
|
||||||
|
this.cancelRename();
|
||||||
|
}
|
||||||
|
|
||||||
|
saveToStorage (file) {
|
||||||
|
const files = this.getFromStorage();
|
||||||
|
const index = files.findIndex((f) => file.id === f.id);
|
||||||
|
|
||||||
|
if (index === -1) {
|
||||||
|
files.push(file);
|
||||||
|
} else {
|
||||||
|
files[index] = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return store.set(LS_SNIPPETS_KEY, files);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
select (id) {
|
||||||
|
this.selected = id;
|
||||||
|
|
||||||
|
// Wait for the file content to be loaded
|
||||||
|
setTimeout(() => {
|
||||||
|
this.clearCodeHistory();
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
setCodeMirror (codeMirror) {
|
||||||
|
this.codeMirror = codeMirror;
|
||||||
|
|
||||||
|
if (!codeMirror) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.codeMirror
|
||||||
|
.on('keydown', (_, event) => {
|
||||||
|
const codeName = keycode(event);
|
||||||
|
|
||||||
|
if (codeName === 'enter' && event.ctrlKey) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
return this.evaluate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
startRename (id) {
|
||||||
|
const file = this.files.get(id);
|
||||||
|
|
||||||
|
transaction(() => {
|
||||||
|
this.renaming = id;
|
||||||
|
this.nextName = file.name;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
updateFile (file) {
|
||||||
|
file.isPristine = (file.content === file.savedContent);
|
||||||
|
|
||||||
|
this.files.set(file.id, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
updateName (value) {
|
||||||
|
this.nextName = value;
|
||||||
|
}
|
||||||
|
}
|
17
js/src/dapps/console/Watches/index.js
Normal file
17
js/src/dapps/console/Watches/index.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
export default from './watches';
|
107
js/src/dapps/console/Watches/watches.css
Normal file
107
js/src/dapps/console/Watches/watches.css
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
/* This file is part of Parity.
|
||||||
|
/*
|
||||||
|
/* Parity is free software: you can redistribute it and/or modify
|
||||||
|
/* it under the terms of the GNU General Public License as published by
|
||||||
|
/* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
/* (at your option) any later version.
|
||||||
|
/*
|
||||||
|
/* Parity is distributed in the hope that it will be useful,
|
||||||
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
/* GNU General Public License for more details.
|
||||||
|
/*
|
||||||
|
/* You should have received a copy of the GNU General Public License
|
||||||
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.container {
|
||||||
|
background: #eee;
|
||||||
|
border-top: 1px solid lightgray;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
padding: 0.25em;
|
||||||
|
font-size: 8pt;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.watch {
|
||||||
|
align-items: flex-end;
|
||||||
|
border-left: 1px solid #ccc;
|
||||||
|
display: flex;
|
||||||
|
padding: 0 1em;
|
||||||
|
|
||||||
|
&.error .result {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result {
|
||||||
|
color: #00f;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.add {
|
||||||
|
color: green;
|
||||||
|
cursor: default;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold !important;
|
||||||
|
padding: 0 1em;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #fcfcfc;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
background-color: rgb(230, 236, 255);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.addContainer {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.addForm {
|
||||||
|
bottom: 100%;
|
||||||
|
display: flex;
|
||||||
|
padding: 0.5em 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 100vw;
|
||||||
|
|
||||||
|
.inputContainer {
|
||||||
|
border: solid 1px #d8d8d8;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
border: none;
|
||||||
|
font: 12px Arial;
|
||||||
|
|
||||||
|
&.big {
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
color: black;
|
||||||
|
font: 12px Arial;
|
||||||
|
padding: 0 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove {
|
||||||
|
cursor: default;
|
||||||
|
display: inline-flex;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-right: 0.75em;
|
||||||
|
|
||||||
|
* {
|
||||||
|
line-height: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #fcfcfc;
|
||||||
|
}
|
||||||
|
}
|
186
js/src/dapps/console/Watches/watches.js
Normal file
186
js/src/dapps/console/Watches/watches.js
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { observer } from 'mobx-react';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
import WatchesStore from './watches.store';
|
||||||
|
|
||||||
|
import styles from './watches.css';
|
||||||
|
|
||||||
|
@observer
|
||||||
|
export default class Watches extends Component {
|
||||||
|
watchesStore = WatchesStore.get();
|
||||||
|
|
||||||
|
render () {
|
||||||
|
return (
|
||||||
|
<div className={ styles.container }>
|
||||||
|
{ this.renderAddWatch() }
|
||||||
|
{ this.renderWatches() }
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAddForm () {
|
||||||
|
const { showAdd } = this.watchesStore;
|
||||||
|
|
||||||
|
if (!showAdd) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.addForm }>
|
||||||
|
<div className={ styles.inputContainer }>
|
||||||
|
<input
|
||||||
|
className={ styles.input }
|
||||||
|
onChange={ this.handleAddNameChange }
|
||||||
|
placeholder='Name'
|
||||||
|
type='text'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={ styles.inputContainer }>
|
||||||
|
<input
|
||||||
|
className={ [ styles.input, styles.big ].join(' ') }
|
||||||
|
onChange={ this.handleAddFunctionChange }
|
||||||
|
placeholder='Function'
|
||||||
|
type='text'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={ styles.inputContainer }>
|
||||||
|
<input
|
||||||
|
className={ styles.input }
|
||||||
|
onChange={ this.handleAddContextChange }
|
||||||
|
placeholder='Context'
|
||||||
|
type='text'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
className={ styles.button }
|
||||||
|
onClick={ this.handleAddWatch }
|
||||||
|
>
|
||||||
|
Add
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderAddWatch () {
|
||||||
|
const { showAdd } = this.watchesStore;
|
||||||
|
const classes = [ styles.add ];
|
||||||
|
|
||||||
|
if (showAdd) {
|
||||||
|
classes.push(styles.selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={ styles.addContainer }>
|
||||||
|
{ this.renderAddForm() }
|
||||||
|
<span
|
||||||
|
className={ classes.join(' ') }
|
||||||
|
onClick={ this.handleToggleAdd }
|
||||||
|
>
|
||||||
|
+
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderWatches () {
|
||||||
|
const { names } = this.watchesStore;
|
||||||
|
|
||||||
|
return names.map((name) => {
|
||||||
|
const { result, error } = this.watchesStore.get(name);
|
||||||
|
const classes = [ styles.watch ];
|
||||||
|
const resultStr = error
|
||||||
|
? error.toString()
|
||||||
|
: this.toString(result);
|
||||||
|
|
||||||
|
const onClick = () => this.handleRemoveWatch(name);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
classes.push(styles.error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={ classes.join(' ') }
|
||||||
|
key={ name }
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={ styles.remove }
|
||||||
|
onClick={ onClick }
|
||||||
|
title={ `Remove "${name}" watch` }
|
||||||
|
>
|
||||||
|
<span>✖</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span>{ name }</span>
|
||||||
|
<span className={ styles.result }>{ resultStr.toString() }</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleAddFunctionChange = (event) => {
|
||||||
|
const { value } = event.target;
|
||||||
|
|
||||||
|
this.watchesStore.updateAddFunction(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleAddContextChange = (event) => {
|
||||||
|
const { value } = event.target;
|
||||||
|
|
||||||
|
this.watchesStore.updateAddContext(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleAddNameChange = (event) => {
|
||||||
|
const { value } = event.target;
|
||||||
|
|
||||||
|
this.watchesStore.updateAddName(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleAddWatch = () => {
|
||||||
|
this.watchesStore.addWatch();
|
||||||
|
};
|
||||||
|
|
||||||
|
handleRemoveWatch = (name) => {
|
||||||
|
this.watchesStore.remove(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleToggleAdd = () => {
|
||||||
|
this.watchesStore.toggleAdd();
|
||||||
|
};
|
||||||
|
|
||||||
|
toString (result) {
|
||||||
|
if (result === undefined) {
|
||||||
|
return 'undefined';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result === null) {
|
||||||
|
return 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof result.toFormat === 'function') {
|
||||||
|
return result.toFormat();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof result.toString === 'function') {
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
148
js/src/dapps/console/Watches/watches.store.js
Normal file
148
js/src/dapps/console/Watches/watches.store.js
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import { action, map, observable } from 'mobx';
|
||||||
|
|
||||||
|
import { api } from '../parity';
|
||||||
|
import { evaluate } from '../utils';
|
||||||
|
|
||||||
|
let instance;
|
||||||
|
|
||||||
|
export default class WatchesStore {
|
||||||
|
@observable showAdd = false;
|
||||||
|
@observable watches = map();
|
||||||
|
|
||||||
|
watchesFunctions = {};
|
||||||
|
|
||||||
|
constructor () {
|
||||||
|
api.subscribe('eth_blockNumber', () => {
|
||||||
|
this.refreshWatches();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static get () {
|
||||||
|
if (!instance) {
|
||||||
|
instance = new WatchesStore();
|
||||||
|
|
||||||
|
window.watch = instance.add.bind(instance);
|
||||||
|
window.unwatch = instance.remove.bind(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
add (name, func, context) {
|
||||||
|
if (!func || (typeof func !== 'function' && typeof func.then !== 'function')) {
|
||||||
|
return console.error(Error(`cannot watch ${name} ; not a Function/Promise given`));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.watchesFunctions[name] = { func, context };
|
||||||
|
this.watches.set(name, {});
|
||||||
|
this.refreshWatches();
|
||||||
|
}
|
||||||
|
|
||||||
|
addWatch () {
|
||||||
|
this.toggleAdd();
|
||||||
|
|
||||||
|
const { addContext, addFunction, addName } = this;
|
||||||
|
|
||||||
|
const evaluatedFunction = evaluate(addFunction);
|
||||||
|
const evaluatedContext = addContext
|
||||||
|
? evaluate(addContext)
|
||||||
|
: {};
|
||||||
|
|
||||||
|
this.add(addName, evaluatedFunction.result, evaluatedContext.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
get (name) {
|
||||||
|
return this.watches.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
get names () {
|
||||||
|
return this.watches.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshWatches () {
|
||||||
|
const names = this.watches.keys();
|
||||||
|
const promises = names
|
||||||
|
.map((name) => {
|
||||||
|
const { context, func } = this.watchesFunctions[name];
|
||||||
|
let result;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (typeof func === 'function') {
|
||||||
|
result = func.apply(context || this);
|
||||||
|
} else {
|
||||||
|
result = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve(result);
|
||||||
|
} catch (error) {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map((promise, index) => {
|
||||||
|
const name = names[index];
|
||||||
|
|
||||||
|
return promise
|
||||||
|
.then((result) => {
|
||||||
|
this.updateWatch(name, result);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.updateWatch(name, error, true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
remove (name) {
|
||||||
|
this.watches.delete(name);
|
||||||
|
delete this.watchesFunctions[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
toggleAdd () {
|
||||||
|
this.showAdd = !this.showAdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateAddContext (value) {
|
||||||
|
this.addContext = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateAddFunction (value) {
|
||||||
|
this.addFunction = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateAddName (value) {
|
||||||
|
this.addName = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
updateWatch (name, result, isError = false) {
|
||||||
|
const next = {};
|
||||||
|
|
||||||
|
if (isError) {
|
||||||
|
next.error = result;
|
||||||
|
} else {
|
||||||
|
next.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.watches.set(name, { ...next });
|
||||||
|
}
|
||||||
|
}
|
36
js/src/dapps/console/codemirror.css
Normal file
36
js/src/dapps/console/codemirror.css
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/* Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
/* This file is part of Parity.
|
||||||
|
/*
|
||||||
|
/* Parity is free software: you can redistribute it and/or modify
|
||||||
|
/* it under the terms of the GNU General Public License as published by
|
||||||
|
/* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
/* (at your option) any later version.
|
||||||
|
/*
|
||||||
|
/* Parity is distributed in the hope that it will be useful,
|
||||||
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
/* GNU General Public License for more details.
|
||||||
|
/*
|
||||||
|
/* You should have received a copy of the GNU General Public License
|
||||||
|
/* along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
:global {
|
||||||
|
.cm-matchhighlight {
|
||||||
|
background-color: rgba(255, 255, 0, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror-hints {
|
||||||
|
font-family: dejavu sans mono, monospace;
|
||||||
|
font-size: 11px;
|
||||||
|
border-radius: 0;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CodeMirror-hint {
|
||||||
|
border-radius: 0;
|
||||||
|
cursor: default;
|
||||||
|
padding: 0.25em 0.25em 0.25em 0.35em;
|
||||||
|
}
|
||||||
|
}
|
335
js/src/dapps/console/parity.js
Normal file
335
js/src/dapps/console/parity.js
Normal file
File diff suppressed because one or more lines are too long
36
js/src/dapps/console/utils.js
Normal file
36
js/src/dapps/console/utils.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
/* eslint-disable no-eval */
|
||||||
|
|
||||||
|
export function evaluate (input) {
|
||||||
|
try {
|
||||||
|
const result = eval.apply(window, [ `${input}` ]);
|
||||||
|
|
||||||
|
return { result };
|
||||||
|
} catch (err) {
|
||||||
|
try {
|
||||||
|
const result = eval.apply(window, [ `(function () {
|
||||||
|
var x = ${input};
|
||||||
|
return x;
|
||||||
|
})()` ]);
|
||||||
|
|
||||||
|
return { result };
|
||||||
|
} catch (error) {
|
||||||
|
return { error };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
0
js/src/dapps/static/.gitkeep
Normal file
0
js/src/dapps/static/.gitkeep
Normal file
@ -1,221 +0,0 @@
|
|||||||
#full-screen {
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea:focus, input:focus{
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
* { padding: 0; margin: 0; }
|
|
||||||
|
|
||||||
html, body, #full-screen {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#full-screen {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-end;
|
|
||||||
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
#history-wrap {
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#history {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
min-height: min-content;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.entry, #input {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0.25em;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: flex-start;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.type {
|
|
||||||
color: #ccc;
|
|
||||||
font-weight: bold;
|
|
||||||
font-family: "Lucida Console", Monaco, monospace;
|
|
||||||
font-size: 11pt;
|
|
||||||
padding: 0 0.5em 0 0.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.command .type {
|
|
||||||
color: #aaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.result .type {
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
#input .type {
|
|
||||||
color: #59f;
|
|
||||||
}
|
|
||||||
|
|
||||||
.addwatch {
|
|
||||||
background-color: #cfc;
|
|
||||||
border-top: 1px solid #6e6;
|
|
||||||
}
|
|
||||||
.addwatch .type {
|
|
||||||
color: #040;
|
|
||||||
}
|
|
||||||
.addwatch .text {
|
|
||||||
color: #080;
|
|
||||||
}
|
|
||||||
|
|
||||||
.log.logLevel .type {
|
|
||||||
color: blue;
|
|
||||||
}
|
|
||||||
.log.debugLevel .text {
|
|
||||||
color: blue;
|
|
||||||
}
|
|
||||||
.log.infoLevel .type {
|
|
||||||
color: #00c;
|
|
||||||
}
|
|
||||||
.log.warnLevel {
|
|
||||||
background-color: #fff8dd;
|
|
||||||
border-top: 1px solid #fe8;
|
|
||||||
border-bottom: 1px solid #fe8;
|
|
||||||
}
|
|
||||||
.log.warnLevel .text {
|
|
||||||
color: #440;
|
|
||||||
}
|
|
||||||
.log.warnLevel .type {
|
|
||||||
color: #880;
|
|
||||||
}
|
|
||||||
.log.errorLevel, .error {
|
|
||||||
background-color: #fee;
|
|
||||||
border-top: 1px solid #fbb;
|
|
||||||
border-bottom: 1px solid #fbb;
|
|
||||||
}
|
|
||||||
.log.errorLevel .text, .error .text {
|
|
||||||
color: #c00;
|
|
||||||
}
|
|
||||||
.log.errorLevel .type, .error .type {
|
|
||||||
color: #800;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
span.text {
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
.text {
|
|
||||||
border: 0;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
color: black;
|
|
||||||
font-weight: 1000;
|
|
||||||
font-family: "Lucida Console", Monaco, monospace;
|
|
||||||
font-size: 11pt;
|
|
||||||
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
div.error {
|
|
||||||
background-color: #fee;
|
|
||||||
border-top: 1px solid #fbb;
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
div.command {
|
|
||||||
border-top: 1px solid #eee;
|
|
||||||
}
|
|
||||||
div#input {
|
|
||||||
border-top: 1px solid #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
#status {
|
|
||||||
background: #eee;
|
|
||||||
padding: 0.25em;
|
|
||||||
font-family: "Lucida Console", Monaco, monospace;
|
|
||||||
font-size: 8pt;
|
|
||||||
color: #888;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#input {
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
#status {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.watch {
|
|
||||||
padding-left: 1em;
|
|
||||||
padding-right: 1em;
|
|
||||||
}
|
|
||||||
.watch:not(:first-child) {
|
|
||||||
border-left: 1px solid #ccc;
|
|
||||||
}
|
|
||||||
.expr {
|
|
||||||
color: #888;
|
|
||||||
margin-right: 0.5em;
|
|
||||||
}
|
|
||||||
.res {
|
|
||||||
font-weight: bold;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stringType {
|
|
||||||
color: #c00;
|
|
||||||
}
|
|
||||||
.numberType {
|
|
||||||
color: #00f;
|
|
||||||
}
|
|
||||||
.eObject {
|
|
||||||
color: #00f;
|
|
||||||
}
|
|
||||||
.objectType {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
.fieldType {
|
|
||||||
color: #808;
|
|
||||||
}
|
|
||||||
.undefinedType {
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
.functionType {
|
|
||||||
color: #666;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
#autocomplete-anchor {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
#autocomplete {
|
|
||||||
position: absolute;
|
|
||||||
left: 1.5em;
|
|
||||||
bottom: 0;
|
|
||||||
background: #f8f8f8;
|
|
||||||
box-shadow: 0 0.125em 0.25em rgba(0, 0, 0, 0.5);
|
|
||||||
max-height: 20em;
|
|
||||||
overflow: scroll;
|
|
||||||
}
|
|
||||||
#autocomplete div {
|
|
||||||
font-size: small;
|
|
||||||
font-family: "Lucida Console", Monaco, monospace;
|
|
||||||
padding: 0.1em 1em 0.1em 0;
|
|
||||||
border-top: 1px solid #eee;
|
|
||||||
}
|
|
||||||
.ac-already {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.ac-new {
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
.ac-selected {
|
|
||||||
background-color: #ccddff;
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="us">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>JS Console dapp</title>
|
|
||||||
<link href="console.css" rel='stylesheet' type='text/css'>
|
|
||||||
<script src="/web3.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="full-screen">
|
|
||||||
<div id="eval"></div>
|
|
||||||
<div id="history-wrap"><div id="history"></div></div>
|
|
||||||
<div id="autocomplete-anchor"><div id="autocomplete"></div></div>
|
|
||||||
<div id="input"><span class="type">></span><input type="text" class="text" id="command" list="input-datalist"></div>
|
|
||||||
<div id="status"></div>
|
|
||||||
</div>
|
|
||||||
<script src="console.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
File diff suppressed because one or more lines are too long
@ -22,7 +22,7 @@
|
|||||||
color: #333;
|
color: #333;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-family: 'Roboto', sans-serif;
|
font-family: 'Roboto', sans-serif;
|
||||||
font-weight: 300 !important;
|
font-weight: 300;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
@ -39,7 +39,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
:root * {
|
:root * {
|
||||||
font-weight: 300 !important;
|
font-weight: 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root :global(#container) > div {
|
:root :global(#container) > div {
|
||||||
|
@ -7,6 +7,17 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"visible": false
|
"visible": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "0xa635a9326814bded464190eddf0bdb90ce92d40ea2359cf553ea80e3c5a4076c",
|
||||||
|
"url": "console",
|
||||||
|
"name": "Parity/Web3 console",
|
||||||
|
"description": "A Javascript development console complete with web3 and parity objects",
|
||||||
|
"version": "0.3",
|
||||||
|
"author": "Gav Wood <gavin@parity.io>",
|
||||||
|
"position": "top-right",
|
||||||
|
"visible": true,
|
||||||
|
"secure": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "0xf9f2d620c2e08f83e45555247146c62185e4ab7cf82a4b9002a265a0d020348f",
|
"id": "0xf9f2d620c2e08f83e45555247146c62185e4ab7cf82a4b9002a265a0d020348f",
|
||||||
"url": "tokendeploy",
|
"url": "tokendeploy",
|
||||||
@ -84,17 +95,5 @@
|
|||||||
"visible": true,
|
"visible": true,
|
||||||
"skipBuild": true,
|
"skipBuild": true,
|
||||||
"skipHistory": true
|
"skipHistory": true
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "0xa635a9326814bded464190eddf0bdb90ce92d40ea2359cf553ea80e3c5a4076c",
|
|
||||||
"url": "console",
|
|
||||||
"name": "Parity/Web3 console",
|
|
||||||
"description": "A Javascript development console complete with web3 and parity objects",
|
|
||||||
"version": "0.3",
|
|
||||||
"author": "Gav Wood <gavin@parity.io>",
|
|
||||||
"position": "top-right",
|
|
||||||
"visible": true,
|
|
||||||
"secure": true,
|
|
||||||
"skipBuild": true
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
56
js/yarn.lock
56
js/yarn.lock
@ -1053,7 +1053,7 @@ babel-register@6.23.0, babel-register@^6.23.0:
|
|||||||
mkdirp "^0.5.1"
|
mkdirp "^0.5.1"
|
||||||
source-map-support "^0.4.2"
|
source-map-support "^0.4.2"
|
||||||
|
|
||||||
babel-runtime@6.23.0, babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.20.0, babel-runtime@^6.22.0:
|
babel-runtime@6.23.0, babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.2.0, babel-runtime@^6.20.0, babel-runtime@^6.22.0, babel-runtime@^6.9.2:
|
||||||
version "6.23.0"
|
version "6.23.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
|
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -1551,7 +1551,7 @@ clap@^1.0.9:
|
|||||||
dependencies:
|
dependencies:
|
||||||
chalk "^1.1.3"
|
chalk "^1.1.3"
|
||||||
|
|
||||||
classnames@2.2.5, classnames@^2.2.0:
|
classnames@2.2.5, classnames@^2.2.0, classnames@^2.2.5:
|
||||||
version "2.2.5"
|
version "2.2.5"
|
||||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d"
|
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d"
|
||||||
|
|
||||||
@ -1637,6 +1637,10 @@ code-point-at@^1.0.0:
|
|||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
|
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
|
||||||
|
|
||||||
|
codemirror@^5.18.2:
|
||||||
|
version "5.25.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.25.2.tgz#8c77677ca9c9248d757d3a07ed1e89a8404850b7"
|
||||||
|
|
||||||
collapse-white-space@^1.0.0:
|
collapse-white-space@^1.0.0:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.2.tgz#9c463fb9c6d190d2dcae21a356a01bcae9eeef6d"
|
resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.2.tgz#9c463fb9c6d190d2dcae21a356a01bcae9eeef6d"
|
||||||
@ -2118,6 +2122,13 @@ dashdash@^1.12.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
assert-plus "^1.0.0"
|
assert-plus "^1.0.0"
|
||||||
|
|
||||||
|
date-difference@1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/date-difference/-/date-difference-1.0.0.tgz#d3e6e883c0cad2dc9dbfcbf12e06297b97298974"
|
||||||
|
dependencies:
|
||||||
|
get-stdin "^3.0.2"
|
||||||
|
meow "^3.1.0"
|
||||||
|
|
||||||
date-now@1.0.1:
|
date-now@1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/date-now/-/date-now-1.0.1.tgz#bb7d086438debe4182a485fb3df3fbfb99d6153c"
|
resolved "https://registry.yarnpkg.com/date-now/-/date-now-1.0.1.tgz#bb7d086438debe4182a485fb3df3fbfb99d6153c"
|
||||||
@ -3332,6 +3343,10 @@ get-proxy@^1.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
rc "^1.1.2"
|
rc "^1.1.2"
|
||||||
|
|
||||||
|
get-stdin@^3.0.2:
|
||||||
|
version "3.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-3.0.2.tgz#c1ced24b9039b38ded85bdf161e57713b6dd4abe"
|
||||||
|
|
||||||
get-stdin@^4.0.1:
|
get-stdin@^4.0.1:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
|
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
|
||||||
@ -4086,6 +4101,10 @@ is-date-object@^1.0.1:
|
|||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16"
|
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16"
|
||||||
|
|
||||||
|
is-dom@^1.0.5:
|
||||||
|
version "1.0.9"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-dom/-/is-dom-1.0.9.tgz#483832d52972073de12b9fe3f60320870da8370d"
|
||||||
|
|
||||||
is-dotfile@^1.0.0:
|
is-dotfile@^1.0.0:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
|
resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d"
|
||||||
@ -4563,9 +4582,9 @@ keycode@^2.1.1:
|
|||||||
version "2.1.8"
|
version "2.1.8"
|
||||||
resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.1.8.tgz#94d2b7098215eff0e8f9a8931d5a59076c4532fb"
|
resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.1.8.tgz#94d2b7098215eff0e8f9a8931d5a59076c4532fb"
|
||||||
|
|
||||||
keythereum@0.4.3:
|
keythereum@0.4.6:
|
||||||
version "0.4.3"
|
version "0.4.6"
|
||||||
resolved "https://registry.yarnpkg.com/keythereum/-/keythereum-0.4.3.tgz#514acfec3cc4d04b33a21f5d081600719457d2c0"
|
resolved "https://registry.yarnpkg.com/keythereum/-/keythereum-0.4.6.tgz#0fdec7cf938ae39e5e3061b2f6e16677b766c5da"
|
||||||
dependencies:
|
dependencies:
|
||||||
elliptic "6.4.0"
|
elliptic "6.4.0"
|
||||||
ethereumjs-util "5.1.1"
|
ethereumjs-util "5.1.1"
|
||||||
@ -4775,6 +4794,10 @@ lodash.create@3.1.1:
|
|||||||
lodash._basecreate "^3.0.0"
|
lodash._basecreate "^3.0.0"
|
||||||
lodash._isiterateecall "^3.0.0"
|
lodash._isiterateecall "^3.0.0"
|
||||||
|
|
||||||
|
lodash.debounce@^4.0.8:
|
||||||
|
version "4.0.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
|
||||||
|
|
||||||
lodash.defaults@^4.0.1:
|
lodash.defaults@^4.0.1:
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
|
resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
|
||||||
@ -5237,11 +5260,11 @@ multipipe@^0.1.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
duplexer2 "0.0.2"
|
duplexer2 "0.0.2"
|
||||||
|
|
||||||
mute-stream@0.0.5, mute-stream@~0.0.4:
|
mute-stream@0.0.5:
|
||||||
version "0.0.5"
|
version "0.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0"
|
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0"
|
||||||
|
|
||||||
mute-stream@0.0.7:
|
mute-stream@0.0.7, mute-stream@~0.0.4:
|
||||||
version "0.0.7"
|
version "0.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
|
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
|
||||||
|
|
||||||
@ -6524,6 +6547,14 @@ react-addons-test-utils@15.4.2:
|
|||||||
fbjs "^0.8.4"
|
fbjs "^0.8.4"
|
||||||
object-assign "^4.1.0"
|
object-assign "^4.1.0"
|
||||||
|
|
||||||
|
react-codemirror@^0.3.0:
|
||||||
|
version "0.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-codemirror/-/react-codemirror-0.3.0.tgz#cd6bd6ef458ec1e035cfd8b3fe7b30c8c7883c6c"
|
||||||
|
dependencies:
|
||||||
|
classnames "^2.2.5"
|
||||||
|
codemirror "^5.18.2"
|
||||||
|
lodash.debounce "^4.0.8"
|
||||||
|
|
||||||
react-container-dimensions@1.2.0:
|
react-container-dimensions@1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-container-dimensions/-/react-container-dimensions-1.2.0.tgz#bfb5e70e10aa82d2ecba49147d14bb4c22cafdaa"
|
resolved "https://registry.yarnpkg.com/react-container-dimensions/-/react-container-dimensions-1.2.0.tgz#bfb5e70e10aa82d2ecba49147d14bb4c22cafdaa"
|
||||||
@ -6596,6 +6627,13 @@ react-hot-loader@3.0.0-beta.6:
|
|||||||
redbox-react "^1.2.5"
|
redbox-react "^1.2.5"
|
||||||
source-map "^0.4.4"
|
source-map "^0.4.4"
|
||||||
|
|
||||||
|
react-inspector@paritytech/react-inspector:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://codeload.github.com/paritytech/react-inspector/tar.gz/73b5214261a5131821eb9088f58d7e5f31210c23"
|
||||||
|
dependencies:
|
||||||
|
babel-runtime "^6.9.2"
|
||||||
|
is-dom "^1.0.5"
|
||||||
|
|
||||||
react-intl-aggregate-webpack-plugin@0.0.1:
|
react-intl-aggregate-webpack-plugin@0.0.1:
|
||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/react-intl-aggregate-webpack-plugin/-/react-intl-aggregate-webpack-plugin-0.0.1.tgz#c29958860d7bcdfa6f460dec79f55ae0220488c6"
|
resolved "https://registry.yarnpkg.com/react-intl-aggregate-webpack-plugin/-/react-intl-aggregate-webpack-plugin-0.0.1.tgz#c29958860d7bcdfa6f460dec79f55ae0220488c6"
|
||||||
@ -6958,7 +6996,7 @@ request-capture-har@^1.1.4:
|
|||||||
version "1.2.2"
|
version "1.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/request-capture-har/-/request-capture-har-1.2.2.tgz#cd692cfb2cc744fd84a3358aac6ee51528cf720d"
|
resolved "https://registry.yarnpkg.com/request-capture-har/-/request-capture-har-1.2.2.tgz#cd692cfb2cc744fd84a3358aac6ee51528cf720d"
|
||||||
|
|
||||||
request@2, request@^2.75.0, request@^2.81.0:
|
request@2, request@^2.75.0, request@^2.79.0, request@^2.81.0:
|
||||||
version "2.81.0"
|
version "2.81.0"
|
||||||
resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
|
resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -6985,7 +7023,7 @@ request@2, request@^2.75.0, request@^2.81.0:
|
|||||||
tunnel-agent "^0.6.0"
|
tunnel-agent "^0.6.0"
|
||||||
uuid "^3.0.0"
|
uuid "^3.0.0"
|
||||||
|
|
||||||
request@2.79.0, request@^2.79.0:
|
request@2.79.0:
|
||||||
version "2.79.0"
|
version "2.79.0"
|
||||||
resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de"
|
resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
Loading…
Reference in New Issue
Block a user