Browse Source

Javascript & API console app (#666)

* JS playground & console (start something...)

* It runs...

* WIP

* Use codeflask

* Highlights

* Small updates, console v0.1 is ok to play with

* Bump

* Only shadow, no border (article)
Jaco Greeff 6 years ago
parent
commit
fb9cf70a71
41 changed files with 669 additions and 52 deletions
  1. 1 1
      jest.config.js
  2. 1 1
      lerna.json
  3. 2 2
      packages/app-123code/package.json
  4. 2 2
      packages/app-accounts/package.json
  5. 2 2
      packages/app-addresses/package.json
  6. 3 3
      packages/app-democracy/package.json
  7. 2 2
      packages/app-explorer/package.json
  8. 4 4
      packages/app-extrinsics/package.json
  9. 201 0
      packages/app-js/LICENSE
  10. 1 0
      packages/app-js/README.md
  11. 17 0
      packages/app-js/package.json
  12. 80 0
      packages/app-js/src/Editor.tsx
  13. 38 0
      packages/app-js/src/Output.tsx
  14. 5 0
      packages/app-js/src/codeflask.d.ts
  15. 59 0
      packages/app-js/src/index.css
  16. 106 0
      packages/app-js/src/index.tsx
  17. 8 0
      packages/app-js/src/snippets/newHead.ts
  18. 12 0
      packages/app-js/src/snippets/wrapping.ts
  19. 7 0
      packages/app-js/src/translate.ts
  20. 10 0
      packages/app-js/src/types.ts
  21. 2 2
      packages/app-nodeinfo/package.json
  22. 3 3
      packages/app-settings/package.json
  23. 4 4
      packages/app-staking/package.json
  24. 3 3
      packages/app-storage/package.json
  25. 2 2
      packages/app-toolbox/package.json
  26. 3 3
      packages/app-transfer/package.json
  27. 3 3
      packages/apps/package.json
  28. 1 1
      packages/apps/src/SideBar/SideBar.css
  29. 1 1
      packages/apps/src/index.css
  30. 2 0
      packages/apps/src/routing/index.ts
  31. 22 0
      packages/apps/src/routing/js.ts
  32. 1 0
      packages/apps/webpack.config.js
  33. 1 1
      packages/ui-api/package.json
  34. 3 3
      packages/ui-app/package.json
  35. 4 2
      packages/ui-app/src/styles/app.css
  36. 2 2
      packages/ui-app/src/styles/semantic.css
  37. 2 2
      packages/ui-params/package.json
  38. 1 1
      packages/ui-reactive/package.json
  39. 2 2
      packages/ui-signer/package.json
  40. 1 0
      tsconfig.json
  41. 45 0
      yarn.lock

+ 1 - 1
jest.config.js

@@ -2,7 +2,7 @@ const config = require('@polkadot/dev-react/config/jest');
 
 module.exports = Object.assign({}, config, {
   moduleNameMapper: {
-    '@polkadot/app-(123code|accounts|addresses|democracy|explorer|extrinsics|rpc|settings|staking|status|storage|toolbox|transfer)(.*)$': '<rootDir>/packages/app-$1/src/$2',
+    '@polkadot/app-(123code|accounts|addresses|democracy|explorer|extrinsics|js|rpc|settings|staking|status|storage|toolbox|transfer)(.*)$': '<rootDir>/packages/app-$1/src/$2',
     '@polkadot/ui-(api|app|params|reactive|signer)(.*)$': '<rootDir>/packages/ui-$1/src/$2',
     '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': 'empty/object',
     '\\.(css|less)$': 'empty/object'

+ 1 - 1
lerna.json

@@ -10,5 +10,5 @@
   "packages": [
     "packages/*"
   ],
-  "version": "0.22.60"
+  "version": "0.23.0"
 }

+ 2 - 2
packages/app-123code/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/app-123code",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "description": "A baasic app that shows the ropes on customisation",
   "main": "index.js",
   "scripts": {},
@@ -11,6 +11,6 @@
   "license": "Apache-2.0",
   "dependencies": {
     "@babel/runtime": "^7.2.0",
-    "@polkadot/ui-app": "^0.22.60"
+    "@polkadot/ui-app": "^0.23.0"
   }
 }

+ 2 - 2
packages/app-accounts/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/app-accounts",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "main": "index.js",
   "repository": "https://github.com/polkadot-js/apps.git",
   "author": "Jaco Greeff <jacogr@gmail.com>",
@@ -11,7 +11,7 @@
   "license": "Apache-2.0",
   "dependencies": {
     "@babel/runtime": "^7.2.0",
-    "@polkadot/ui-app": "^0.22.60",
+    "@polkadot/ui-app": "^0.23.0",
     "@types/file-saver": "^2.0.0",
     "@types/yargs": "^12.0.5",
     "babel-plugin-module-resolver": "^3.1.1",

+ 2 - 2
packages/app-addresses/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/app-addresses",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "main": "index.js",
   "repository": "https://github.com/polkadot-js/apps.git",
   "author": "Jaco Greeff <jacogr@gmail.com>",
@@ -11,6 +11,6 @@
   "license": "Apache-2.0",
   "dependencies": {
     "@babel/runtime": "^7.2.0",
-    "@polkadot/ui-app": "^0.22.60"
+    "@polkadot/ui-app": "^0.23.0"
   }
 }

+ 3 - 3
packages/app-democracy/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/app-democracy",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "description": "A referendum & proposal app",
   "main": "index.js",
   "scripts": {},
@@ -11,7 +11,7 @@
   "license": "Apache-2.0",
   "dependencies": {
     "@babel/runtime": "^7.2.0",
-    "@polkadot/ui-app": "^0.22.60",
-    "@polkadot/ui-reactive": "^0.22.60"
+    "@polkadot/ui-app": "^0.23.0",
+    "@polkadot/ui-reactive": "^0.23.0"
   }
 }

+ 2 - 2
packages/app-explorer/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/app-explorer",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "main": "index.js",
   "repository": "https://github.com/polkadot-js/apps.git",
   "author": "Jaco Greeff <jacogr@gmail.com>",
@@ -11,6 +11,6 @@
   "license": "Apache-2.0",
   "dependencies": {
     "@babel/runtime": "^7.2.0",
-    "@polkadot/ui-app": "^0.22.60"
+    "@polkadot/ui-app": "^0.23.0"
   }
 }

+ 4 - 4
packages/app-extrinsics/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/app-extrinsics",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "main": "index.js",
   "repository": "https://github.com/polkadot-js/apps.git",
   "author": "Jaco Greeff <jacogr@gmail.com>",
@@ -11,8 +11,8 @@
   "license": "Apache-2.0",
   "dependencies": {
     "@babel/runtime": "^7.2.0",
-    "@polkadot/ui-app": "^0.22.60",
-    "@polkadot/ui-params": "^0.22.60",
-    "@polkadot/ui-signer": "^0.22.60"
+    "@polkadot/ui-app": "^0.23.0",
+    "@polkadot/ui-params": "^0.23.0",
+    "@polkadot/ui-signer": "^0.23.0"
   }
 }

+ 201 - 0
packages/app-js/LICENSE

@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                    http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+  "License" shall mean the terms and conditions for use, reproduction,
+  and distribution as defined by Sections 1 through 9 of this document.
+
+  "Licensor" shall mean the copyright owner or entity authorized by
+  the copyright owner that is granting the License.
+
+  "Legal Entity" shall mean the union of the acting entity and all
+  other entities that control, are controlled by, or are under common
+  control with that entity. For the purposes of this definition,
+  "control" means (i) the power, direct or indirect, to cause the
+  direction or management of such entity, whether by contract or
+  otherwise, or (ii) ownership of fifty percent (50%) or more of the
+  outstanding shares, or (iii) beneficial ownership of such entity.
+
+  "You" (or "Your") shall mean an individual or Legal Entity
+  exercising permissions granted by this License.
+
+  "Source" form shall mean the preferred form for making modifications,
+  including but not limited to software source code, documentation
+  source, and configuration files.
+
+  "Object" form shall mean any form resulting from mechanical
+  transformation or translation of a Source form, including but
+  not limited to compiled object code, generated documentation,
+  and conversions to other media types.
+
+  "Work" shall mean the work of authorship, whether in Source or
+  Object form, made available under the License, as indicated by a
+  copyright notice that is included in or attached to the work
+  (an example is provided in the Appendix below).
+
+  "Derivative Works" shall mean any work, whether in Source or Object
+  form, that is based on (or derived from) the Work and for which the
+  editorial revisions, annotations, elaborations, or other modifications
+  represent, as a whole, an original work of authorship. For the purposes
+  of this License, Derivative Works shall not include works that remain
+  separable from, or merely link (or bind by name) to the interfaces of,
+  the Work and Derivative Works thereof.
+
+  "Contribution" shall mean any work of authorship, including
+  the original version of the Work and any modifications or additions
+  to that Work or Derivative Works thereof, that is intentionally
+  submitted to Licensor for inclusion in the Work by the copyright owner
+  or by an individual or Legal Entity authorized to submit on behalf of
+  the copyright owner. For the purposes of this definition, "submitted"
+  means any form of electronic, verbal, or written communication sent
+  to the Licensor or its representatives, including but not limited to
+  communication on electronic mailing lists, source code control systems,
+  and issue tracking systems that are managed by, or on behalf of, the
+  Licensor for the purpose of discussing and improving the Work, but
+  excluding communication that is conspicuously marked or otherwise
+  designated in writing by the copyright owner as "Not a Contribution."
+
+  "Contributor" shall mean Licensor and any individual or Legal Entity
+  on behalf of whom a Contribution has been received by Licensor and
+  subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  copyright license to reproduce, prepare Derivative Works of,
+  publicly display, publicly perform, sublicense, and distribute the
+  Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+  this License, each Contributor hereby grants to You a perpetual,
+  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+  (except as stated in this section) patent license to make, have made,
+  use, offer to sell, sell, import, and otherwise transfer the Work,
+  where such license applies only to those patent claims licensable
+  by such Contributor that are necessarily infringed by their
+  Contribution(s) alone or by combination of their Contribution(s)
+  with the Work to which such Contribution(s) was submitted. If You
+  institute patent litigation against any entity (including a
+  cross-claim or counterclaim in a lawsuit) alleging that the Work
+  or a Contribution incorporated within the Work constitutes direct
+  or contributory patent infringement, then any patent licenses
+  granted to You under this License for that Work shall terminate
+  as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+  Work or Derivative Works thereof in any medium, with or without
+  modifications, and in Source or Object form, provided that You
+  meet the following conditions:
+
+  (a) You must give any other recipients of the Work or
+      Derivative Works a copy of this License; and
+
+  (b) You must cause any modified files to carry prominent notices
+      stating that You changed the files; and
+
+  (c) You must retain, in the Source form of any Derivative Works
+      that You distribute, all copyright, patent, trademark, and
+      attribution notices from the Source form of the Work,
+      excluding those notices that do not pertain to any part of
+      the Derivative Works; and
+
+  (d) If the Work includes a "NOTICE" text file as part of its
+      distribution, then any Derivative Works that You distribute must
+      include a readable copy of the attribution notices contained
+      within such NOTICE file, excluding those notices that do not
+      pertain to any part of the Derivative Works, in at least one
+      of the following places: within a NOTICE text file distributed
+      as part of the Derivative Works; within the Source form or
+      documentation, if provided along with the Derivative Works; or,
+      within a display generated by the Derivative Works, if and
+      wherever such third-party notices normally appear. The contents
+      of the NOTICE file are for informational purposes only and
+      do not modify the License. You may add Your own attribution
+      notices within Derivative Works that You distribute, alongside
+      or as an addendum to the NOTICE text from the Work, provided
+      that such additional attribution notices cannot be construed
+      as modifying the License.
+
+  You may add Your own copyright statement to Your modifications and
+  may provide additional or different license terms and conditions
+  for use, reproduction, or distribution of Your modifications, or
+  for any such Derivative Works as a whole, provided Your use,
+  reproduction, and distribution of the Work otherwise complies with
+  the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+  any Contribution intentionally submitted for inclusion in the Work
+  by You to the Licensor shall be under the terms and conditions of
+  this License, without any additional terms or conditions.
+  Notwithstanding the above, nothing herein shall supersede or modify
+  the terms of any separate license agreement you may have executed
+  with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+  names, trademarks, service marks, or product names of the Licensor,
+  except as required for reasonable and customary use in describing the
+  origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+  agreed to in writing, Licensor provides the Work (and each
+  Contributor provides its Contributions) on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+  implied, including, without limitation, any warranties or conditions
+  of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+  PARTICULAR PURPOSE. You are solely responsible for determining the
+  appropriateness of using or redistributing the Work and assume any
+  risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+  whether in tort (including negligence), contract, or otherwise,
+  unless required by applicable law (such as deliberate and grossly
+  negligent acts) or agreed to in writing, shall any Contributor be
+  liable to You for damages, including any direct, indirect, special,
+  incidental, or consequential damages of any character arising as a
+  result of this License or out of the use or inability to use the
+  Work (including but not limited to damages for loss of goodwill,
+  work stoppage, computer failure or malfunction, or any and all
+  other commercial damages or losses), even if such Contributor
+  has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+  the Work or Derivative Works thereof, You may choose to offer,
+  and charge a fee for, acceptance of support, warranty, indemnity,
+  or other liability obligations and/or rights consistent with this
+  License. However, in accepting such obligations, You may act only
+  on Your own behalf and on Your sole responsibility, not on behalf
+  of any other Contributor, and only if You agree to indemnify,
+  defend, and hold each Contributor harmless for any liability
+  incurred by, or claims asserted against, such Contributor by reason
+  of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+  To apply the Apache License to your work, attach the following
+  boilerplate notice, with the fields enclosed by brackets "[]"
+  replaced with your own identifying information. (Don't include
+  the brackets!)  The text should be enclosed in the appropriate
+  comment syntax for the file format. We also recommend that a
+  file or class name and description of purpose be included on the
+  same "printed page" as the copyright notice for easier
+  identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.

+ 1 - 0
packages/app-js/README.md

@@ -0,0 +1 @@
+# @polkadot/app-js

+ 17 - 0
packages/app-js/package.json

@@ -0,0 +1,17 @@
+{
+  "name": "@polkadot/app-js",
+  "version": "0.23.0",
+  "description": "A simple JavaScript console for playing with the API",
+  "main": "index.js",
+  "scripts": {},
+  "author": "Jaco Greeff <jacogr@gmail.com>",
+  "maintainers": [
+    "Jaco Greeff <jacogr@gmail.com>"
+  ],
+  "license": "Apache-2.0",
+  "dependencies": {
+    "@babel/runtime": "^7.2.0",
+    "@polkadot/ui-app": "^0.23.0",
+    "codeflask": "1.4.0"
+  }
+}

+ 80 - 0
packages/app-js/src/Editor.tsx

@@ -0,0 +1,80 @@
+// Copyright 2017-2019 @polkadot/app-123code authors & contributors
+// This software may be modified and distributed under the terms
+// of the Apache-2.0 license. See the LICENSE file for details.
+
+import { BareProps } from '@polkadot/ui-app/types';
+
+import React from 'react';
+import CodeFlask from 'codeflask';
+
+import DEFAULT_CODE from './snippets/newHead';
+import WRAPPING from './snippets/wrapping';
+
+type Props = BareProps & {
+  children?: React.ReactNode,
+  onEdit: (code: string) => void
+};
+type State = {
+  code: string
+};
+
+export default class Editor extends React.PureComponent<Props, State> {
+  private id: string;
+
+  constructor (props: Props) {
+    super(props);
+
+    this.id = `flask-${Date.now()}`;
+    this.state = {
+      code: `${WRAPPING}${DEFAULT_CODE}`
+    };
+  }
+
+  componentDidMount () {
+    const { onEdit } = this.props;
+    const { code } = this.state;
+
+    const editor = new CodeFlask(`#${this.id}`, {
+      language: 'js',
+      lineNumbers: true
+    });
+
+    editor.updateCode(code);
+
+    editor.onUpdate((code: string) => {
+      this.onEdit(code);
+    });
+
+    editor.editorRoot.addEventListener('focusin', () => {
+      editor.onUpdate(this.onEdit);
+    });
+
+    editor.editorRoot.addEventListener('focusout', () => {
+      editor.onUpdate(() => {
+        // empty
+      });
+    });
+
+    onEdit(code);
+  }
+
+  render () {
+    const { children } = this.props;
+
+    return (
+      <article className='js--Editor'>
+        <div
+          className='container'
+          id={this.id}
+        />
+        {children}
+      </article>
+    );
+  }
+
+  private onEdit = (code: string): void => {
+    const { onEdit } = this.props;
+
+    this.setState({ code }, () => onEdit(code));
+  }
+}

+ 38 - 0
packages/app-js/src/Output.tsx

@@ -0,0 +1,38 @@
+// Copyright 2017-2019 @polkadot/app-123code authors & contributors
+// This software may be modified and distributed under the terms
+// of the Apache-2.0 license. See the LICENSE file for details.
+
+import { BareProps } from '@polkadot/ui-app/types';
+import { Log } from './types';
+
+import React from 'react';
+import { format } from '@polkadot/util/logger';
+
+type Props = BareProps & {
+  children?: React.ReactNode,
+  logs: Array<Log>
+};
+
+export default class Output extends React.PureComponent<Props> {
+  render () {
+    const { children, logs } = this.props;
+
+    return (
+      <div className='js--Output'>
+        {logs.map(this.renderEntry)}
+        {children}
+      </div>
+    );
+  }
+
+  private renderEntry = ({ args, type }: Log, index: number) => {
+    return (
+      <div
+        className={`js--Log ${type}`}
+        key={index}
+      >
+        {args.map((arg) => format(arg)).join(' ')}
+      </div>
+    );
+  }
+}

+ 5 - 0
packages/app-js/src/codeflask.d.ts

@@ -0,0 +1,5 @@
+// Copyright 2017-2019 @polkadot/app-123code authors & contributors
+// This software may be modified and distributed under the terms
+// of the Apache-2.0 license. See the LICENSE file for details.
+
+declare module 'codeflask';

+ 59 - 0
packages/app-js/src/index.css

@@ -0,0 +1,59 @@
+/* Copyright 2017-2019 @polkadot/app-js authors & contributors
+/* This software may be modified and distributed under the terms
+/* of the Apache-2.0 license. See the LICENSE file for details. */
+
+.js--App {
+  padding: 1rem 1.5rem;
+
+  /* .container {
+    padding: 0.25rem;
+  } */
+}
+
+.js--Editor,
+.js--Output {
+  .action-button {
+    position: absolute;
+    right: 0.25rem;
+    top: 0.5rem;
+    z-index: 100;
+  }
+}
+
+.js--Output {
+  margin-top: 1rem;
+  padding: 10px;
+  font-family: monospace;
+  font-size: 14px;
+  font-variant-ligatures: common-ligatures;
+  position: relative;
+
+  .js--Log {
+    animation: fadein 0.2s;
+    margin: 0 0 5px 0;
+    word-break: break-all;
+
+    &.error {
+      color: red;
+    }
+  }
+}
+
+.js--Editor {
+  padding: 0;
+  position: relative;
+
+  > div.container {
+    width: 100%;
+    height: 60vh;
+    position: relative;
+  }
+
+  .codeflask {
+    /* background: #f4f7fb; */
+  }
+
+  textarea {
+    outline: 0;
+  }
+}

+ 106 - 0
packages/app-js/src/index.tsx

@@ -0,0 +1,106 @@
+// Copyright 2017-2019 @polkadot/app-js authors & contributors
+// This software may be modified and distributed under the terms
+// of the Apache-2.0 license. See the LICENSE file for details.
+
+import { ApiProps } from '@polkadot/ui-api/types';
+import { AppProps, I18nProps } from '@polkadot/ui-app/types';
+import { Log, LogType } from './types';
+
+import React from 'react';
+import { withApi, withMulti } from '@polkadot/ui-api/index';
+import { Button } from '@polkadot/ui-app/index';
+import uiKeyring from '@polkadot/ui-keyring';
+import * as util from '@polkadot/util';
+import * as hashing from '@polkadot/util-crypto';
+
+import './index.css';
+
+import Editor from './Editor';
+import Output from './Output';
+import translate from './translate';
+
+type Props = ApiProps & AppProps & I18nProps;
+type State = {
+  code: string,
+  logs: Array<Log>
+};
+
+class App extends React.PureComponent<Props, State> {
+  state: State = {
+    code: '',
+    logs: []
+  };
+
+  render () {
+    const { logs } = this.state;
+
+    return (
+      <main className='js--App'>
+        <Editor onEdit={this.onEdit}>
+          <Button
+            className='action-button'
+            isCircular
+            isPrimary
+            icon='play'
+            onClick={this.runJs}
+          />
+        </Editor>
+        <Output logs={logs}>
+          <Button
+            className='action-button'
+            isCircular
+            isNegative
+            icon='erase'
+            onClick={this.clearConsole}
+          />
+        </Output>
+      </main>
+    );
+  }
+
+  private runJs = (): void => {
+    const { api } = this.props;
+    const { code } = this.state;
+    const { keyring } = uiKeyring;
+    const injected = {
+      api,
+      console: {
+        error: this.hookConsole('error'),
+        log: this.hookConsole('log')
+      },
+      global: null,
+      hashing,
+      keyring,
+      util,
+      window: null
+    };
+
+    const exec = `(async ({${Object.keys(injected).join(',')}}) => { try { ${code} } catch (error) { console.error(error); } })(injected);`;
+
+    new Function('injected', exec)(injected);
+  }
+
+  private onEdit = (code: string): void => {
+    this.setState({ code });
+  }
+
+  private clearConsole = () => {
+    this.setState({ logs: [] });
+  }
+
+  private hookConsole = (type: LogType) => {
+    return (...args: Array<any>): void => {
+      this.setState(({ logs }: State) => {
+        logs.push({ args, type });
+
+        return { logs: logs.slice(0) };
+      });
+    };
+  }
+}
+
+export default withMulti(
+  App,
+  translate,
+  withApi
+);

+ 8 - 0
packages/app-js/src/snippets/newHead.ts

@@ -0,0 +1,8 @@
+// Copyright 2017-2019 @polkadot/app-123code authors & contributors
+// This software may be modified and distributed under the terms
+// of the Apache-2.0 license. See the LICENSE file for details.
+
+export default `// subscribe to new headers, printing the full result
+api.rpc.chain.subscribeNewHead((header) => {
+  console.log(\`#\${header.blockNumber}:\`, header);
+});`;

+ 12 - 0
packages/app-js/src/snippets/wrapping.ts

@@ -0,0 +1,12 @@
+// Copyright 2017-2019 @polkadot/app-123code authors & contributors
+// This software may be modified and distributed under the terms
+// of the Apache-2.0 license. See the LICENSE file for details.
+
+export default `// all code is wrapped within an async closure, allowing access to:
+//     api (@polkadot/api), hashing (@polkadot/util-crypto),
+//     keyring (@polkadot/keyring) and util (@polkadot/util)
+// (async ({ api, hashing, keyring, util }) => {
+//   ... any user code is executed here ...
+// })(injected);
+
+`;

+ 7 - 0
packages/app-js/src/translate.ts

@@ -0,0 +1,7 @@
+// Copyright 2017-2019 @polkadot/app-js authors & contributors
+// This software may be modified and distributed under the terms
+// of the Apache-2.0 license. See the LICENSE file for details.
+
+import { withNamespaces } from 'react-i18next';
+
+export default withNamespaces(['js', 'ui']);

+ 10 - 0
packages/app-js/src/types.ts

@@ -0,0 +1,10 @@
+// Copyright 2017-2019 @polkadot/app-123code authors & contributors
+// This software may be modified and distributed under the terms
+// of the Apache-2.0 license. See the LICENSE file for details.
+
+export type LogType = 'error' | 'log';
+
+export type Log = {
+  args: Array<any>,
+  type: LogType
+};

+ 2 - 2
packages/app-nodeinfo/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/app-nodeinfo",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "description": "Node status and information",
   "main": "index.js",
   "scripts": {},
@@ -11,6 +11,6 @@
   "license": "Apache-2.0",
   "dependencies": {
     "@babel/runtime": "^7.2.0",
-    "@polkadot/ui-app": "^0.22.60"
+    "@polkadot/ui-app": "^0.23.0"
   }
 }

+ 3 - 3
packages/app-settings/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/app-settings",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "description": "Settings management",
   "main": "index.js",
   "scripts": {},
@@ -11,7 +11,7 @@
   "license": "Apache-2.0",
   "dependencies": {
     "@babel/runtime": "^7.2.0",
-    "@polkadot/ui-app": "^0.22.60",
-    "@polkadot/ui-reactive": "^0.22.60"
+    "@polkadot/ui-app": "^0.23.0",
+    "@polkadot/ui-reactive": "^0.23.0"
   }
 }

+ 4 - 4
packages/app-staking/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/app-staking",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "description": "A basic staking app",
   "main": "index.js",
   "scripts": {},
@@ -11,8 +11,8 @@
   "license": "Apache-2.0",
   "dependencies": {
     "@babel/runtime": "^7.2.0",
-    "@polkadot/app-explorer": "^0.22.60",
-    "@polkadot/ui-app": "^0.22.60",
-    "@polkadot/ui-reactive": "^0.22.60"
+    "@polkadot/app-explorer": "^0.23.0",
+    "@polkadot/ui-app": "^0.23.0",
+    "@polkadot/ui-reactive": "^0.23.0"
   }
 }

+ 3 - 3
packages/app-storage/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/app-storage",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "main": "index.js",
   "repository": "https://github.com/polkadot-js/apps.git",
   "author": "Jaco Greeff <jacogr@gmail.com>",
@@ -11,7 +11,7 @@
   "license": "Apache-2.0",
   "dependencies": {
     "@babel/runtime": "^7.2.0",
-    "@polkadot/ui-app": "^0.22.60",
-    "@polkadot/ui-params": "^0.22.60"
+    "@polkadot/ui-app": "^0.23.0",
+    "@polkadot/ui-params": "^0.23.0"
   }
 }

+ 2 - 2
packages/app-toolbox/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/app-toolbox",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "main": "index.js",
   "repository": "https://github.com/polkadot-js/apps.git",
   "author": "Jaco Greeff <jacogr@gmail.com>",
@@ -11,6 +11,6 @@
   "license": "Apache-2.0",
   "dependencies": {
     "@babel/runtime": "^7.2.0",
-    "@polkadot/ui-app": "^0.22.60"
+    "@polkadot/ui-app": "^0.23.0"
   }
 }

+ 3 - 3
packages/app-transfer/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/app-transfer",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "description": "A basic transfer app",
   "main": "index.js",
   "scripts": {},
@@ -11,7 +11,7 @@
   "license": "Apache-2.0",
   "dependencies": {
     "@babel/runtime": "^7.2.0",
-    "@polkadot/ui-app": "^0.22.60",
-    "@polkadot/ui-reactive": "^0.22.60"
+    "@polkadot/ui-app": "^0.23.0",
+    "@polkadot/ui-reactive": "^0.23.0"
   }
 }

+ 3 - 3
packages/apps/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/apps",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "description": "An Apps portal into the Polkadot network",
   "main": "index.js",
   "homepage": ".",
@@ -13,8 +13,8 @@
   "license": "Apache-2.0",
   "dependencies": {
     "@babel/runtime": "^7.2.0",
-    "@polkadot/ui-app": "^0.22.60",
+    "@polkadot/ui-app": "^0.23.0",
     "@polkadot/ui-assets": "^0.25.8",
-    "@polkadot/ui-signer": "^0.22.60"
+    "@polkadot/ui-signer": "^0.23.0"
   }
 }

+ 1 - 1
packages/apps/src/SideBar/SideBar.css

@@ -45,7 +45,7 @@ a.apps--SideBar-Item-NavLink {
 }
 
 a.apps--SideBar-Item-NavLink-active {
-  background: #fafafa;
+  background: #fafafa /* #fff */;
   border-radius: 0.28571429rem 0 0 0.28571429rem;
   /*
   border: 1px solid rgba(34, 36, 38, 0.15);

+ 1 - 1
packages/apps/src/index.css

@@ -16,7 +16,7 @@
   }
 
   .apps--Content {
-    background: #fafafa;
+    background: #fafafa /* #fff */;
     flex-grow: 1;
     overflow-x: hidden;
     overflow-y: auto;

+ 2 - 0
packages/apps/src/routing/index.ts

@@ -12,6 +12,7 @@ import addresses from './addresses';
 import democracy from './democracy';
 import explorer from './explorer';
 import extrinsics from './extrinsics';
+import js from './js';
 import nodeinfo from './nodeinfo';
 import settings from './settings';
 import staking from './staking';
@@ -47,6 +48,7 @@ const routes: Routes = appSettings.uiMode === 'light'
     settings,
     nodeinfo,
     toolbox,
+    js,
     template
   );
 

+ 22 - 0
packages/apps/src/routing/js.ts

@@ -0,0 +1,22 @@
+// Copyright 2017-2019 @polkadot/apps authors & contributors
+// This software may be modified and distributed under the terms
+// of the Apache-2.0 license. See the LICENSE file for details.
+
+import { Routes } from '../types';
+
+import Js from '@polkadot/app-js/index';
+
+export default ([
+  {
+    Component: Js,
+    display: {
+      isHidden: true,
+      needsApi: []
+    },
+    i18n: {
+      defaultValue: 'Javascript'
+    },
+    icon: 'code',
+    name: 'js'
+  }
+] as Routes);

+ 1 - 0
packages/apps/webpack.config.js

@@ -16,6 +16,7 @@ const packages = [
   'app-democracy',
   'app-explorer',
   'app-extrinsics',
+  'app-js',
   'app-settings',
   'app-staking',
   'app-nodeinfo',

+ 1 - 1
packages/ui-api/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/ui-api",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "description": "A collection of RxJs React components the Polkadot JS API",
   "main": "index.js",
   "keywords": [

+ 3 - 3
packages/ui-app/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/ui-app",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "main": "index.js",
   "repository": "https://github.com/polkadot-js/apps.git",
   "author": "Jaco Greeff <jacogr@gmail.com>",
@@ -15,10 +15,10 @@
     "@polkadot/keyring": "^0.33.36",
     "@polkadot/storage": "^0.42.2",
     "@polkadot/types": "^0.42.2",
-    "@polkadot/ui-api": "^0.22.60",
+    "@polkadot/ui-api": "^0.23.0",
     "@polkadot/ui-identicon": "^0.25.8",
     "@polkadot/ui-keyring": "^0.25.8",
-    "@polkadot/ui-reactive": "^0.22.60",
+    "@polkadot/ui-reactive": "^0.23.0",
     "@polkadot/ui-settings": "^0.25.8",
     "@polkadot/util": "^0.33.36",
     "@polkadot/util-crypto": "^0.33.36",

+ 4 - 2
packages/ui-app/src/styles/app.css

@@ -63,9 +63,11 @@ main > section {
 
 article {
   background: white;
-  border: 1px solid #f2f2f2;
-  border-left-width: 0.25rem;
+  /*border: 1px solid #f2f2f2;
+  border-left-width: 0.25rem;*/
+  border: 0 solid #fafafa;
   border-radius: 0.25rem;
+  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
   margin: 0.25rem;
   padding: 1rem 1.5rem;
   text-align: left;

+ 2 - 2
packages/ui-app/src/styles/semantic.css

@@ -95,7 +95,7 @@
 }
 
 .ui.modal {
-  background: #fafafa;
+  background: #fafafa /* #fff */;
   color: #4e4e4e;
   font-family: sans-serif;
 
@@ -166,6 +166,6 @@
   padding: 1em 2em 0;
 
   .item.active {
-    background: #fafafa;
+    background: #fafafa /* #fff */;
   }
 }

+ 2 - 2
packages/ui-params/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/ui-params",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "main": "index.js",
   "repository": "https://github.com/polkadot-js/apps.git",
   "author": "Jaco Greeff <jacogr@gmail.com>",
@@ -11,6 +11,6 @@
   "license": "Apache-2.0",
   "dependencies": {
     "@babel/runtime": "^7.2.0",
-    "@polkadot/ui-app": "^0.22.60"
+    "@polkadot/ui-app": "^0.23.0"
   }
 }

+ 1 - 1
packages/ui-reactive/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/ui-reactive",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "description": "A collection of RxJs React components the Polkadot JS API",
   "main": "index.js",
   "keywords": [

+ 2 - 2
packages/ui-signer/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@polkadot/ui-signer",
-  "version": "0.22.60",
+  "version": "0.23.0",
   "main": "index.js",
   "repository": "https://github.com/polkadot-js/apps.git",
   "author": "Jaco Greeff <jacogr@gmail.com>",
@@ -11,6 +11,6 @@
   "license": "Apache-2.0",
   "dependencies": {
     "@babel/runtime": "^7.2.0",
-    "@polkadot/ui-app": "^0.22.60"
+    "@polkadot/ui-app": "^0.23.0"
   }
 }

+ 1 - 0
tsconfig.json

@@ -9,6 +9,7 @@
       "@polkadot/app-democracy/*": [ "packages/app-democracy/src/*" ],
       "@polkadot/app-explorer/*": [ "packages/app-explorer/src/*" ],
       "@polkadot/app-extrinsics/*": [ "packages/app-extrinsics/src/*" ],
+      "@polkadot/app-js/*": [ "packages/app-js/src/*" ],
       "@polkadot/app-settings/*": [ "packages/app-settings/src/*" ],
       "@polkadot/app-staking/*": [ "packages/app-staking/src/*" ],
       "@polkadot/app-nodeinfo/*": [ "packages/app-nodeinfo/src/*" ],

+ 45 - 0
yarn.lock

@@ -3621,6 +3621,15 @@ cli-width@^2.0.0:
   resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
   integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
 
+clipboard@^2.0.0:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.4.tgz#836dafd66cf0fea5d71ce5d5b0bf6e958009112d"
+  integrity sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==
+  dependencies:
+    good-listener "^1.2.2"
+    select "^1.1.2"
+    tiny-emitter "^2.0.0"
+
 clipboardy@^1.2.2:
   version "1.2.3"
   resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-1.2.3.tgz#0526361bf78724c1f20be248d428e365433c07ef"
@@ -3671,6 +3680,13 @@ codeclimate-test-reporter@^0.5.1:
     lcov-parse "0.0.10"
     request "~2.88.0"
 
+codeflask@1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/codeflask/-/codeflask-1.4.0.tgz#71a349368cb6ba3d12f5da286ed4f39627a62c62"
+  integrity sha512-b2v30UmlapvddFATHzf+xIQ5q6+ONKvQJUtyziO1OuKQgnFyv0pn6eGxJntp0pGldzMA+nXX0Ff6Y1a8odrRtA==
+  dependencies:
+    prismjs "^1.14.0"
+
 collection-visit@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
@@ -4492,6 +4508,11 @@ delayed-stream@~1.0.0:
   resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
   integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
 
+delegate@^3.1.2:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
+  integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==
+
 delegates@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
@@ -6011,6 +6032,13 @@ gonzales-pe@^4.2.3:
   dependencies:
     minimist "1.1.x"
 
+good-listener@^1.2.2:
+  version "1.2.2"
+  resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
+  integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=
+  dependencies:
+    delegate "^3.1.2"
+
 got@^6.7.1:
   version "6.7.1"
   resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
@@ -10581,6 +10609,13 @@ pretty-format@^23.6.0:
     ansi-regex "^3.0.0"
     ansi-styles "^3.2.0"
 
+prismjs@^1.14.0:
+  version "1.15.0"
+  resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.15.0.tgz#8801d332e472091ba8def94976c8877ad60398d9"
+  integrity sha512-Lf2JrFYx8FanHrjoV5oL8YHCclLQgbJcVZR+gikGGMqz6ub5QVWDTM6YIwm3BuPxM/LOV+rKns3LssXNLIf+DA==
+  optionalDependencies:
+    clipboard "^2.0.0"
+
 private@^0.1.6, private@~0.1.5:
   version "0.1.8"
   resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
@@ -11671,6 +11706,11 @@ schema-utils@^1.0.0:
     ajv-errors "^1.0.0"
     ajv-keywords "^3.1.0"
 
+select@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
+  integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=
+
 semantic-ui-css@^2.3.1:
   version "2.4.1"
   resolved "https://registry.yarnpkg.com/semantic-ui-css/-/semantic-ui-css-2.4.1.tgz#f5aea39fafb787cbd905ec724272a3f9cba9004a"
@@ -12619,6 +12659,11 @@ timers-ext@^0.1.5:
     es5-ext "~0.10.46"
     next-tick "1"
 
+tiny-emitter@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.0.2.tgz#82d27468aca5ade8e5fd1e6d22b57dd43ebdfb7c"
+  integrity sha512-2NM0auVBGft5tee/OxP4PI3d8WItkDM+fPnaRAVo6xTDI2knbz9eC5ArWGqtGlYqiH3RU5yMpdyTTO7MguC4ow==
+
 tmp@0.0.31:
   version "0.0.31"
   resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7"