From cd08b816dafd1ad9521ab4029f46f0042683dc91 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Mon, 23 Nov 2020 08:50:29 +0100 Subject: [PATCH 01/99] Scaffold file explorer react app --- libs/remix-ui/file-explorer/.babelrc | 4 + libs/remix-ui/file-explorer/.eslintrc | 248 ++++++++++++++++++ libs/remix-ui/file-explorer/README.md | 7 + libs/remix-ui/file-explorer/src/index.ts | 1 + .../file-explorer/src/lib/file-explorer.css | 0 .../file-explorer/src/lib/file-explorer.tsx | 16 ++ libs/remix-ui/file-explorer/tsconfig.json | 16 ++ libs/remix-ui/file-explorer/tsconfig.lib.json | 13 + nx.json | 3 + package.json | 2 +- tsconfig.json | 3 +- workspace.json | 19 ++ 12 files changed, 330 insertions(+), 2 deletions(-) create mode 100644 libs/remix-ui/file-explorer/.babelrc create mode 100644 libs/remix-ui/file-explorer/.eslintrc create mode 100644 libs/remix-ui/file-explorer/README.md create mode 100644 libs/remix-ui/file-explorer/src/index.ts create mode 100644 libs/remix-ui/file-explorer/src/lib/file-explorer.css create mode 100644 libs/remix-ui/file-explorer/src/lib/file-explorer.tsx create mode 100644 libs/remix-ui/file-explorer/tsconfig.json create mode 100644 libs/remix-ui/file-explorer/tsconfig.lib.json diff --git a/libs/remix-ui/file-explorer/.babelrc b/libs/remix-ui/file-explorer/.babelrc new file mode 100644 index 0000000000..09d67939cc --- /dev/null +++ b/libs/remix-ui/file-explorer/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["@nrwl/react/babel"], + "plugins": [] +} diff --git a/libs/remix-ui/file-explorer/.eslintrc b/libs/remix-ui/file-explorer/.eslintrc new file mode 100644 index 0000000000..977f139a09 --- /dev/null +++ b/libs/remix-ui/file-explorer/.eslintrc @@ -0,0 +1,248 @@ +{ + "rules": { + "array-callback-return": "warn", + "dot-location": ["warn", "property"], + "eqeqeq": ["warn", "smart"], + "new-parens": "warn", + "no-caller": "warn", + "no-cond-assign": ["warn", "except-parens"], + "no-const-assign": "warn", + "no-control-regex": "warn", + "no-delete-var": "warn", + "no-dupe-args": "warn", + "no-dupe-keys": "warn", + "no-duplicate-case": "warn", + "no-empty-character-class": "warn", + "no-empty-pattern": "warn", + "no-eval": "warn", + "no-ex-assign": "warn", + "no-extend-native": "warn", + "no-extra-bind": "warn", + "no-extra-label": "warn", + "no-fallthrough": "warn", + "no-func-assign": "warn", + "no-implied-eval": "warn", + "no-invalid-regexp": "warn", + "no-iterator": "warn", + "no-label-var": "warn", + "no-labels": ["warn", { "allowLoop": true, "allowSwitch": false }], + "no-lone-blocks": "warn", + "no-loop-func": "warn", + "no-mixed-operators": [ + "warn", + { + "groups": [ + ["&", "|", "^", "~", "<<", ">>", ">>>"], + ["==", "!=", "===", "!==", ">", ">=", "<", "<="], + ["&&", "||"], + ["in", "instanceof"] + ], + "allowSamePrecedence": false + } + ], + "no-multi-str": "warn", + "no-native-reassign": "warn", + "no-negated-in-lhs": "warn", + "no-new-func": "warn", + "no-new-object": "warn", + "no-new-symbol": "warn", + "no-new-wrappers": "warn", + "no-obj-calls": "warn", + "no-octal": "warn", + "no-octal-escape": "warn", + "no-redeclare": "warn", + "no-regex-spaces": "warn", + "no-restricted-syntax": ["warn", "WithStatement"], + "no-script-url": "warn", + "no-self-assign": "warn", + "no-self-compare": "warn", + "no-sequences": "warn", + "no-shadow-restricted-names": "warn", + "no-sparse-arrays": "warn", + "no-template-curly-in-string": "warn", + "no-this-before-super": "warn", + "no-throw-literal": "warn", + "no-restricted-globals": [ + "error", + "addEventListener", + "blur", + "close", + "closed", + "confirm", + "defaultStatus", + "defaultstatus", + "event", + "external", + "find", + "focus", + "frameElement", + "frames", + "history", + "innerHeight", + "innerWidth", + "length", + "location", + "locationbar", + "menubar", + "moveBy", + "moveTo", + "name", + "onblur", + "onerror", + "onfocus", + "onload", + "onresize", + "onunload", + "open", + "opener", + "opera", + "outerHeight", + "outerWidth", + "pageXOffset", + "pageYOffset", + "parent", + "print", + "removeEventListener", + "resizeBy", + "resizeTo", + "screen", + "screenLeft", + "screenTop", + "screenX", + "screenY", + "scroll", + "scrollbars", + "scrollBy", + "scrollTo", + "scrollX", + "scrollY", + "self", + "status", + "statusbar", + "stop", + "toolbar", + "top" + ], + "no-unexpected-multiline": "warn", + "no-unreachable": "warn", + "no-unused-expressions": [ + "error", + { + "allowShortCircuit": true, + "allowTernary": true, + "allowTaggedTemplates": true + } + ], + "no-unused-labels": "warn", + "no-useless-computed-key": "warn", + "no-useless-concat": "warn", + "no-useless-escape": "warn", + "no-useless-rename": [ + "warn", + { + "ignoreDestructuring": false, + "ignoreImport": false, + "ignoreExport": false + } + ], + "no-with": "warn", + "no-whitespace-before-property": "warn", + "react-hooks/exhaustive-deps": "warn", + "require-yield": "warn", + "rest-spread-spacing": ["warn", "never"], + "strict": ["warn", "never"], + "unicode-bom": ["warn", "never"], + "use-isnan": "warn", + "valid-typeof": "warn", + "no-restricted-properties": [ + "error", + { + "object": "require", + "property": "ensure", + "message": "Please use import() instead. More info: https://facebook.github.io/create-react-app/docs/code-splitting" + }, + { + "object": "System", + "property": "import", + "message": "Please use import() instead. More info: https://facebook.github.io/create-react-app/docs/code-splitting" + } + ], + "getter-return": "warn", + "import/first": "error", + "import/no-amd": "error", + "import/no-webpack-loader-syntax": "error", + "react/forbid-foreign-prop-types": ["warn", { "allowInPropTypes": true }], + "react/jsx-no-comment-textnodes": "warn", + "react/jsx-no-duplicate-props": "warn", + "react/jsx-no-target-blank": "warn", + "react/jsx-no-undef": "error", + "react/jsx-pascal-case": ["warn", { "allowAllCaps": true, "ignore": [] }], + "react/jsx-uses-react": "warn", + "react/jsx-uses-vars": "warn", + "react/no-danger-with-children": "warn", + "react/no-direct-mutation-state": "warn", + "react/no-is-mounted": "warn", + "react/no-typos": "error", + "react/react-in-jsx-scope": "error", + "react/require-render-return": "error", + "react/style-prop-object": "warn", + "react/jsx-no-useless-fragment": "warn", + "jsx-a11y/accessible-emoji": "warn", + "jsx-a11y/alt-text": "warn", + "jsx-a11y/anchor-has-content": "warn", + "jsx-a11y/anchor-is-valid": [ + "warn", + { "aspects": ["noHref", "invalidHref"] } + ], + "jsx-a11y/aria-activedescendant-has-tabindex": "warn", + "jsx-a11y/aria-props": "warn", + "jsx-a11y/aria-proptypes": "warn", + "jsx-a11y/aria-role": "warn", + "jsx-a11y/aria-unsupported-elements": "warn", + "jsx-a11y/heading-has-content": "warn", + "jsx-a11y/iframe-has-title": "warn", + "jsx-a11y/img-redundant-alt": "warn", + "jsx-a11y/no-access-key": "warn", + "jsx-a11y/no-distracting-elements": "warn", + "jsx-a11y/no-redundant-roles": "warn", + "jsx-a11y/role-has-required-aria-props": "warn", + "jsx-a11y/role-supports-aria-props": "warn", + "jsx-a11y/scope": "warn", + "react-hooks/rules-of-hooks": "error", + "default-case": "off", + "no-dupe-class-members": "off", + "no-undef": "off", + "@typescript-eslint/consistent-type-assertions": "warn", + "no-array-constructor": "off", + "@typescript-eslint/no-array-constructor": "warn", + "@typescript-eslint/no-namespace": "error", + "no-use-before-define": "off", + "@typescript-eslint/no-use-before-define": [ + "warn", + { + "functions": false, + "classes": false, + "variables": false, + "typedefs": false + } + ], + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": [ + "warn", + { "args": "none", "ignoreRestSiblings": true } + ], + "no-useless-constructor": "off", + "@typescript-eslint/no-useless-constructor": "warn" + }, + "env": { + "browser": true, + "commonjs": true, + "es6": true, + "jest": true, + "node": true + }, + "settings": { "react": { "version": "detect" } }, + "plugins": ["import", "jsx-a11y", "react", "react-hooks"], + "extends": ["../../../.eslintrc"], + "ignorePatterns": ["!**/*"] +} diff --git a/libs/remix-ui/file-explorer/README.md b/libs/remix-ui/file-explorer/README.md new file mode 100644 index 0000000000..d38b498f59 --- /dev/null +++ b/libs/remix-ui/file-explorer/README.md @@ -0,0 +1,7 @@ +# remix-ui-file-explorer + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test remix-ui-file-explorer` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/libs/remix-ui/file-explorer/src/index.ts b/libs/remix-ui/file-explorer/src/index.ts new file mode 100644 index 0000000000..7f375b8fb6 --- /dev/null +++ b/libs/remix-ui/file-explorer/src/index.ts @@ -0,0 +1 @@ +export * from './lib/file-explorer' diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.css b/libs/remix-ui/file-explorer/src/lib/file-explorer.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx new file mode 100644 index 0000000000..2582096189 --- /dev/null +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -0,0 +1,16 @@ +import React from 'react' + +import './remix-ui-file-explorer.css' + +/* eslint-disable-next-line */ +export interface FileExplorerProps {} + +export const FileExplorer = (props: FileExplorerProps) => { + return ( +
+

Welcome to file-explorer!

+
+ ) +} + +export default FileExplorer diff --git a/libs/remix-ui/file-explorer/tsconfig.json b/libs/remix-ui/file-explorer/tsconfig.json new file mode 100644 index 0000000000..6b65264565 --- /dev/null +++ b/libs/remix-ui/file-explorer/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "jsx": "react", + "allowJs": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + } + ] +} diff --git a/libs/remix-ui/file-explorer/tsconfig.lib.json b/libs/remix-ui/file-explorer/tsconfig.lib.json new file mode 100644 index 0000000000..b560bc4dec --- /dev/null +++ b/libs/remix-ui/file-explorer/tsconfig.lib.json @@ -0,0 +1,13 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "types": ["node"] + }, + "files": [ + "../../../node_modules/@nrwl/react/typings/cssmodule.d.ts", + "../../../node_modules/@nrwl/react/typings/image.d.ts" + ], + "exclude": ["**/*.spec.ts", "**/*.spec.tsx"], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/nx.json b/nx.json index e27c2d38e4..4f324dd6cf 100644 --- a/nx.json +++ b/nx.json @@ -86,6 +86,9 @@ }, "remix-ui-toaster": { "tags": [] + }, + "remix-ui-file-explorer": { + "tags": [] } } } diff --git a/package.json b/package.json index affda60c1f..030cea751f 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "workspace-schematic": "nx workspace-schematic", "dep-graph": "nx dep-graph", "help": "nx help", - "lint:libs": "nx run-many --target=lint --projects=remixd,remix-ui-modal-dialog,remix-ui-toaster", + "lint:libs": "nx run-many --target=lint --projects=remixd,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-file-explorer", "build:libs": "nx run-many --target=build --parallel=false --with-deps=true --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd", "test:libs": "nx run-many --target=test --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd", "publish:libs": "npm run build:libs & lerna publish --skip-git & npm run bumpVersion:libs", diff --git a/tsconfig.json b/tsconfig.json index 07d617152b..f267d32ab8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -33,7 +33,8 @@ "@remix-ui/clipboard": ["libs/remix-ui/clipboard/src/index.ts"], "@remix-project/remix-solidity-ts": ["libs/remix-solidity/src/index.ts"], "@remix-ui/modal-dialog": ["libs/remix-ui/modal-dialog/src/index.ts"], - "@remix-ui/toaster": ["libs/remix-ui/toaster/src/index.ts"] + "@remix-ui/toaster": ["libs/remix-ui/toaster/src/index.ts"], + "@remix-ui/file-explorer": ["libs/remix-ui/file-explorer/src/index.ts"] } }, "exclude": ["node_modules", "tmp"] diff --git a/workspace.json b/workspace.json index 6f6935c308..4fb9bbd36c 100644 --- a/workspace.json +++ b/workspace.json @@ -617,6 +617,25 @@ } } } + }, + "remix-ui-file-explorer": { + "root": "libs/remix-ui/file-explorer", + "sourceRoot": "libs/remix-ui/file-explorer/src", + "projectType": "library", + "schematics": {}, + "architect": { + "lint": { + "builder": "@nrwl/linter:lint", + "options": { + "linter": "eslint", + "tsConfig": ["libs/remix-ui/file-explorer/tsconfig.lib.json"], + "exclude": [ + "**/node_modules/**", + "!libs/remix-ui/file-explorer/**/*" + ] + } + } + } } }, "cli": { From eb353fa5961a1419d8817fdf919a39de49724503 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Mon, 23 Nov 2020 12:32:03 +0100 Subject: [PATCH 02/99] File Explorer barebone --- apps/remix-ide/src/app/panels/file-panel.js | 14 +- libs/remix-ui/file-explorer/.eslintrc | 261 ++---------------- .../file-explorer/src/lib/file-explorer.css | 55 ++++ .../file-explorer/src/lib/file-explorer.tsx | 170 +++++++++++- .../file-explorer/src/lib/types/index.ts | 7 + 5 files changed, 254 insertions(+), 253 deletions(-) create mode 100644 libs/remix-ui/file-explorer/src/lib/types/index.ts diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js index e210ca8ef0..9a5ad3b135 100644 --- a/apps/remix-ide/src/app/panels/file-panel.js +++ b/apps/remix-ide/src/app/panels/file-panel.js @@ -1,9 +1,12 @@ import { ViewPlugin } from '@remixproject/engine-web' import * as packageJson from '../../../../../package.json' +import React from 'react' // eslint-disable-line +import ReactDOM from 'react-dom' +import { FileExplorer } from '@remix-ui/file-explorer' var yo = require('yo-yo') var EventManager = require('../../lib/events') -var FileExplorer = require('../files/file-explorer') +// var FileExplorer = require('../files/file-explorer') var { RemixdHandle } = require('../files/remixd-handle.js') var { GitHandle } = require('../files/git-handle.js') var globalRegistry = require('../../global/registry') @@ -54,13 +57,18 @@ module.exports = class Filepanel extends ViewPlugin { } function createProvider (key, menuItems) { - return new FileExplorer(self._components.registry, self._deps.fileProviders[key], menuItems, self) + return } var fileExplorer = createProvider('browser', ['createNewFile', 'publishToGist', canUpload ? 'uploadFile' : '']) var fileSystemExplorer = createProvider('localhost') - self.remixdHandle = new RemixdHandle(fileSystemExplorer, self._deps.fileProviders.localhost, appManager) + // self.remixdHandle = new RemixdHandle(fileSystemExplorer, self._deps.fileProviders.localhost, appManager) self.gitHandle = new GitHandle() const explorers = yo` diff --git a/libs/remix-ui/file-explorer/.eslintrc b/libs/remix-ui/file-explorer/.eslintrc index 977f139a09..dae5c6feeb 100644 --- a/libs/remix-ui/file-explorer/.eslintrc +++ b/libs/remix-ui/file-explorer/.eslintrc @@ -1,248 +1,19 @@ { - "rules": { - "array-callback-return": "warn", - "dot-location": ["warn", "property"], - "eqeqeq": ["warn", "smart"], - "new-parens": "warn", - "no-caller": "warn", - "no-cond-assign": ["warn", "except-parens"], - "no-const-assign": "warn", - "no-control-regex": "warn", - "no-delete-var": "warn", - "no-dupe-args": "warn", - "no-dupe-keys": "warn", - "no-duplicate-case": "warn", - "no-empty-character-class": "warn", - "no-empty-pattern": "warn", - "no-eval": "warn", - "no-ex-assign": "warn", - "no-extend-native": "warn", - "no-extra-bind": "warn", - "no-extra-label": "warn", - "no-fallthrough": "warn", - "no-func-assign": "warn", - "no-implied-eval": "warn", - "no-invalid-regexp": "warn", - "no-iterator": "warn", - "no-label-var": "warn", - "no-labels": ["warn", { "allowLoop": true, "allowSwitch": false }], - "no-lone-blocks": "warn", - "no-loop-func": "warn", - "no-mixed-operators": [ - "warn", - { - "groups": [ - ["&", "|", "^", "~", "<<", ">>", ">>>"], - ["==", "!=", "===", "!==", ">", ">=", "<", "<="], - ["&&", "||"], - ["in", "instanceof"] - ], - "allowSamePrecedence": false - } - ], - "no-multi-str": "warn", - "no-native-reassign": "warn", - "no-negated-in-lhs": "warn", - "no-new-func": "warn", - "no-new-object": "warn", - "no-new-symbol": "warn", - "no-new-wrappers": "warn", - "no-obj-calls": "warn", - "no-octal": "warn", - "no-octal-escape": "warn", - "no-redeclare": "warn", - "no-regex-spaces": "warn", - "no-restricted-syntax": ["warn", "WithStatement"], - "no-script-url": "warn", - "no-self-assign": "warn", - "no-self-compare": "warn", - "no-sequences": "warn", - "no-shadow-restricted-names": "warn", - "no-sparse-arrays": "warn", - "no-template-curly-in-string": "warn", - "no-this-before-super": "warn", - "no-throw-literal": "warn", - "no-restricted-globals": [ - "error", - "addEventListener", - "blur", - "close", - "closed", - "confirm", - "defaultStatus", - "defaultstatus", - "event", - "external", - "find", - "focus", - "frameElement", - "frames", - "history", - "innerHeight", - "innerWidth", - "length", - "location", - "locationbar", - "menubar", - "moveBy", - "moveTo", - "name", - "onblur", - "onerror", - "onfocus", - "onload", - "onresize", - "onunload", - "open", - "opener", - "opera", - "outerHeight", - "outerWidth", - "pageXOffset", - "pageYOffset", - "parent", - "print", - "removeEventListener", - "resizeBy", - "resizeTo", - "screen", - "screenLeft", - "screenTop", - "screenX", - "screenY", - "scroll", - "scrollbars", - "scrollBy", - "scrollTo", - "scrollX", - "scrollY", - "self", - "status", - "statusbar", - "stop", - "toolbar", - "top" - ], - "no-unexpected-multiline": "warn", - "no-unreachable": "warn", - "no-unused-expressions": [ - "error", - { - "allowShortCircuit": true, - "allowTernary": true, - "allowTaggedTemplates": true - } - ], - "no-unused-labels": "warn", - "no-useless-computed-key": "warn", - "no-useless-concat": "warn", - "no-useless-escape": "warn", - "no-useless-rename": [ - "warn", - { - "ignoreDestructuring": false, - "ignoreImport": false, - "ignoreExport": false - } - ], - "no-with": "warn", - "no-whitespace-before-property": "warn", - "react-hooks/exhaustive-deps": "warn", - "require-yield": "warn", - "rest-spread-spacing": ["warn", "never"], - "strict": ["warn", "never"], - "unicode-bom": ["warn", "never"], - "use-isnan": "warn", - "valid-typeof": "warn", - "no-restricted-properties": [ - "error", - { - "object": "require", - "property": "ensure", - "message": "Please use import() instead. More info: https://facebook.github.io/create-react-app/docs/code-splitting" - }, - { - "object": "System", - "property": "import", - "message": "Please use import() instead. More info: https://facebook.github.io/create-react-app/docs/code-splitting" - } - ], - "getter-return": "warn", - "import/first": "error", - "import/no-amd": "error", - "import/no-webpack-loader-syntax": "error", - "react/forbid-foreign-prop-types": ["warn", { "allowInPropTypes": true }], - "react/jsx-no-comment-textnodes": "warn", - "react/jsx-no-duplicate-props": "warn", - "react/jsx-no-target-blank": "warn", - "react/jsx-no-undef": "error", - "react/jsx-pascal-case": ["warn", { "allowAllCaps": true, "ignore": [] }], - "react/jsx-uses-react": "warn", - "react/jsx-uses-vars": "warn", - "react/no-danger-with-children": "warn", - "react/no-direct-mutation-state": "warn", - "react/no-is-mounted": "warn", - "react/no-typos": "error", - "react/react-in-jsx-scope": "error", - "react/require-render-return": "error", - "react/style-prop-object": "warn", - "react/jsx-no-useless-fragment": "warn", - "jsx-a11y/accessible-emoji": "warn", - "jsx-a11y/alt-text": "warn", - "jsx-a11y/anchor-has-content": "warn", - "jsx-a11y/anchor-is-valid": [ - "warn", - { "aspects": ["noHref", "invalidHref"] } - ], - "jsx-a11y/aria-activedescendant-has-tabindex": "warn", - "jsx-a11y/aria-props": "warn", - "jsx-a11y/aria-proptypes": "warn", - "jsx-a11y/aria-role": "warn", - "jsx-a11y/aria-unsupported-elements": "warn", - "jsx-a11y/heading-has-content": "warn", - "jsx-a11y/iframe-has-title": "warn", - "jsx-a11y/img-redundant-alt": "warn", - "jsx-a11y/no-access-key": "warn", - "jsx-a11y/no-distracting-elements": "warn", - "jsx-a11y/no-redundant-roles": "warn", - "jsx-a11y/role-has-required-aria-props": "warn", - "jsx-a11y/role-supports-aria-props": "warn", - "jsx-a11y/scope": "warn", - "react-hooks/rules-of-hooks": "error", - "default-case": "off", - "no-dupe-class-members": "off", - "no-undef": "off", - "@typescript-eslint/consistent-type-assertions": "warn", - "no-array-constructor": "off", - "@typescript-eslint/no-array-constructor": "warn", - "@typescript-eslint/no-namespace": "error", - "no-use-before-define": "off", - "@typescript-eslint/no-use-before-define": [ - "warn", - { - "functions": false, - "classes": false, - "variables": false, - "typedefs": false - } - ], - "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": [ - "warn", - { "args": "none", "ignoreRestSiblings": true } - ], - "no-useless-constructor": "off", - "@typescript-eslint/no-useless-constructor": "warn" - }, "env": { - "browser": true, - "commonjs": true, - "es6": true, - "jest": true, - "node": true + "browser": true, + "es6": true + }, + "extends": "../../../.eslintrc", + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" }, - "settings": { "react": { "version": "detect" } }, - "plugins": ["import", "jsx-a11y", "react", "react-hooks"], - "extends": ["../../../.eslintrc"], - "ignorePatterns": ["!**/*"] -} + "parserOptions": { + "ecmaVersion": 11, + "sourceType": "module" + }, + "rules": { + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": "error" + } +} diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.css b/libs/remix-ui/file-explorer/src/lib/file-explorer.css index e69de29bb2..360834289f 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.css +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.css @@ -0,0 +1,55 @@ +.remixui_label { + margin-top : 4px; +} +.remixui_leaf { + overflow : hidden; + text-overflow : ellipsis; + width : 90%; + margin-bottom : 0px; +} +.remixui_fileexplorer { + box-sizing : border-box; +} +input[type="file"] { + display: none; +} +.remixui_folder, +.remixui_file { + font-size : 14px; + cursor : pointer; +} +.remixui_file { + padding : 4px; +} +.remixui_newFile { + padding-right : 10px; +} +.remixui_newFile i { + cursor : pointer; +} +.remixui_newFile:hover { + transform : scale(1.3); +} +.remixui_menu { + margin-left : 20px; +} +.remixui_items { + display : inline +} +.remixui_remove { + margin-left : auto; + padding-left : 5px; + padding-right : 5px; +} +.remixui_activeMode { + display : flex; + width : 100%; + margin-right : 10px; + padding-right : 19px; +} +.remixui_activeMode > div { + min-width : 10px; +} +ul { + padding : 0; +} \ No newline at end of file diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 2582096189..5d5e31b9fa 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -1,14 +1,174 @@ -import React from 'react' +import React, { useReducer, useState } from 'react' // eslint-disable-line +import { TreeView, TreeViewItem } from '@remix-ui/tree-view' +import * as helper from '../../../../../apps/remix-ide/src/lib/helper' +import { FileExplorerProps } from './types' -import './remix-ui-file-explorer.css' +import './file-explorer.css' -/* eslint-disable-next-line */ -export interface FileExplorerProps {} +function extractData (value, tree, key) { + const newValue = {} + let isFile = false + + Object.keys(value).filter((x) => { + if (x === '/content') isFile = true + if (x[0] !== '/') return true + }).forEach((x) => { newValue[x] = value[x] }) + + return { + path: (tree || {}).path ? tree.path + '/' + key : key, + children: isFile ? undefined + : value instanceof Array ? value.map((item, index) => ({ + key: index, value: item + })) : value instanceof Object ? Object.keys(value).map(subkey => ({ + key: subkey, value: value[subkey] + })) : undefined + } +} export const FileExplorer = (props: FileExplorerProps) => { + const [state, setState] = useState({ + files: props.files, + focusElement: null, + focusPath: null, + menuItems: [ + { + action: 'createNewFile', + title: 'Create New File', + icon: 'fas fa-plus-circle' + }, + { + action: 'publishToGist', + title: 'Publish all [browser] explorer files to a github gist', + icon: 'fab fa-github' + }, + { + action: 'uploadFile', + title: 'Add Local file to the Browser Storage Explorer', + icon: 'far fa-folder-open' + }, + { + action: 'updateGist', + title: 'Update the current [gist] explorer', + icon: 'fab fa-github' + } + ].filter(item => props.menuItems && props.menuItems.find((name) => { return name === item.action })) + }) + + const formatSelf = (key, data, li) => { + const isRoot = data.path === state.files.type + const isFolder = !!data.children + + return ( +
+ + {key.split('/').pop()} + + {isRoot ? renderMenuItems() : ''} +
+ ) + } + + const remixdDialog = () => { + return
This file has been changed outside of Remix IDE.
+ } + + const fileRenamedError = (error) => { + console.log(error) + // modalDialogCustom.alert(error) + } + + const extractNameFromKey = (key) => { + const keyPath = key.split('/') + + return keyPath[keyPath.length - 1] + } + + const renderMenuItems = () => { + let items + if (state.menuItems) { + items = state.menuItems.map(({ action, title, icon }) => { + if (action === 'uploadFile') { + return ( + + ) + } else { + return ( + { stopPropagation(); this[action]() }} + className={'newFile ' + icon + ' remixui_newFile'} + title={title} + > + + ) + } + }) + } + return {items} + } + + const uploadFile = (target) => { + // TODO The file explorer is merely a view on the current state of + // the files module. Please ask the user here if they want to overwrite + // a file and then just use `files.add`. The file explorer will + // pick that up via the 'fileAdded' event from the files module. + + ;[...target.files].forEach((file) => { + const files = state.files + + function loadFile () { + const fileReader = new FileReader() + + fileReader.onload = async function (event) { + if (helper.checkSpecialChars(file.name)) { + // modalDialogCustom.alert('Special characters are not allowed') + return + } + const success = await files.set(name, event.target.result) + + if (!success) { + // modalDialogCustom.alert('Failed to create file ' + name) + } else { + // self.events.trigger('focus', [name]) + } + } + fileReader.readAsText(file) + } + const name = files.type + '/' + file.name + + files.exists(name, (error, exist) => { + if (error) console.log(error) + if (!exist) { + loadFile() + } else { + // modalDialogCustom.confirm('Confirm overwrite', `The file ${name} already exists! Would you like to overwrite it?`, () => { loadFile() }) + } + }) + }) + } + return (
-

Welcome to file-explorer!

+
) } diff --git a/libs/remix-ui/file-explorer/src/lib/types/index.ts b/libs/remix-ui/file-explorer/src/lib/types/index.ts new file mode 100644 index 0000000000..3886bd86af --- /dev/null +++ b/libs/remix-ui/file-explorer/src/lib/types/index.ts @@ -0,0 +1,7 @@ +/* eslint-disable-next-line */ +export interface FileExplorerProps { + localRegistry: any, + files: any, + menuItems?: string[], + plugin: any +} From 2c32becfc7d5d9d7339380802e53c113aa94aada Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 25 Nov 2020 09:55:32 +0100 Subject: [PATCH 03/99] Display menu items --- apps/remix-ide/src/app/panels/file-panel.js | 102 ++++++++-------- .../app/panels/styles/file-panel-styles.css | 56 +++++++++ .../src/lib/{ => css}/file-explorer.css | 0 .../file-explorer/src/lib/file-explorer.tsx | 109 +++++++++++++++--- .../file-explorer/src/lib/types/index.ts | 1 + 5 files changed, 203 insertions(+), 65 deletions(-) create mode 100644 apps/remix-ide/src/app/panels/styles/file-panel-styles.css rename libs/remix-ui/file-explorer/src/lib/{ => css}/file-explorer.css (100%) diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js index 9a5ad3b135..08d4602aa5 100644 --- a/apps/remix-ide/src/app/panels/file-panel.js +++ b/apps/remix-ide/src/app/panels/file-panel.js @@ -3,14 +3,14 @@ import { ViewPlugin } from '@remixproject/engine-web' import * as packageJson from '../../../../../package.json' import React from 'react' // eslint-disable-line import ReactDOM from 'react-dom' -import { FileExplorer } from '@remix-ui/file-explorer' +import { FileExplorer } from '@remix-ui/file-explorer' // eslint-disable-line +import './styles/file-panel-styles.css' var yo = require('yo-yo') var EventManager = require('../../lib/events') // var FileExplorer = require('../files/file-explorer') var { RemixdHandle } = require('../files/remixd-handle.js') var { GitHandle } = require('../files/git-handle.js') var globalRegistry = require('../../global/registry') -var css = require('./styles/file-panel-styles') var canUpload = window.File || window.FileReader || window.FileList || window.Blob @@ -47,68 +47,72 @@ const profile = { module.exports = class Filepanel extends ViewPlugin { constructor (appManager) { super(profile) - var self = this - self._components = {} - self._components.registry = globalRegistry - self._deps = { - fileProviders: self._components.registry.get('fileproviders').api, - fileManager: self._components.registry.get('filemanager').api, - config: self._components.registry.get('config').api + this._components = {} + this._components.registry = globalRegistry + this._deps = { + fileProviders: this._components.registry.get('fileproviders').api, + fileManager: this._components.registry.get('filemanager').api, + config: this._components.registry.get('config').api } - - function createProvider (key, menuItems) { - return - } - - var fileExplorer = createProvider('browser', ['createNewFile', 'publishToGist', canUpload ? 'uploadFile' : '']) - var fileSystemExplorer = createProvider('localhost') - - // self.remixdHandle = new RemixdHandle(fileSystemExplorer, self._deps.fileProviders.localhost, appManager) - self.gitHandle = new GitHandle() - - const explorers = yo` -
-
${fileExplorer.init()}
-
${fileSystemExplorer.init()}
+ this.el = yo` +
` - function template () { - return yo` -
-
-
- ${explorers} -
-
-
- ` - } + this.remixdHandle = new RemixdHandle({}, this._deps.fileProviders.localhost, appManager) - var event = new EventManager() - self.event = event - var element = template() - fileExplorer.ensureRoot() - self._deps.fileProviders.localhost.event.register('connecting', (event) => { + this.event = new EventManager() + // fileExplorer.ensureRoot() + this._deps.fileProviders.localhost.event.register('connecting', (event) => { }) - self._deps.fileProviders.localhost.event.register('connected', (event) => { + this._deps.fileProviders.localhost.event.register('connected', (event) => { fileSystemExplorer.show() }) - self._deps.fileProviders.localhost.event.register('errored', (event) => { + this._deps.fileProviders.localhost.event.register('errored', (event) => { fileSystemExplorer.hide() }) - self._deps.fileProviders.localhost.event.register('closed', (event) => { + this._deps.fileProviders.localhost.event.register('closed', (event) => { fileSystemExplorer.hide() }) - self.render = function render () { return element } + this.renderComponent() + } + + render () { + return this.el + } + + renderComponent () { + ReactDOM.render( +
+
+
+
+
+ +
+
+ +
+
+
+
+
+ , this.el) } } diff --git a/apps/remix-ide/src/app/panels/styles/file-panel-styles.css b/apps/remix-ide/src/app/panels/styles/file-panel-styles.css new file mode 100644 index 0000000000..087c59e8e3 --- /dev/null +++ b/apps/remix-ide/src/app/panels/styles/file-panel-styles.css @@ -0,0 +1,56 @@ +.remixui_container { + display : flex; + flex-direction : row; + width : 100%; + height : 100%; + box-sizing : border-box; +} +.remixui_fileexplorer { + display : flex; + flex-direction : column; + position : relative; + width : 100%; + padding-left : 6px; + padding-top : 6px; +} +.remixui_fileExplorerTree { + cursor : default; +} +.remixui_gist { + padding : 10px; +} +.remixui_gist i { + cursor : pointer; +} +.remixui_gist i:hover { + color : orange; +} +.remixui_connectToLocalhost { + padding : 10px; +} +.remixui_connectToLocalhost i { + cursor : pointer; +} +.remixui_connectToLocalhost i:hover { + color : var(--secondary) +} +.remixui_uploadFile { + padding : 10px; +} +.remixui_uploadFile label:hover { + color : var(--secondary) +} +.remixui_uploadFile label { + cursor : pointer; +} +.remixui_treeview { + overflow-y : auto; +} +.remixui_dialog { + display: flex; + flex-direction: column; +} +.remixui_dialogParagraph { + margin-bottom: 2em; + word-break: break-word; +} diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.css b/libs/remix-ui/file-explorer/src/lib/css/file-explorer.css similarity index 100% rename from libs/remix-ui/file-explorer/src/lib/file-explorer.css rename to libs/remix-ui/file-explorer/src/lib/css/file-explorer.css diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 5d5e31b9fa..9ce6041200 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -1,9 +1,9 @@ -import React, { useReducer, useState } from 'react' // eslint-disable-line -import { TreeView, TreeViewItem } from '@remix-ui/tree-view' +import React, { useEffect, useState } from 'react' // eslint-disable-line +import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line import * as helper from '../../../../../apps/remix-ide/src/lib/helper' import { FileExplorerProps } from './types' -import './file-explorer.css' +import './css/file-explorer.css' function extractData (value, tree, key) { const newValue = {} @@ -54,34 +54,100 @@ export const FileExplorer = (props: FileExplorerProps) => { ].filter(item => props.menuItems && props.menuItems.find((name) => { return name === item.action })) }) + useEffect(() => { + if (props.files) { + console.log('props.files.type: ', props.files.type) + props.files.event.register('fileAdded', fileAdded) + } + }, [props.files]) + const formatSelf = (key, data, li) => { - const isRoot = data.path === state.files.type const isFolder = !!data.children return (
{key.split('/').pop()} - {isRoot ? renderMenuItems() : ''}
) } - const remixdDialog = () => { - return
This file has been changed outside of Remix IDE.
- } - - const fileRenamedError = (error) => { - console.log(error) - // modalDialogCustom.alert(error) + // self._components = {} + // self._components.registry = localRegistry || globalRegistry + // self._deps = { + // config: self._components.registry.get('config').api, + // editor: self._components.registry.get('editor').api, + // fileManager: self._components.registry.get('filemanager').api + // } + + // self.events.register('focus', function (path) { + // self._deps.fileManager.open(path) + // }) + + // self._components.registry.put({ api: self, name: `fileexplorer/${self.files.type}` }) + + // warn if file changed outside of Remix + // function remixdDialog () { + // return yo`
This file has been changed outside of Remix IDE.
` + // } + + // props.files.event.register('fileExternallyChanged', (path, file) => { + // if (self._deps.config.get('currentFile') === path && self._deps.editor.currentContent() && self._deps.editor.currentContent() !== file.content) { + // if (this.files.isReadOnly(path)) return self._deps.editor.setText(file.content) + + // modalDialog(path + ' changed', remixdDialog(), + // { + // label: 'Replace by the new content', + // fn: () => { + // self._deps.editor.setText(file.content) + // } + // }, + // { + // label: 'Keep the content displayed in Remix', + // fn: () => {} + // } + // ) + // } + // }) + + // register to event of the file provider + // files.event.register('fileRemoved', fileRemoved) + // files.event.register('fileRenamed', fileRenamed) + // files.event.register('fileRenamedError', fileRenamedError) + // files.event.register('fileAdded', fileAdded) + // files.event.register('folderAdded', folderAdded) + + // function fileRenamedError (error) { + // modalDialogCustom.alert(error) + // } + + const fileAdded = (filepath) => { + const folderpath = filepath.split('/').slice(0, -1).join('/') + console.log('filePath: ', folderpath) + console.log('folderPath: ', folderpath) + // const currentTree = self.treeView.nodeAt(folderpath) + // if (!self.treeView.isExpanded(folderpath)) self.treeView.expand(folderpath) + // if (currentTree) { + // props.files.resolveDirectory(folderpath, (error, fileTree) => { + // if (error) console.error(error) + // if (!fileTree) return + // fileTree = normalize(folderpath, fileTree) + // self.treeView.updateNodeFromJSON(folderpath, fileTree, true) + // self.focusElement = self.treeView.labelAt(self.focusPath) + // // TODO: here we update the selected file (it applicable) + // // cause we are refreshing the interface of the whole directory when there's a new file. + // if (self.focusElement && !self.focusElement.classList.contains('bg-secondary')) { + // self.focusElement.classList.add('bg-secondary') + // } + // }) + // } } const extractNameFromKey = (key) => { @@ -93,7 +159,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const renderMenuItems = () => { let items if (state.menuItems) { - items = state.menuItems.map(({ action, title, icon }) => { + items = state.menuItems.map(({ action, title, icon }, index) => { if (action === 'uploadFile') { return (
diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 9ce6041200..c851a10e84 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -5,29 +5,76 @@ import { FileExplorerProps } from './types' import './css/file-explorer.css' -function extractData (value, tree, key) { - const newValue = {} - let isFile = false - - Object.keys(value).filter((x) => { - if (x === '/content') isFile = true - if (x[0] !== '/') return true - }).forEach((x) => { newValue[x] = value[x] }) - - return { - path: (tree || {}).path ? tree.path + '/' + key : key, - children: isFile ? undefined - : value instanceof Array ? value.map((item, index) => ({ - key: index, value: item - })) : value instanceof Object ? Object.keys(value).map(subkey => ({ - key: subkey, value: value[subkey] - })) : undefined +export const FileExplorer = (props: FileExplorerProps) => { + const { files, name, registry } = props + const uploadFile = (target) => { + // TODO The file explorer is merely a view on the current state of + // the files module. Please ask the user here if they want to overwrite + // a file and then just use `files.add`. The file explorer will + // pick that up via the 'fileAdded' event from the files module. + + [...target.files].forEach((file) => { + const files = props.files + + function loadFile () { + const fileReader = new FileReader() + + fileReader.onload = async function (event) { + if (helper.checkSpecialChars(file.name)) { + // modalDialogCustom.alert('Special characters are not allowed') + return + } + const success = await files.set(name, event.target.result) + + if (!success) { + // modalDialogCustom.alert('Failed to create file ' + name) + } else { + // self.events.trigger('focus', [name]) + } + } + fileReader.readAsText(file) + } + const name = files.type + '/' + file.name + + files.exists(name, (error, exist) => { + if (error) console.log(error) + if (!exist) { + loadFile() + } else { + // modalDialogCustom.confirm('Confirm overwrite', `The file ${name} already exists! Would you like to overwrite it?`, () => { loadFile() }) + } + }) + }) + } + const publishToGist = () => { + // modalDialogCustom.confirm( + // 'Create a public gist', + // 'Are you sure you want to publish all your files in browser directory anonymously as a public gist on github.com? Note: this will not include directories.', + // () => { this.toGist() } + // ) + } + const createNewFile = (parentFolder = 'browser') => { + // const self = this + // modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => { + // if (!input) input = 'New file' + // helper.createNonClashingName(parentFolder + '/' + input, self.files, async (error, newName) => { + // if (error) return tooltip('Failed to create file ' + newName + ' ' + error) + // const fileManager = self._deps.fileManager + // const createFile = await fileManager.writeFile(newName, '') + + // if (!createFile) { + // tooltip('Failed to create file ' + newName) + // } else { + // await fileManager.open(newName) + // if (newName.includes('_test.sol')) { + // self.events.trigger('newTestFileCreated', [newName]) + // } + // } + // }) + // }, null, true) } -} -export const FileExplorer = (props: FileExplorerProps) => { const [state, setState] = useState({ - files: props.files, focusElement: null, focusPath: null, menuItems: [ @@ -51,34 +98,184 @@ export const FileExplorer = (props: FileExplorerProps) => { title: 'Update the current [gist] explorer', icon: 'fab fa-github' } - ].filter(item => props.menuItems && props.menuItems.find((name) => { return name === item.action })) + ].filter(item => props.menuItems && props.menuItems.find((name) => { return name === item.action })), + files: [], + actions: { + updateGist: () => {}, + uploadFile, + publishToGist, + createNewFile + }, + fileManager: null }) useEffect(() => { - if (props.files) { - console.log('props.files.type: ', props.files.type) - props.files.event.register('fileAdded', fileAdded) - } - }, [props.files]) + const fileManager = registry.get('filemanager').api + + setState(prevState => { + return { ...prevState, fileManager } + }) + resolveDirectory(name) + }, []) + + const resolveDirectory = (folderPath) => { + const folderIndex = state.files.findIndex(({ path }) => path === folderPath) + + if (folderIndex === -1) { + files.resolveDirectory(folderPath, (error, fileTree) => { + if (error) console.error(error) + const files = normalize(folderPath, fileTree) + + setState(prevState => { + return { ...prevState, files } + }) + }) + } else { + files.resolveDirectory(folderPath, (error, fileTree) => { + if (error) console.error(error) + const files = state.files - const formatSelf = (key, data, li) => { - const isFolder = !!data.children + files[folderIndex].child = normalize(folderPath, fileTree) + setState(prevState => { + return { ...prevState, files } + }) + }) + } + } + const label = (data) => { return (
- {key.split('/').pop()} + { data.path.split('/').pop() }
) } + const normalize = (path, filesList) => { + const prefix = path.split('/')[0] + const files = Object.keys(filesList).map(key => { + const path = prefix + '/' + key + + return { + path, + name: extractNameFromKey(path), + isDirectory: filesList[key].isDirectory + } + }) + + return files + } + + const extractNameFromKey = (key) => { + const keyPath = key.split('/') + + return keyPath[keyPath.length - 1] + } + + const toGist = (id) => { + // const proccedResult = function (error, data) { + // if (error) { + // modalDialogCustom.alert('Failed to manage gist: ' + error) + // console.log('Failed to manage gist: ' + error) + // } else { + // if (data.html_url) { + // modalDialogCustom.confirm('Gist is ready', `The gist is at ${data.html_url}. Would you like to open it in a new window?`, () => { + // window.open(data.html_url, '_blank') + // }) + // } else { + // modalDialogCustom.alert(data.message + ' ' + data.documentation_url + ' ' + JSON.stringify(data.errors, null, '\t')) + // } + // } + // } + + // /** + // * This function is to get the original content of given gist + // * @params id is the gist id to fetch + // */ + // async function getOriginalFiles (id) { + // if (!id) { + // return [] + // } + + // const url = `https://api.github.com/gists/${id}` + // const res = await fetch(url) + // const data = await res.json() + // return data.files || [] + // } + + // // If 'id' is not defined, it is not a gist update but a creation so we have to take the files from the browser explorer. + // const folder = id ? 'browser/gists/' + id : 'browser/' + // this.packageFiles(this.files, folder, (error, packaged) => { + // if (error) { + // console.log(error) + // modalDialogCustom.alert('Failed to create gist: ' + error.message) + // } else { + // // check for token + // var tokenAccess = this._deps.config.get('settings/gist-access-token') + // if (!tokenAccess) { + // modalDialogCustom.alert( + // 'Remix requires an access token (which includes gists creation permission). Please go to the settings tab to create one.' + // ) + // } else { + // const description = 'Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. \n Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=' + + // queryParams.get().version + '&optimize=' + queryParams.get().optimize + '&runs=' + queryParams.get().runs + '&gist=' + // const gists = new Gists({ token: tokenAccess }) + + // if (id) { + // const originalFileList = getOriginalFiles(id) + // // Telling the GIST API to remove files + // const updatedFileList = Object.keys(packaged) + // const allItems = Object.keys(originalFileList) + // .filter(fileName => updatedFileList.indexOf(fileName) === -1) + // .reduce((acc, deleteFileName) => ({ + // ...acc, + // [deleteFileName]: null + // }), originalFileList) + // // adding new files + // updatedFileList.forEach((file) => { + // const _items = file.split('/') + // const _fileName = _items[_items.length - 1] + // allItems[_fileName] = packaged[file] + // }) + + // tooltip('Saving gist (' + id + ') ...') + // gists.edit({ + // description: description, + // public: true, + // files: allItems, + // id: id + // }, (error, result) => { + // proccedResult(error, result) + // if (!error) { + // for (const key in allItems) { + // if (allItems[key] === null) delete allItems[key] + // } + // } + // }) + // } else { + // // id is not existing, need to create a new gist + // tooltip('Creating a new gist ...') + // gists.create({ + // description: description, + // public: true, + // files: packaged + // }, (error, result) => { + // proccedResult(error, result) + // }) + // } + // } + // } + // }) + } + // self._components = {} // self._components.registry = localRegistry || globalRegistry // self._deps = { @@ -87,10 +284,6 @@ export const FileExplorer = (props: FileExplorerProps) => { // fileManager: self._components.registry.get('filemanager').api // } - // self.events.register('focus', function (path) { - // self._deps.fileManager.open(path) - // }) - // self._components.registry.put({ api: self, name: `fileexplorer/${self.files.type}` }) // warn if file changed outside of Remix @@ -128,33 +321,25 @@ export const FileExplorer = (props: FileExplorerProps) => { // modalDialogCustom.alert(error) // } - const fileAdded = (filepath) => { - const folderpath = filepath.split('/').slice(0, -1).join('/') - console.log('filePath: ', folderpath) - console.log('folderPath: ', folderpath) - // const currentTree = self.treeView.nodeAt(folderpath) - // if (!self.treeView.isExpanded(folderpath)) self.treeView.expand(folderpath) - // if (currentTree) { - // props.files.resolveDirectory(folderpath, (error, fileTree) => { - // if (error) console.error(error) - // if (!fileTree) return - // fileTree = normalize(folderpath, fileTree) - // self.treeView.updateNodeFromJSON(folderpath, fileTree, true) - // self.focusElement = self.treeView.labelAt(self.focusPath) - // // TODO: here we update the selected file (it applicable) - // // cause we are refreshing the interface of the whole directory when there's a new file. - // if (self.focusElement && !self.focusElement.classList.contains('bg-secondary')) { - // self.focusElement.classList.add('bg-secondary') - // } - // }) - // } - } - - const extractNameFromKey = (key) => { - const keyPath = key.split('/') - - return keyPath[keyPath.length - 1] - } + // const fileAdded = (filepath) => { + // const folderpath = filepath.split('/').slice(0, -1).join('/') + // const currentTree = self.treeView.nodeAt(folderpath) + // if (!self.treeView.isExpanded(folderpath)) self.treeView.expand(folderpath) + // if (currentTree) { + // props.files.resolveDirectory(folderpath, (error, fileTree) => { + // if (error) console.error(error) + // if (!fileTree) return + // fileTree = normalize(folderpath, fileTree) + // self.treeView.updateNodeFromJSON(folderpath, fileTree, true) + // self.focusElement = self.treeView.labelAt(self.focusPath) + // // TODO: here we update the selected file (it applicable) + // // cause we are refreshing the interface of the whole directory when there's a new file. + // if (self.focusElement && !self.focusElement.classList.contains('bg-secondary')) { + // self.focusElement.classList.add('bg-secondary') + // } + // }) + // } + // } const renderMenuItems = () => { let items @@ -181,7 +366,10 @@ export const FileExplorer = (props: FileExplorerProps) => { { stopPropagation(); this[action]() }} + onClick={(e) => { + e.stopPropagation() + state.actions[action]() + }} className={'newFile ' + icon + ' remixui_newFile'} title={title} key={index} @@ -193,57 +381,49 @@ export const FileExplorer = (props: FileExplorerProps) => { } return ( <> - { props.name } + { name } {items} ) } - const uploadFile = (target) => { - // TODO The file explorer is merely a view on the current state of - // the files module. Please ask the user here if they want to overwrite - // a file and then just use `files.add`. The file explorer will - // pick that up via the 'fileAdded' event from the files module. - - ;[...target.files].forEach((file) => { - const files = state.files - - function loadFile () { - const fileReader = new FileReader() - - fileReader.onload = async function (event) { - if (helper.checkSpecialChars(file.name)) { - // modalDialogCustom.alert('Special characters are not allowed') - return + const renderFiles = (file, index) => { + if (file.isDirectory) { + return ( + { resolveDirectory(file.path) }} key={index} label={label(file)}> + { + file.child ? { + file.child.map((file, index) => { + return renderFiles(file, index) + }) + } + : } - const success = await files.set(name, event.target.result) - - if (!success) { - // modalDialogCustom.alert('Failed to create file ' + name) - } else { - // self.events.trigger('focus', [name]) - } - } - fileReader.readAsText(file) - } - const name = files.type + '/' + file.name - - files.exists(name, (error, exist) => { - if (error) console.log(error) - if (!exist) { - loadFile() - } else { - // modalDialogCustom.confirm('Confirm overwrite', `The file ${name} already exists! Would you like to overwrite it?`, () => { loadFile() }) - } - }) - }) + + ) + } else { + return ( + { state.fileManager.open(file.path) }} + /> + ) + } } return (
- - + + + { + state.files.map((file, index) => { + return renderFiles(file, index) + }) + } +
diff --git a/libs/remix-ui/file-explorer/src/lib/types/index.ts b/libs/remix-ui/file-explorer/src/lib/types/index.ts index a2ee05aea6..75d7fb3dc9 100644 --- a/libs/remix-ui/file-explorer/src/lib/types/index.ts +++ b/libs/remix-ui/file-explorer/src/lib/types/index.ts @@ -1,7 +1,7 @@ /* eslint-disable-next-line */ export interface FileExplorerProps { name: string, - localRegistry: any, + registry: any, files: any, menuItems?: string[], plugin: any diff --git a/libs/remix-ui/tree-view/src/types/index.ts b/libs/remix-ui/tree-view/src/types/index.ts index 9218469ec5..7ebbc05155 100644 --- a/libs/remix-ui/tree-view/src/types/index.ts +++ b/libs/remix-ui/tree-view/src/types/index.ts @@ -1,11 +1,11 @@ export interface TreeViewProps { children?: React.ReactNode, - id: string + id?: string } export interface TreeViewItemProps { children?: React.ReactNode, - id: string, + id?: string, label: string | number | React.ReactNode, expand?: boolean, onClick?: VoidFunction, From d40cf2210d095509ee3dd69247ab42c229b7dfe8 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 26 Nov 2020 10:26:28 +0100 Subject: [PATCH 05/99] Order files and folders, added support for icons in tree view --- .../file-explorer/src/lib/file-explorer.tsx | 25 +- libs/remix-ui/tree-view/.eslintrc | 261 ++---------------- libs/remix-ui/tree-view/jest.config.js | 2 +- libs/remix-ui/tree-view/src/index.ts | 4 +- .../tree-view/src/lib/remix-ui-tree-view.tsx | 4 +- .../src/lib/tree-view-item/tree-view-item.tsx | 8 +- libs/remix-ui/tree-view/src/types/index.ts | 7 +- 7 files changed, 48 insertions(+), 263 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index c851a10e84..7aa4c1f6f9 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -160,18 +160,29 @@ export const FileExplorer = (props: FileExplorerProps) => { } const normalize = (path, filesList) => { + const folders = [] + const files = [] const prefix = path.split('/')[0] - const files = Object.keys(filesList).map(key => { + + Object.keys(filesList).forEach(key => { const path = prefix + '/' + key - return { - path, - name: extractNameFromKey(path), - isDirectory: filesList[key].isDirectory + if (filesList[key].isDirectory) { + folders.push({ + path, + name: extractNameFromKey(path), + isDirectory: filesList[key].isDirectory + }) + } else { + files.push({ + path, + name: extractNameFromKey(path), + isDirectory: filesList[key].isDirectory + }) } }) - return files + return [...folders, ...files] } const extractNameFromKey = (key) => { @@ -390,7 +401,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const renderFiles = (file, index) => { if (file.isDirectory) { return ( - { resolveDirectory(file.path) }} key={index} label={label(file)}> + { resolveDirectory(file.path) }}> { file.child ? { file.child.map((file, index) => { diff --git a/libs/remix-ui/tree-view/.eslintrc b/libs/remix-ui/tree-view/.eslintrc index 977f139a09..dae5c6feeb 100644 --- a/libs/remix-ui/tree-view/.eslintrc +++ b/libs/remix-ui/tree-view/.eslintrc @@ -1,248 +1,19 @@ { - "rules": { - "array-callback-return": "warn", - "dot-location": ["warn", "property"], - "eqeqeq": ["warn", "smart"], - "new-parens": "warn", - "no-caller": "warn", - "no-cond-assign": ["warn", "except-parens"], - "no-const-assign": "warn", - "no-control-regex": "warn", - "no-delete-var": "warn", - "no-dupe-args": "warn", - "no-dupe-keys": "warn", - "no-duplicate-case": "warn", - "no-empty-character-class": "warn", - "no-empty-pattern": "warn", - "no-eval": "warn", - "no-ex-assign": "warn", - "no-extend-native": "warn", - "no-extra-bind": "warn", - "no-extra-label": "warn", - "no-fallthrough": "warn", - "no-func-assign": "warn", - "no-implied-eval": "warn", - "no-invalid-regexp": "warn", - "no-iterator": "warn", - "no-label-var": "warn", - "no-labels": ["warn", { "allowLoop": true, "allowSwitch": false }], - "no-lone-blocks": "warn", - "no-loop-func": "warn", - "no-mixed-operators": [ - "warn", - { - "groups": [ - ["&", "|", "^", "~", "<<", ">>", ">>>"], - ["==", "!=", "===", "!==", ">", ">=", "<", "<="], - ["&&", "||"], - ["in", "instanceof"] - ], - "allowSamePrecedence": false - } - ], - "no-multi-str": "warn", - "no-native-reassign": "warn", - "no-negated-in-lhs": "warn", - "no-new-func": "warn", - "no-new-object": "warn", - "no-new-symbol": "warn", - "no-new-wrappers": "warn", - "no-obj-calls": "warn", - "no-octal": "warn", - "no-octal-escape": "warn", - "no-redeclare": "warn", - "no-regex-spaces": "warn", - "no-restricted-syntax": ["warn", "WithStatement"], - "no-script-url": "warn", - "no-self-assign": "warn", - "no-self-compare": "warn", - "no-sequences": "warn", - "no-shadow-restricted-names": "warn", - "no-sparse-arrays": "warn", - "no-template-curly-in-string": "warn", - "no-this-before-super": "warn", - "no-throw-literal": "warn", - "no-restricted-globals": [ - "error", - "addEventListener", - "blur", - "close", - "closed", - "confirm", - "defaultStatus", - "defaultstatus", - "event", - "external", - "find", - "focus", - "frameElement", - "frames", - "history", - "innerHeight", - "innerWidth", - "length", - "location", - "locationbar", - "menubar", - "moveBy", - "moveTo", - "name", - "onblur", - "onerror", - "onfocus", - "onload", - "onresize", - "onunload", - "open", - "opener", - "opera", - "outerHeight", - "outerWidth", - "pageXOffset", - "pageYOffset", - "parent", - "print", - "removeEventListener", - "resizeBy", - "resizeTo", - "screen", - "screenLeft", - "screenTop", - "screenX", - "screenY", - "scroll", - "scrollbars", - "scrollBy", - "scrollTo", - "scrollX", - "scrollY", - "self", - "status", - "statusbar", - "stop", - "toolbar", - "top" - ], - "no-unexpected-multiline": "warn", - "no-unreachable": "warn", - "no-unused-expressions": [ - "error", - { - "allowShortCircuit": true, - "allowTernary": true, - "allowTaggedTemplates": true - } - ], - "no-unused-labels": "warn", - "no-useless-computed-key": "warn", - "no-useless-concat": "warn", - "no-useless-escape": "warn", - "no-useless-rename": [ - "warn", - { - "ignoreDestructuring": false, - "ignoreImport": false, - "ignoreExport": false - } - ], - "no-with": "warn", - "no-whitespace-before-property": "warn", - "react-hooks/exhaustive-deps": "warn", - "require-yield": "warn", - "rest-spread-spacing": ["warn", "never"], - "strict": ["warn", "never"], - "unicode-bom": ["warn", "never"], - "use-isnan": "warn", - "valid-typeof": "warn", - "no-restricted-properties": [ - "error", - { - "object": "require", - "property": "ensure", - "message": "Please use import() instead. More info: https://facebook.github.io/create-react-app/docs/code-splitting" - }, - { - "object": "System", - "property": "import", - "message": "Please use import() instead. More info: https://facebook.github.io/create-react-app/docs/code-splitting" - } - ], - "getter-return": "warn", - "import/first": "error", - "import/no-amd": "error", - "import/no-webpack-loader-syntax": "error", - "react/forbid-foreign-prop-types": ["warn", { "allowInPropTypes": true }], - "react/jsx-no-comment-textnodes": "warn", - "react/jsx-no-duplicate-props": "warn", - "react/jsx-no-target-blank": "warn", - "react/jsx-no-undef": "error", - "react/jsx-pascal-case": ["warn", { "allowAllCaps": true, "ignore": [] }], - "react/jsx-uses-react": "warn", - "react/jsx-uses-vars": "warn", - "react/no-danger-with-children": "warn", - "react/no-direct-mutation-state": "warn", - "react/no-is-mounted": "warn", - "react/no-typos": "error", - "react/react-in-jsx-scope": "error", - "react/require-render-return": "error", - "react/style-prop-object": "warn", - "react/jsx-no-useless-fragment": "warn", - "jsx-a11y/accessible-emoji": "warn", - "jsx-a11y/alt-text": "warn", - "jsx-a11y/anchor-has-content": "warn", - "jsx-a11y/anchor-is-valid": [ - "warn", - { "aspects": ["noHref", "invalidHref"] } - ], - "jsx-a11y/aria-activedescendant-has-tabindex": "warn", - "jsx-a11y/aria-props": "warn", - "jsx-a11y/aria-proptypes": "warn", - "jsx-a11y/aria-role": "warn", - "jsx-a11y/aria-unsupported-elements": "warn", - "jsx-a11y/heading-has-content": "warn", - "jsx-a11y/iframe-has-title": "warn", - "jsx-a11y/img-redundant-alt": "warn", - "jsx-a11y/no-access-key": "warn", - "jsx-a11y/no-distracting-elements": "warn", - "jsx-a11y/no-redundant-roles": "warn", - "jsx-a11y/role-has-required-aria-props": "warn", - "jsx-a11y/role-supports-aria-props": "warn", - "jsx-a11y/scope": "warn", - "react-hooks/rules-of-hooks": "error", - "default-case": "off", - "no-dupe-class-members": "off", - "no-undef": "off", - "@typescript-eslint/consistent-type-assertions": "warn", - "no-array-constructor": "off", - "@typescript-eslint/no-array-constructor": "warn", - "@typescript-eslint/no-namespace": "error", - "no-use-before-define": "off", - "@typescript-eslint/no-use-before-define": [ - "warn", - { - "functions": false, - "classes": false, - "variables": false, - "typedefs": false - } - ], - "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": [ - "warn", - { "args": "none", "ignoreRestSiblings": true } - ], - "no-useless-constructor": "off", - "@typescript-eslint/no-useless-constructor": "warn" - }, "env": { - "browser": true, - "commonjs": true, - "es6": true, - "jest": true, - "node": true + "browser": true, + "es6": true + }, + "extends": "../../../.eslintrc", + "globals": { + "Atomics": "readonly", + "SharedArrayBuffer": "readonly" }, - "settings": { "react": { "version": "detect" } }, - "plugins": ["import", "jsx-a11y", "react", "react-hooks"], - "extends": ["../../../.eslintrc"], - "ignorePatterns": ["!**/*"] -} + "parserOptions": { + "ecmaVersion": 11, + "sourceType": "module" + }, + "rules": { + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": "error" + } +} diff --git a/libs/remix-ui/tree-view/jest.config.js b/libs/remix-ui/tree-view/jest.config.js index ea99fbe3c5..b442eaf362 100644 --- a/libs/remix-ui/tree-view/jest.config.js +++ b/libs/remix-ui/tree-view/jest.config.js @@ -9,4 +9,4 @@ module.exports = { }, moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], coverageDirectory: '../../../coverage/libs/remix-ui/tree-view' -}; +} diff --git a/libs/remix-ui/tree-view/src/index.ts b/libs/remix-ui/tree-view/src/index.ts index 639d70eff2..abc1b93872 100644 --- a/libs/remix-ui/tree-view/src/index.ts +++ b/libs/remix-ui/tree-view/src/index.ts @@ -1,2 +1,2 @@ -export * from './lib/tree-view-item/tree-view-item'; -export * from './lib/remix-ui-tree-view'; +export * from './lib/tree-view-item/tree-view-item' +export * from './lib/remix-ui-tree-view' diff --git a/libs/remix-ui/tree-view/src/lib/remix-ui-tree-view.tsx b/libs/remix-ui/tree-view/src/lib/remix-ui-tree-view.tsx index 70842535d3..37f9c49dad 100644 --- a/libs/remix-ui/tree-view/src/lib/remix-ui-tree-view.tsx +++ b/libs/remix-ui/tree-view/src/lib/remix-ui-tree-view.tsx @@ -1,11 +1,11 @@ -import React from 'react' +import React from 'react' // eslint-disable-line import { TreeViewProps } from '../types' import './remix-ui-tree-view.css' export const TreeView = (props: TreeViewProps) => { const { children, id, ...otherProps } = props - + return (
    { children } diff --git a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx index a80767132c..ea607fbc26 100644 --- a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx +++ b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx @@ -1,10 +1,10 @@ -import React, { useState, useEffect } from 'react' +import React, { useState, useEffect } from 'react' // eslint-disable-line import { TreeViewItemProps } from '../../types' import './tree-view-item.css' export const TreeViewItem = (props: TreeViewItemProps) => { - const { id, children, label, expand, ...otherProps } = props + const { id, children, label, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon = 'fa fa-file', ...otherProps } = props const [isExpanded, setIsExpanded] = useState(false) useEffect(() => { @@ -14,12 +14,12 @@ export const TreeViewItem = (props: TreeViewItemProps) => { return (
  • setIsExpanded(!isExpanded)}> -
    + { children ?
    :
    } { label }
    - { isExpanded ? children : null } + { isExpanded ? children : null }
  • ) } diff --git a/libs/remix-ui/tree-view/src/types/index.ts b/libs/remix-ui/tree-view/src/types/index.ts index 7ebbc05155..5650b85191 100644 --- a/libs/remix-ui/tree-view/src/types/index.ts +++ b/libs/remix-ui/tree-view/src/types/index.ts @@ -9,5 +9,8 @@ export interface TreeViewItemProps { label: string | number | React.ReactNode, expand?: boolean, onClick?: VoidFunction, - className?: string -} \ No newline at end of file + className?: string, + iconX?: string, + iconY?: string, + icon?: string +} From 59352cee6e50b6aa97aea09aebae9e8d22433527 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 26 Nov 2020 10:53:09 +0100 Subject: [PATCH 06/99] Align files and folders, install library for drag and drop --- .../file-explorer/src/lib/file-explorer.tsx | 3 ++- .../src/lib/tree-view-item/tree-view-item.tsx | 4 ++-- package-lock.json | 14 +++++++++----- package.json | 3 ++- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 7aa4c1f6f9..571a133cb6 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -401,7 +401,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const renderFiles = (file, index) => { if (file.isDirectory) { return ( - { resolveDirectory(file.path) }}> + { resolveDirectory(file.path) }}> { file.child ? { file.child.map((file, index) => { @@ -419,6 +419,7 @@ export const FileExplorer = (props: FileExplorerProps) => { key={index} label={label(file)} onClick={() => { state.fileManager.open(file.path) }} + icon='fa fa-file' /> ) } diff --git a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx index ea607fbc26..e04e738212 100644 --- a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx +++ b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx @@ -4,7 +4,7 @@ import { TreeViewItemProps } from '../../types' import './tree-view-item.css' export const TreeViewItem = (props: TreeViewItemProps) => { - const { id, children, label, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon = 'fa fa-file', ...otherProps } = props + const { id, children, label, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon, ...otherProps } = props const [isExpanded, setIsExpanded] = useState(false) useEffect(() => { @@ -14,7 +14,7 @@ export const TreeViewItem = (props: TreeViewItemProps) => { return (
  • setIsExpanded(!isExpanded)}> - { children ?
    :
    } + { children ?
    : icon ?
    : null } { label } diff --git a/package-lock.json b/package-lock.json index 779a2ec5db..bb2393535c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28220,7 +28220,6 @@ }, "dezalgo": { "version": "1.0.3", - "resolved": false, "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", "requires": { "asap": "^2.0.0", @@ -28849,7 +28848,6 @@ }, "normalize-git-url": { "version": "3.0.2", - "resolved": false, "integrity": "sha1-jl8Uvgva7bc+ByADEKpBbCc1D8Q=" }, "normalize-package-data": { @@ -28887,7 +28885,6 @@ }, "npm-install-checks": { "version": "3.0.0", - "resolved": false, "integrity": "sha1-1K7N/VGlPjcjt7L5Oy7ijjB7wNc=", "requires": { "semver": "^2.3.0 || 3.x || 4 || 5" @@ -29234,7 +29231,6 @@ }, "realize-package-specifier": { "version": "3.0.3", - "resolved": false, "integrity": "sha1-0N74gpUrjeP2frpekRmWYScfQfQ=", "requires": { "dezalgo": "^1.0.1", @@ -29771,7 +29767,6 @@ "dependencies": { "unique-slug": { "version": "2.0.0", - "resolved": false, "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", "requires": { "imurmurhash": "^0.1.4" @@ -35591,6 +35586,15 @@ "scheduler": "^0.19.1" } }, + "react-draggable": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.3.tgz", + "integrity": "sha512-jV4TE59MBuWm7gb6Ns3Q1mxX8Azffb7oTtDtBgFkxRvhDp38YAARmRplrj0+XGkhOJB5XziArX+4HUUABtyZ0w==", + "requires": { + "classnames": "^2.2.5", + "prop-types": "^15.6.0" + } + }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", diff --git a/package.json b/package.json index 030cea751f..50a14088df 100644 --- a/package.json +++ b/package.json @@ -155,11 +155,12 @@ "react": "16.13.1", "react-bootstrap": "^1.3.0", "react-dom": "16.13.1", + "react-draggable": "^4.4.3", "signale": "^1.4.0", "time-stamp": "^2.2.0", "winston": "^3.3.3", "ws": "^7.3.0" - }, + }, "devDependencies": { "@babel/core": "^7.4.5", "@babel/plugin-transform-modules-amd": "^7.10.4", From ce317597462f5c10571f132023de211e106f6362 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 27 Nov 2020 10:00:30 +0100 Subject: [PATCH 07/99] Async/await for files --- .../file-explorer/src/lib/file-explorer.tsx | 127 +++++++++++++----- .../src/lib/tree-view-item/tree-view-item.tsx | 4 +- libs/remix-ui/tree-view/src/types/index.ts | 5 +- 3 files changed, 95 insertions(+), 41 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 571a133cb6..19384724d6 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from 'react' // eslint-disable-line import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line +import Draggable from 'react-draggable' // eslint-disable-line import * as helper from '../../../../../apps/remix-ide/src/lib/helper' import { FileExplorerProps } from './types' @@ -75,7 +76,7 @@ export const FileExplorer = (props: FileExplorerProps) => { } const [state, setState] = useState({ - focusElement: null, + focusElement: [], focusPath: null, menuItems: [ { @@ -106,41 +107,42 @@ export const FileExplorer = (props: FileExplorerProps) => { publishToGist, createNewFile }, - fileManager: null + fileManager: null, + ctrlKey: false }) useEffect(() => { - const fileManager = registry.get('filemanager').api + (async () => { + const fileManager = registry.get('filemanager').api + const files = await resolveDirectory(name) - setState(prevState => { - return { ...prevState, fileManager } - }) - resolveDirectory(name) + setState(prevState => { + return { ...prevState, fileManager, files } + }) + })() }, []) - const resolveDirectory = (folderPath) => { - const folderIndex = state.files.findIndex(({ path }) => path === folderPath) + const resolveDirectory = async (folderPath): Promise<{ path: string, name: string, isDirectory: boolean }[]> => { + return new Promise((resolve) => { + const folderIndex = state.files.findIndex(({ path }) => path === folderPath) - if (folderIndex === -1) { - files.resolveDirectory(folderPath, (error, fileTree) => { - if (error) console.error(error) - const files = normalize(folderPath, fileTree) + if (folderIndex === -1) { + files.resolveDirectory(folderPath, (error, fileTree) => { + if (error) console.error(error) + const files = normalize(folderPath, fileTree) - setState(prevState => { - return { ...prevState, files } + resolve(files) }) - }) - } else { - files.resolveDirectory(folderPath, (error, fileTree) => { - if (error) console.error(error) - const files = state.files + } else { + files.resolveDirectory(folderPath, (error, fileTree) => { + if (error) console.error(error) + const files = state.files - files[folderIndex].child = normalize(folderPath, fileTree) - setState(prevState => { - return { ...prevState, files } + files[folderIndex].child = normalize(folderPath, fileTree) + resolve(files) }) - }) - } + } + }) } const label = (data) => { @@ -159,7 +161,7 @@ export const FileExplorer = (props: FileExplorerProps) => { ) } - const normalize = (path, filesList) => { + const normalize = (path, filesList): { path: string, name: string, isDirectory: boolean }[] => { const folders = [] const files = [] const prefix = path.split('/')[0] @@ -352,6 +354,23 @@ export const FileExplorer = (props: FileExplorerProps) => { // } // } + const handleClickFile = async (event, path) => { + event.stopPropagation() + await state.fileManager.open(path) + setState(prevState => { + return { ...prevState, focusElement: [path] } + }) + } + + const handleClickFolder = async (path) => { + console.log('path: ', path) + const files = await resolveDirectory(path) + + setState(prevState => { + return { ...prevState, focusElement: [path], files } + }) + } + const renderMenuItems = () => { let items if (state.menuItems) { @@ -401,7 +420,16 @@ export const FileExplorer = (props: FileExplorerProps) => { const renderFiles = (file, index) => { if (file.isDirectory) { return ( - { resolveDirectory(file.path) }}> + // + { e.stopPropagation(); handleClickFolder(file.path) }} + labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' } + > { file.child ? { file.child.map((file, index) => { @@ -411,31 +439,56 @@ export const FileExplorer = (props: FileExplorerProps) => { : } + // ) } else { return ( + // { state.fileManager.open(file.path) }} + onClick={(event) => { + handleClickFile(event, file.path) + }} icon='fa fa-file' + labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' } /> + // ) } } return ( -
    +
    { + if (e.ctrlKey) { + console.log('TRUE') + setState(prevState => { + return { ...prevState, ctrlKey: true } + }) + } + }} + onKeyUp={() => { + console.log('FALSE') + setState(prevState => { + return { ...prevState, ctrlKey: false } + }) + }} + > - - { - state.files.map((file, index) => { - return renderFiles(file, index) - }) - } - + {/* false}> */} +
    + + { + state.files.map((file, index) => { + return renderFiles(file, index) + }) + } + +
    + {/*
    */}
    diff --git a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx index e04e738212..25c0fed0d7 100644 --- a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx +++ b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx @@ -4,7 +4,7 @@ import { TreeViewItemProps } from '../../types' import './tree-view-item.css' export const TreeViewItem = (props: TreeViewItemProps) => { - const { id, children, label, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon, ...otherProps } = props + const { id, children, label, labelClass, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon, ...otherProps } = props const [isExpanded, setIsExpanded] = useState(false) useEffect(() => { @@ -13,7 +13,7 @@ export const TreeViewItem = (props: TreeViewItemProps) => { return (
  • -
    setIsExpanded(!isExpanded)}> +
    setIsExpanded(!isExpanded)}> { children ?
    : icon ?
    : null } { label } diff --git a/libs/remix-ui/tree-view/src/types/index.ts b/libs/remix-ui/tree-view/src/types/index.ts index 5650b85191..f3e9346004 100644 --- a/libs/remix-ui/tree-view/src/types/index.ts +++ b/libs/remix-ui/tree-view/src/types/index.ts @@ -8,9 +8,10 @@ export interface TreeViewItemProps { id?: string, label: string | number | React.ReactNode, expand?: boolean, - onClick?: VoidFunction, + onClick?: (...args: any) => void, className?: string, iconX?: string, iconY?: string, - icon?: string + icon?: string, + labelClass?: string } From 33346be89dcddc2e7abeafdc71c4f20e10f0f128 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 27 Nov 2020 15:47:56 +0100 Subject: [PATCH 08/99] Resolve directory --- .../file-explorer/src/lib/file-explorer.tsx | 140 +++++++++--------- .../file-explorer/src/lib/types/index.ts | 7 + 2 files changed, 80 insertions(+), 67 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 19384724d6..e3ea1f7882 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react' // eslint-disable-line import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line import Draggable from 'react-draggable' // eslint-disable-line import * as helper from '../../../../../apps/remix-ide/src/lib/helper' -import { FileExplorerProps } from './types' +import { FileExplorerProps, File } from './types' import './css/file-explorer.css' @@ -114,7 +114,7 @@ export const FileExplorer = (props: FileExplorerProps) => { useEffect(() => { (async () => { const fileManager = registry.get('filemanager').api - const files = await resolveDirectory(name) + const files = await fetchDirectoryContent(name) setState(prevState => { return { ...prevState, fileManager, files } @@ -122,26 +122,30 @@ export const FileExplorer = (props: FileExplorerProps) => { })() }, []) - const resolveDirectory = async (folderPath): Promise<{ path: string, name: string, isDirectory: boolean }[]> => { - return new Promise((resolve) => { - const folderIndex = state.files.findIndex(({ path }) => path === folderPath) + const resolveDirectory = async (folderPath, dir: File[]): File[] => { + dir = await Promise.all(dir.map(async (file) => { + if (file.path === folderPath) { + file.child = await fetchDirectoryContent(folderPath) + return file + } else if (file.child) { + file.child = await resolveDirectory(folderPath, file.child) + return file + } else { + return file + } + })) - if (folderIndex === -1) { - files.resolveDirectory(folderPath, (error, fileTree) => { - if (error) console.error(error) - const files = normalize(folderPath, fileTree) + return dir + } - resolve(files) - }) - } else { - files.resolveDirectory(folderPath, (error, fileTree) => { - if (error) console.error(error) - const files = state.files + const fetchDirectoryContent = async (folderPath: string): Promise => { + return new Promise((resolve) => { + files.resolveDirectory(folderPath, (error, fileTree) => { + if (error) console.error(error) + const files = normalize(folderPath, fileTree) - files[folderIndex].child = normalize(folderPath, fileTree) - resolve(files) - }) - } + resolve(files) + }) }) } @@ -161,7 +165,7 @@ export const FileExplorer = (props: FileExplorerProps) => { ) } - const normalize = (path, filesList): { path: string, name: string, isDirectory: boolean }[] => { + const normalize = (path, filesList): File[] => { const folders = [] const files = [] const prefix = path.split('/')[0] @@ -354,17 +358,15 @@ export const FileExplorer = (props: FileExplorerProps) => { // } // } - const handleClickFile = async (event, path) => { - event.stopPropagation() - await state.fileManager.open(path) + const handleClickFile = (path) => { + state.fileManager.open(path) setState(prevState => { return { ...prevState, focusElement: [path] } }) } const handleClickFolder = async (path) => { - console.log('path: ', path) - const files = await resolveDirectory(path) + const files = await resolveDirectory(path, state.files) setState(prevState => { return { ...prevState, focusElement: [path], files } @@ -420,41 +422,45 @@ export const FileExplorer = (props: FileExplorerProps) => { const renderFiles = (file, index) => { if (file.isDirectory) { return ( - // - { e.stopPropagation(); handleClickFolder(file.path) }} - labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' } - > - { - file.child ? { - file.child.map((file, index) => { - return renderFiles(file, index) - }) + + { + e.stopPropagation() + handleClickFolder(file.path) + }} + labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' } + > + { + file.child ? { + file.child.map((file, index) => { + return renderFiles(file, index) + }) + } + : } - : - } - - // + + ) } else { return ( - // - { - handleClickFile(event, file.path) - }} - icon='fa fa-file' - labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' } - /> - // + + { + e.stopPropagation() + handleClickFile(file.path) + }} + icon='fa fa-file' + labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' } + /> + ) } } @@ -478,17 +484,17 @@ export const FileExplorer = (props: FileExplorerProps) => { > - {/* false}> */} -
    - - { - state.files.map((file, index) => { - return renderFiles(file, index) - }) - } - -
    - {/*
    */} + false}> +
    + + { + state.files.map((file, index) => { + return renderFiles(file, index) + }) + } + +
    +
    diff --git a/libs/remix-ui/file-explorer/src/lib/types/index.ts b/libs/remix-ui/file-explorer/src/lib/types/index.ts index 75d7fb3dc9..e8cfa73f38 100644 --- a/libs/remix-ui/file-explorer/src/lib/types/index.ts +++ b/libs/remix-ui/file-explorer/src/lib/types/index.ts @@ -6,3 +6,10 @@ export interface FileExplorerProps { menuItems?: string[], plugin: any } + +export interface File { + path: string, + name: string, + isDirectory: boolean, + child?: File[] +} From 3a281f34a8c0338002bc89847107556908811303 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Sun, 29 Nov 2020 18:01:14 +0100 Subject: [PATCH 09/99] Reference element --- libs/remix-ui/file-explorer/src/lib/file-explorer.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index e3ea1f7882..129664fc30 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react' // eslint-disable-line +import React, { useEffect, useState, useRef } from 'react' // eslint-disable-line import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line import Draggable from 'react-draggable' // eslint-disable-line import * as helper from '../../../../../apps/remix-ide/src/lib/helper' @@ -75,6 +75,7 @@ export const FileExplorer = (props: FileExplorerProps) => { // }, null, true) } + const containerRef = useRef(null) const [state, setState] = useState({ focusElement: [], focusPath: null, @@ -122,7 +123,7 @@ export const FileExplorer = (props: FileExplorerProps) => { })() }, []) - const resolveDirectory = async (folderPath, dir: File[]): File[] => { + const resolveDirectory = async (folderPath, dir: File[]): Promise => { dir = await Promise.all(dir.map(async (file) => { if (file.path === folderPath) { file.child = await fetchDirectoryContent(folderPath) @@ -363,6 +364,7 @@ export const FileExplorer = (props: FileExplorerProps) => { setState(prevState => { return { ...prevState, focusElement: [path] } }) + containerRef.current.focus() } const handleClickFolder = async (path) => { @@ -466,7 +468,9 @@ export const FileExplorer = (props: FileExplorerProps) => { } return ( -
    { if (e.ctrlKey) { console.log('TRUE') From 71cee4b01c0f874a7403fcc18e4c134a8cb8e1d9 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Mon, 30 Nov 2020 17:13:11 +0100 Subject: [PATCH 10/99] Multiselect for folders --- .../file-explorer/src/lib/file-explorer.tsx | 23 +++++++++++++++---- .../src/lib/tree-view-item/tree-view-item.tsx | 4 ++-- libs/remix-ui/tree-view/src/types/index.ts | 3 ++- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 129664fc30..a1453ae99c 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -368,11 +368,23 @@ export const FileExplorer = (props: FileExplorerProps) => { } const handleClickFolder = async (path) => { - const files = await resolveDirectory(path, state.files) + if (state.ctrlKey) { + if (state.focusElement.findIndex(item => item === path) !== -1) { + setState(prevState => { + return { ...prevState, focusElement: [...prevState.focusElement.filter(item => item !== path)] } + }) + } else { + setState(prevState => { + return { ...prevState, focusElement: [...prevState.focusElement, path] } + }) + } + } else { + const files = await resolveDirectory(path, state.files) - setState(prevState => { - return { ...prevState, focusElement: [path], files } - }) + setState(prevState => { + return { ...prevState, focusElement: [path], files } + }) + } } const renderMenuItems = () => { @@ -436,6 +448,7 @@ export const FileExplorer = (props: FileExplorerProps) => { handleClickFolder(file.path) }} labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' } + controlBehaviour={ state.ctrlKey } > { file.child ? { @@ -472,7 +485,7 @@ export const FileExplorer = (props: FileExplorerProps) => { ref={containerRef} tabIndex={-1} onKeyDown={(e) => { - if (e.ctrlKey) { + if (e.shiftKey) { console.log('TRUE') setState(prevState => { return { ...prevState, ctrlKey: true } diff --git a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx index 25c0fed0d7..b3aa60cd9f 100644 --- a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx +++ b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx @@ -4,7 +4,7 @@ import { TreeViewItemProps } from '../../types' import './tree-view-item.css' export const TreeViewItem = (props: TreeViewItemProps) => { - const { id, children, label, labelClass, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon, ...otherProps } = props + const { id, children, label, labelClass, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon, controlBehaviour = false, ...otherProps } = props const [isExpanded, setIsExpanded] = useState(false) useEffect(() => { @@ -13,7 +13,7 @@ export const TreeViewItem = (props: TreeViewItemProps) => { return (
  • -
    setIsExpanded(!isExpanded)}> +
    !controlBehaviour && setIsExpanded(!isExpanded)}> { children ?
    : icon ?
    : null } { label } diff --git a/libs/remix-ui/tree-view/src/types/index.ts b/libs/remix-ui/tree-view/src/types/index.ts index f3e9346004..e3d54e71b3 100644 --- a/libs/remix-ui/tree-view/src/types/index.ts +++ b/libs/remix-ui/tree-view/src/types/index.ts @@ -13,5 +13,6 @@ export interface TreeViewItemProps { iconX?: string, iconY?: string, icon?: string, - labelClass?: string + labelClass?: string, + controlBehaviour?: boolean } From 568324e84cf33d4aa696ceed37f9f1d2f1e2ee1c Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 3 Dec 2020 02:54:37 +0100 Subject: [PATCH 11/99] Publish to gist --- .../file-explorer/src/lib/file-explorer.tsx | 465 ++++++++++-------- .../src/lib/tree-view-item/tree-view-item.tsx | 4 +- libs/remix-ui/tree-view/src/types/index.ts | 1 + package-lock.json | 102 +++- package.json | 3 +- 5 files changed, 365 insertions(+), 210 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index a1453ae99c..6b1882fd7e 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -1,13 +1,43 @@ import React, { useEffect, useState, useRef } from 'react' // eslint-disable-line import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line -import Draggable from 'react-draggable' // eslint-disable-line +import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd' // eslint-disable-line +import * as async from 'async' +import * as Gists from 'gists' import * as helper from '../../../../../apps/remix-ide/src/lib/helper' +import QueryParams from '../../../../../apps/remix-ide/src/lib/query-params' import { FileExplorerProps, File } from './types' import './css/file-explorer.css' +const queryParams = new QueryParams() + +function packageFiles (filesProvider, directory, callback) { + const ret = {} + filesProvider.resolveDirectory(directory, (error, files) => { + if (error) callback(error) + else { + async.eachSeries(Object.keys(files), (path, cb) => { + if (filesProvider.isDirectory(path)) { + cb() + } else { + filesProvider.get(path, (error, content) => { + if (error) return cb(error) + if (/^\s+$/.test(content) || !content.length) { + content = '// this line is added to create a gist. Empty file is not allowed.' + } + ret[path] = { content } + cb() + }) + } + }, (error) => { + callback(error, ret) + }) + } + }) +} + export const FileExplorer = (props: FileExplorerProps) => { - const { files, name, registry } = props + const { files, name, registry, plugin } = props const uploadFile = (target) => { // TODO The file explorer is merely a view on the current state of // the files module. Please ask the user here if they want to overwrite @@ -47,34 +77,6 @@ export const FileExplorer = (props: FileExplorerProps) => { }) }) } - const publishToGist = () => { - // modalDialogCustom.confirm( - // 'Create a public gist', - // 'Are you sure you want to publish all your files in browser directory anonymously as a public gist on github.com? Note: this will not include directories.', - // () => { this.toGist() } - // ) - } - const createNewFile = (parentFolder = 'browser') => { - // const self = this - // modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => { - // if (!input) input = 'New file' - // helper.createNonClashingName(parentFolder + '/' + input, self.files, async (error, newName) => { - // if (error) return tooltip('Failed to create file ' + newName + ' ' + error) - // const fileManager = self._deps.fileManager - // const createFile = await fileManager.writeFile(newName, '') - - // if (!createFile) { - // tooltip('Failed to create file ' + newName) - // } else { - // await fileManager.open(newName) - // if (newName.includes('_test.sol')) { - // self.events.trigger('newTestFileCreated', [newName]) - // } - // } - // }) - // }, null, true) - } - const containerRef = useRef(null) const [state, setState] = useState({ focusElement: [], @@ -102,23 +104,28 @@ export const FileExplorer = (props: FileExplorerProps) => { } ].filter(item => props.menuItems && props.menuItems.find((name) => { return name === item.action })), files: [], - actions: { - updateGist: () => {}, - uploadFile, - publishToGist, - createNewFile - }, + actions: {}, fileManager: null, - ctrlKey: false + tokenAccess: null, + ctrlKey: false, + newFileName: '' }) useEffect(() => { (async () => { + console.log('registry: ', registry) const fileManager = registry.get('filemanager').api + const config = registry.get('config').api + const tokenAccess = config.get('settings/gist-access-token').api const files = await fetchDirectoryContent(name) + const actions = { + updateGist: () => {}, + uploadFile, + publishToGist + } setState(prevState => { - return { ...prevState, fileManager, files } + return { ...prevState, fileManager, tokenAccess, files, actions } }) })() }, []) @@ -150,22 +157,6 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } - const label = (data) => { - return ( -
    - - { data.path.split('/').pop() } - -
    - ) - } - const normalize = (path, filesList): File[] => { const folders = [] const files = [] @@ -198,100 +189,147 @@ export const FileExplorer = (props: FileExplorerProps) => { return keyPath[keyPath.length - 1] } - const toGist = (id) => { - // const proccedResult = function (error, data) { - // if (error) { - // modalDialogCustom.alert('Failed to manage gist: ' + error) - // console.log('Failed to manage gist: ' + error) - // } else { - // if (data.html_url) { - // modalDialogCustom.confirm('Gist is ready', `The gist is at ${data.html_url}. Would you like to open it in a new window?`, () => { - // window.open(data.html_url, '_blank') - // }) - // } else { - // modalDialogCustom.alert(data.message + ' ' + data.documentation_url + ' ' + JSON.stringify(data.errors, null, '\t')) - // } - // } - // } + const createNewFile = (parentFolder = 'browser') => { + // const self = this + // modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => { + // if (!input) input = 'New file' + // get filename from state (state.newFileName) + const fileManager = state.fileManager + const newFileName = parentFolder + '/' + 'unnamed' + Math.floor(Math.random() * 101) + + helper.createNonClashingName(newFileName, files, async (error, newName) => { + // if (error) return tooltip('Failed to create file ' + newName + ' ' + error) + if (error) return + const createFile = await fileManager.writeFile(newName, '') + + if (!createFile) { + // tooltip('Failed to create file ' + newName) + } else { + if (parentFolder === name) { + // const updatedFiles = await resolveDirectory(parentFolder, state.files) - // /** - // * This function is to get the original content of given gist - // * @params id is the gist id to fetch - // */ - // async function getOriginalFiles (id) { - // if (!id) { - // return [] - // } - - // const url = `https://api.github.com/gists/${id}` - // const res = await fetch(url) - // const data = await res.json() - // return data.files || [] - // } - - // // If 'id' is not defined, it is not a gist update but a creation so we have to take the files from the browser explorer. - // const folder = id ? 'browser/gists/' + id : 'browser/' - // this.packageFiles(this.files, folder, (error, packaged) => { - // if (error) { - // console.log(error) - // modalDialogCustom.alert('Failed to create gist: ' + error.message) - // } else { - // // check for token - // var tokenAccess = this._deps.config.get('settings/gist-access-token') - // if (!tokenAccess) { - // modalDialogCustom.alert( - // 'Remix requires an access token (which includes gists creation permission). Please go to the settings tab to create one.' - // ) - // } else { - // const description = 'Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. \n Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=' + - // queryParams.get().version + '&optimize=' + queryParams.get().optimize + '&runs=' + queryParams.get().runs + '&gist=' - // const gists = new Gists({ token: tokenAccess }) - - // if (id) { - // const originalFileList = getOriginalFiles(id) - // // Telling the GIST API to remove files - // const updatedFileList = Object.keys(packaged) - // const allItems = Object.keys(originalFileList) - // .filter(fileName => updatedFileList.indexOf(fileName) === -1) - // .reduce((acc, deleteFileName) => ({ - // ...acc, - // [deleteFileName]: null - // }), originalFileList) - // // adding new files - // updatedFileList.forEach((file) => { - // const _items = file.split('/') - // const _fileName = _items[_items.length - 1] - // allItems[_fileName] = packaged[file] - // }) - - // tooltip('Saving gist (' + id + ') ...') - // gists.edit({ - // description: description, - // public: true, - // files: allItems, - // id: id - // }, (error, result) => { - // proccedResult(error, result) - // if (!error) { - // for (const key in allItems) { - // if (allItems[key] === null) delete allItems[key] - // } - // } - // }) - // } else { - // // id is not existing, need to create a new gist - // tooltip('Creating a new gist ...') - // gists.create({ - // description: description, - // public: true, - // files: packaged - // }, (error, result) => { - // proccedResult(error, result) - // }) - // } - // } - // } - // }) + setState(prevState => { + return { + ...prevState, + files: [...prevState.files, { + path: newFileName, + name: extractNameFromKey(newFileName), + isDirectory: false + }] + } + }) + } + await fileManager.open(newName) + if (newName.includes('_test.sol')) { + plugin.events.trigger('newTestFileCreated', [newName]) + } + } + }) + // }, null, true) + } + + const publishToGist = () => { + // modalDialogCustom.confirm( + // 'Create a public gist', + // 'Are you sure you want to publish all your files in browser directory anonymously as a public gist on github.com? Note: this will not include directories.', + // () => { this.toGist() } + toGist() + // ) + } + + const toGist = (id?: string) => { + const proccedResult = function (error, data) { + if (error) { + // modalDialogCustom.alert('Failed to manage gist: ' + error) + console.log('Failed to manage gist: ' + error) + } else { + if (data.html_url) { + // modalDialogCustom.confirm('Gist is ready', `The gist is at ${data.html_url}. Would you like to open it in a new window?`, () => { + // window.open(data.html_url, '_blank') + // }) + } else { + // modalDialogCustom.alert(data.message + ' ' + data.documentation_url + ' ' + JSON.stringify(data.errors, null, '\t')) + } + } + } + + /** + * This function is to get the original content of given gist + * @params id is the gist id to fetch + */ + async function getOriginalFiles (id) { + if (!id) { + return [] + } + + const url = `https://api.github.com/gists/${id}` + const res = await fetch(url) + const data = await res.json() + return data.files || [] + } + + // If 'id' is not defined, it is not a gist update but a creation so we have to take the files from the browser explorer. + const folder = id ? 'browser/gists/' + id : 'browser/' + packageFiles(files, folder, (error, packaged) => { + if (error) { + console.log(error) + // modalDialogCustom.alert('Failed to create gist: ' + error.message) + } else { + // check for token + if (!state.tokenAccess) { + // modalDialogCustom.alert( + // 'Remix requires an access token (which includes gists creation permission). Please go to the settings tab to create one.' + // ) + } else { + const description = 'Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. \n Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=' + + queryParams.get().version + '&optimize=' + queryParams.get().optimize + '&runs=' + queryParams.get().runs + '&gist=' + const gists = new Gists({ token: state.tokenAccess }) + + if (id) { + const originalFileList = getOriginalFiles(id) + // Telling the GIST API to remove files + const updatedFileList = Object.keys(packaged) + const allItems = Object.keys(originalFileList) + .filter(fileName => updatedFileList.indexOf(fileName) === -1) + .reduce((acc, deleteFileName) => ({ + ...acc, + [deleteFileName]: null + }), originalFileList) + // adding new files + updatedFileList.forEach((file) => { + const _items = file.split('/') + const _fileName = _items[_items.length - 1] + allItems[_fileName] = packaged[file] + }) + + // tooltip('Saving gist (' + id + ') ...') + gists.edit({ + description: description, + public: true, + files: allItems, + id: id + }, (error, result) => { + proccedResult(error, result) + if (!error) { + for (const key in allItems) { + if (allItems[key] === null) delete allItems[key] + } + } + }) + } else { + // id is not existing, need to create a new gist + // tooltip('Creating a new gist ...') + gists.create({ + description: description, + public: true, + files: packaged + }, (error, result) => { + proccedResult(error, result) + }) + } + } + } + }) } // self._components = {} @@ -359,6 +397,26 @@ export const FileExplorer = (props: FileExplorerProps) => { // } // } + const label = (data) => { + return ( +
    + + { data.path.split('/').pop() } + +
    + ) + } + + const onDragEnd = result => { + + } + const handleClickFile = (path) => { state.fileManager.open(path) setState(prevState => { @@ -414,7 +472,7 @@ export const FileExplorer = (props: FileExplorerProps) => { data-id={'fileExplorerNewFile' + action} onClick={(e) => { e.stopPropagation() - state.actions[action]() + action === 'createNewFile' ? createNewFile() : state.actions[action]() }} className={'newFile ' + icon + ' remixui_newFile'} title={title} @@ -436,45 +494,55 @@ export const FileExplorer = (props: FileExplorerProps) => { const renderFiles = (file, index) => { if (file.isDirectory) { return ( - - { - e.stopPropagation() - handleClickFolder(file.path) - }} - labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' } - controlBehaviour={ state.ctrlKey } - > - { - file.child ? { - file.child.map((file, index) => { - return renderFiles(file, index) - }) + + {(provided) => ( + { + e.stopPropagation() + handleClickFolder(file.path) + }} + labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' } + controlBehaviour={ state.ctrlKey } + > + { + file.child ? { + file.child.map((file, index) => { + return renderFiles(file, index) + }) + } + : } - : - } - - + { provided.placeholder } + + )} + ) } else { return ( - - { - e.stopPropagation() - handleClickFile(file.path) - }} - icon='fa fa-file' - labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' } - /> + + {(provided) => ( + { + e.stopPropagation() + handleClickFile(file.path) + }} + icon='fa fa-file' + labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' } + /> + )} ) } @@ -486,14 +554,12 @@ export const FileExplorer = (props: FileExplorerProps) => { tabIndex={-1} onKeyDown={(e) => { if (e.shiftKey) { - console.log('TRUE') setState(prevState => { return { ...prevState, ctrlKey: true } }) } }} onKeyUp={() => { - console.log('FALSE') setState(prevState => { return { ...prevState, ctrlKey: false } }) @@ -501,17 +567,24 @@ export const FileExplorer = (props: FileExplorerProps) => { > - false}> -
    - - { - state.files.map((file, index) => { - return renderFiles(file, index) - }) - } - -
    -
    + + + {(provided) => ( +
    + + { + state.files.map((file, index) => { + return renderFiles(file, index) + }) + } + + { provided.placeholder } +
    + )} +
    +
    diff --git a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx index b3aa60cd9f..c570de5f07 100644 --- a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx +++ b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx @@ -4,7 +4,7 @@ import { TreeViewItemProps } from '../../types' import './tree-view-item.css' export const TreeViewItem = (props: TreeViewItemProps) => { - const { id, children, label, labelClass, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon, controlBehaviour = false, ...otherProps } = props + const { id, children, label, labelClass, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon, controlBehaviour = false, innerRef, ...otherProps } = props const [isExpanded, setIsExpanded] = useState(false) useEffect(() => { @@ -12,7 +12,7 @@ export const TreeViewItem = (props: TreeViewItemProps) => { }, [expand]) return ( -
  • +
  • !controlBehaviour && setIsExpanded(!isExpanded)}> { children ?
    : icon ?
    : null } diff --git a/libs/remix-ui/tree-view/src/types/index.ts b/libs/remix-ui/tree-view/src/types/index.ts index e3d54e71b3..cf8f850b52 100644 --- a/libs/remix-ui/tree-view/src/types/index.ts +++ b/libs/remix-ui/tree-view/src/types/index.ts @@ -15,4 +15,5 @@ export interface TreeViewItemProps { icon?: string, labelClass?: string, controlBehaviour?: boolean + innerRef?: any } diff --git a/package-lock.json b/package-lock.json index bb2393535c..e2dbf90fc6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7597,6 +7597,15 @@ "csstype": "^2.2.0" } }, + "@types/react-beautiful-dnd": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.0.0.tgz", + "integrity": "sha512-by80tJ8aTTDXT256Gl+RfLRtFjYbUWOnZuEigJgNsJrSEGxvFe5eY6k3g4VIvf0M/6+xoLgfYWoWonlOo6Wqdg==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/react-dom": { "version": "16.9.4", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.4.tgz", @@ -13509,6 +13518,14 @@ "insert-css": "^0.2.0" } }, + "css-box-model": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", + "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==", + "requires": { + "tiny-invariant": "^1.0.6" + } + }, "css-color-names": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", @@ -20226,6 +20243,14 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, "homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", @@ -25592,6 +25617,11 @@ } } }, + "memoize-one": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.1.1.tgz", + "integrity": "sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==" + }, "memory-fs": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", @@ -35427,6 +35457,11 @@ "integrity": "sha1-W4h48ROlgheEjGSCAmxz4bpXcn8=", "dev": true }, + "raf-schd": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.2.tgz", + "integrity": "sha512-VhlMZmGy6A6hrkJWHLNTGl5gtgMUm+xfGza6wbwnE914yeQ5Ybm18vgM734RZhMgfw4tacUrWseGZlpUrrakEQ==" + }, "ramda": { "version": "0.26.1", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", @@ -35534,6 +35569,20 @@ "prop-types": "^15.6.2" } }, + "react-beautiful-dnd": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.0.0.tgz", + "integrity": "sha512-87It8sN0ineoC3nBW0SbQuTFXM6bUqM62uJGY4BtTf0yzPl8/3+bHMWkgIe0Z6m8e+gJgjWxefGRVfpE3VcdEg==", + "requires": { + "@babel/runtime": "^7.8.4", + "css-box-model": "^1.2.0", + "memoize-one": "^5.1.1", + "raf-schd": "^4.0.2", + "react-redux": "^7.1.1", + "redux": "^4.0.4", + "use-memo-one": "^1.1.1" + } + }, "react-bootstrap": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-1.3.0.tgz", @@ -35586,15 +35635,6 @@ "scheduler": "^0.19.1" } }, - "react-draggable": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.3.tgz", - "integrity": "sha512-jV4TE59MBuWm7gb6Ns3Q1mxX8Azffb7oTtDtBgFkxRvhDp38YAARmRplrj0+XGkhOJB5XziArX+4HUUABtyZ0w==", - "requires": { - "classnames": "^2.2.5", - "prop-types": "^15.6.0" - } - }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -35620,6 +35660,28 @@ "warning": "^4.0.3" } }, + "react-redux": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.2.tgz", + "integrity": "sha512-8+CQ1EvIVFkYL/vu6Olo7JFLWop1qRUeb46sGtIMDCSpgwPQq8fPLpirIB0iTqFe9XYEFPHssdX8/UwN6pAkEA==", + "requires": { + "@babel/runtime": "^7.12.1", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^16.13.1" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", + "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + } + } + }, "react-transition-group": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", @@ -35904,6 +35966,15 @@ "esprima": "~4.0.0" } }, + "redux": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", + "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", + "requires": { + "loose-envify": "^1.4.0", + "symbol-observable": "^1.2.0" + } + }, "regenerate": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", @@ -39146,8 +39217,7 @@ "symbol-observable": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", - "dev": true + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" }, "symbol-tree": { "version": "3.2.4", @@ -39735,6 +39805,11 @@ "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=", "dev": true }, + "tiny-invariant": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", + "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -40752,6 +40827,11 @@ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" }, + "use-memo-one": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.1.tgz", + "integrity": "sha512-oFfsyun+bP7RX8X2AskHNTxu+R3QdE/RC5IefMbqptmACAA/gfol1KDD5KRzPsGMa62sWxGZw+Ui43u6x4ddoQ==" + }, "utf8": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", diff --git a/package.json b/package.json index 50a14088df..e232e3750a 100644 --- a/package.json +++ b/package.json @@ -153,9 +153,9 @@ "merge": "^1.2.0", "npm-install-version": "^6.0.2", "react": "16.13.1", + "react-beautiful-dnd": "^13.0.0", "react-bootstrap": "^1.3.0", "react-dom": "16.13.1", - "react-draggable": "^4.4.3", "signale": "^1.4.0", "time-stamp": "^2.2.0", "winston": "^3.3.3", @@ -191,6 +191,7 @@ "@types/nightwatch": "^1.1.6", "@types/node": "~8.9.4", "@types/react": "16.9.17", + "@types/react-beautiful-dnd": "^13.0.0", "@types/react-dom": "16.9.4", "@types/react-router-dom": "5.1.3", "@types/ws": "^7.2.4", From 9b0e58c41e1d9c16ab1084130f7ca66a89120340 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 4 Dec 2020 11:45:37 +0100 Subject: [PATCH 12/99] Complete file upload --- .../src/lib/file-explorer-menu.tsx | 290 ++++++++++++++++ .../file-explorer/src/lib/file-explorer.tsx | 323 ++---------------- .../file-explorer/src/lib/types/index.ts | 9 + 3 files changed, 335 insertions(+), 287 deletions(-) create mode 100644 libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx new file mode 100644 index 0000000000..1bf52d37f4 --- /dev/null +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx @@ -0,0 +1,290 @@ +import React, { useState, useEffect } from 'react' //eslint-disable-line +import { FileExplorerMenuProps } from './types' +import * as helper from '../../../../../apps/remix-ide/src/lib/helper' +import * as async from 'async' +import Gists from 'gists' +import QueryParams from '../../../../../apps/remix-ide/src/lib/query-params' + +const queryParams = new QueryParams() + +function packageFiles (filesProvider, directory, callback) { + const ret = {} + filesProvider.resolveDirectory(directory, (error, files) => { + if (error) callback(error) + else { + async.eachSeries(Object.keys(files), (path, cb) => { + if (filesProvider.isDirectory(path)) { + cb() + } else { + filesProvider.get(path, (error, content) => { + if (error) return cb(error) + if (/^\s+$/.test(content) || !content.length) { + content = '// this line is added to create a gist. Empty file is not allowed.' + } + ret[path] = { content } + cb() + }) + } + }, (error) => { + callback(error, ret) + }) + } + }) +} + +export const FileExplorerMenu = (props: FileExplorerMenuProps) => { + const [state, setState] = useState({ + menuItems: [ + { + action: 'createNewFile', + title: 'Create New File', + icon: 'fas fa-plus-circle' + }, + { + action: 'publishToGist', + title: 'Publish all [browser] explorer files to a github gist', + icon: 'fab fa-github' + }, + { + action: 'uploadFile', + title: 'Add Local file to the Browser Storage Explorer', + icon: 'far fa-folder-open' + }, + { + action: 'updateGist', + title: 'Update the current [gist] explorer', + icon: 'fab fa-github' + } + ].filter(item => props.menuItems && props.menuItems.find((name) => { return name === item.action })), + actions: {} + }) + + useEffect(() => { + const actions = { + updateGist: () => {}, + uploadFile + } + + setState(prevState => { + return { ...prevState, actions } + }) + }, []) + + const createNewFile = (parentFolder = 'browser/Folder 2') => { + // const self = this + // modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => { + // if (!input) input = 'New file' + // get filename from state (state.newFileName) + const fileManager = props.fileManager + const newFileName = parentFolder + '/' + 'unnamed' + Math.floor(Math.random() * 101) + + helper.createNonClashingName(newFileName, props.files, async (error, newName) => { + // if (error) return tooltip('Failed to create file ' + newName + ' ' + error) + if (error) return + const createFile = await fileManager.writeFile(newName, '') + + if (!createFile) { + // tooltip('Failed to create file ' + newName) + } else { + props.addFile(parentFolder, newFileName) + await fileManager.open(newName) + } + }) + // }, null, true) + } + + const uploadFile = (target) => { + // TODO The file explorer is merely a view on the current state of + // the files module. Please ask the user here if they want to overwrite + // a file and then just use `files.add`. The file explorer will + // pick that up via the 'fileAdded' event from the files module. + + [...target.files].forEach((file) => { + const files = props.files + + function loadFile (name: string): void { + const fileReader = new FileReader() + + fileReader.onload = async function (event) { + if (helper.checkSpecialChars(file.name)) { + // modalDialogCustom.alert('Special characters are not allowed') + return + } + const success = await files.set(name, event.target.result) + + if (!success) { + // modalDialogCustom.alert('Failed to create file ' + name) + } else { + props.addFile(props.title, name) + await props.fileManager.open(name) + } + } + fileReader.readAsText(file) + } + const name = files.type + '/' + file.name + + files.exists(name, (error, exist) => { + if (error) console.log(error) + if (!exist) { + loadFile(name) + } else { + // modalDialogCustom.confirm('Confirm overwrite', `The file ${name} already exists! Would you like to overwrite it?`, () => { loadFile() }) + } + }) + }) + } + + const publishToGist = () => { + // modalDialogCustom.confirm( + // 'Create a public gist', + // 'Are you sure you want to publish all your files in browser directory anonymously as a public gist on github.com? Note: this will not include directories.', + // () => { this.toGist() } + toGist() + // ) + } + + const toGist = (id?: string) => { + const proccedResult = function (error, data) { + if (error) { + // modalDialogCustom.alert('Failed to manage gist: ' + error) + console.log('Failed to manage gist: ' + error) + } else { + if (data.html_url) { + // modalDialogCustom.confirm('Gist is ready', `The gist is at ${data.html_url}. Would you like to open it in a new window?`, () => { + // window.open(data.html_url, '_blank') + // }) + } else { + // modalDialogCustom.alert(data.message + ' ' + data.documentation_url + ' ' + JSON.stringify(data.errors, null, '\t')) + } + } + } + + /** + * This function is to get the original content of given gist + * @params id is the gist id to fetch + */ + async function getOriginalFiles (id) { + if (!id) { + return [] + } + + const url = `https://api.github.com/gists/${id}` + const res = await fetch(url) + const data = await res.json() + return data.files || [] + } + + // If 'id' is not defined, it is not a gist update but a creation so we have to take the files from the browser explorer. + const folder = id ? 'browser/gists/' + id : 'browser/' + packageFiles(props.files, folder, (error, packaged) => { + if (error) { + console.log(error) + // modalDialogCustom.alert('Failed to create gist: ' + error.message) + } else { + // check for token + if (!props.accessToken) { + // modalDialogCustom.alert( + // 'Remix requires an access token (which includes gists creation permission). Please go to the settings tab to create one.' + // ) + } else { + const description = 'Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. \n Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=' + + queryParams.get().version + '&optimize=' + queryParams.get().optimize + '&runs=' + queryParams.get().runs + '&gist=' + const gists = new Gists({ token: props.accessToken }) + + if (id) { + const originalFileList = getOriginalFiles(id) + // Telling the GIST API to remove files + const updatedFileList = Object.keys(packaged) + const allItems = Object.keys(originalFileList) + .filter(fileName => updatedFileList.indexOf(fileName) === -1) + .reduce((acc, deleteFileName) => ({ + ...acc, + [deleteFileName]: null + }), originalFileList) + // adding new files + updatedFileList.forEach((file) => { + const _items = file.split('/') + const _fileName = _items[_items.length - 1] + allItems[_fileName] = packaged[file] + }) + + // tooltip('Saving gist (' + id + ') ...') + gists.edit({ + description: description, + public: true, + files: allItems, + id: id + }, (error, result) => { + proccedResult(error, result) + if (!error) { + for (const key in allItems) { + if (allItems[key] === null) delete allItems[key] + } + } + }) + } else { + // id is not existing, need to create a new gist + // tooltip('Creating a new gist ...') + gists.create({ + description: description, + public: true, + files: packaged + }, (error, result) => { + proccedResult(error, result) + }) + } + } + } + }) + } + + return ( + <> + { props.title } + { + state.menuItems.map(({ action, title, icon }, index) => { + if (action === 'uploadFile') { + return ( + + ) + } else { + return ( + { + e.stopPropagation() + if (action === 'createNewFile') { + createNewFile() + } else if (action === 'publishToGist') { + publishToGist() + } else { + state.actions[action]() + } + }} + className={'newFile ' + icon + ' remixui_newFile'} + title={title} + key={index} + > + + ) + } + })} + + + ) +} + +export default FileExplorerMenu diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 6b1882fd7e..ca1e1d8cb9 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -1,131 +1,33 @@ import React, { useEffect, useState, useRef } from 'react' // eslint-disable-line import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd' // eslint-disable-line -import * as async from 'async' -import * as Gists from 'gists' -import * as helper from '../../../../../apps/remix-ide/src/lib/helper' -import QueryParams from '../../../../../apps/remix-ide/src/lib/query-params' +import { FileExplorerMenu } from './file-explorer-menu' // eslint-disable-line import { FileExplorerProps, File } from './types' import './css/file-explorer.css' -const queryParams = new QueryParams() - -function packageFiles (filesProvider, directory, callback) { - const ret = {} - filesProvider.resolveDirectory(directory, (error, files) => { - if (error) callback(error) - else { - async.eachSeries(Object.keys(files), (path, cb) => { - if (filesProvider.isDirectory(path)) { - cb() - } else { - filesProvider.get(path, (error, content) => { - if (error) return cb(error) - if (/^\s+$/.test(content) || !content.length) { - content = '// this line is added to create a gist. Empty file is not allowed.' - } - ret[path] = { content } - cb() - }) - } - }, (error) => { - callback(error, ret) - }) - } - }) -} - export const FileExplorer = (props: FileExplorerProps) => { const { files, name, registry, plugin } = props - const uploadFile = (target) => { - // TODO The file explorer is merely a view on the current state of - // the files module. Please ask the user here if they want to overwrite - // a file and then just use `files.add`. The file explorer will - // pick that up via the 'fileAdded' event from the files module. - - [...target.files].forEach((file) => { - const files = props.files - - function loadFile () { - const fileReader = new FileReader() - - fileReader.onload = async function (event) { - if (helper.checkSpecialChars(file.name)) { - // modalDialogCustom.alert('Special characters are not allowed') - return - } - const success = await files.set(name, event.target.result) - - if (!success) { - // modalDialogCustom.alert('Failed to create file ' + name) - } else { - // self.events.trigger('focus', [name]) - } - } - fileReader.readAsText(file) - } - const name = files.type + '/' + file.name - - files.exists(name, (error, exist) => { - if (error) console.log(error) - if (!exist) { - loadFile() - } else { - // modalDialogCustom.confirm('Confirm overwrite', `The file ${name} already exists! Would you like to overwrite it?`, () => { loadFile() }) - } - }) - }) - } const containerRef = useRef(null) const [state, setState] = useState({ focusElement: [], focusPath: null, - menuItems: [ - { - action: 'createNewFile', - title: 'Create New File', - icon: 'fas fa-plus-circle' - }, - { - action: 'publishToGist', - title: 'Publish all [browser] explorer files to a github gist', - icon: 'fab fa-github' - }, - { - action: 'uploadFile', - title: 'Add Local file to the Browser Storage Explorer', - icon: 'far fa-folder-open' - }, - { - action: 'updateGist', - title: 'Update the current [gist] explorer', - icon: 'fab fa-github' - } - ].filter(item => props.menuItems && props.menuItems.find((name) => { return name === item.action })), files: [], - actions: {}, fileManager: null, - tokenAccess: null, + accessToken: null, ctrlKey: false, newFileName: '' }) useEffect(() => { (async () => { - console.log('registry: ', registry) const fileManager = registry.get('filemanager').api const config = registry.get('config').api - const tokenAccess = config.get('settings/gist-access-token').api + const accessToken = config.get('settings/gist-access-token') const files = await fetchDirectoryContent(name) - const actions = { - updateGist: () => {}, - uploadFile, - publishToGist - } setState(prevState => { - return { ...prevState, fileManager, tokenAccess, files, actions } + return { ...prevState, fileManager, accessToken, files } }) })() }, []) @@ -183,153 +85,35 @@ export const FileExplorer = (props: FileExplorerProps) => { return [...folders, ...files] } - const extractNameFromKey = (key) => { + const extractNameFromKey = (key: string):string => { const keyPath = key.split('/') return keyPath[keyPath.length - 1] } - const createNewFile = (parentFolder = 'browser') => { - // const self = this - // modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => { - // if (!input) input = 'New file' - // get filename from state (state.newFileName) - const fileManager = state.fileManager - const newFileName = parentFolder + '/' + 'unnamed' + Math.floor(Math.random() * 101) - - helper.createNonClashingName(newFileName, files, async (error, newName) => { - // if (error) return tooltip('Failed to create file ' + newName + ' ' + error) - if (error) return - const createFile = await fileManager.writeFile(newName, '') - - if (!createFile) { - // tooltip('Failed to create file ' + newName) - } else { - if (parentFolder === name) { - // const updatedFiles = await resolveDirectory(parentFolder, state.files) - - setState(prevState => { - return { - ...prevState, - files: [...prevState.files, { - path: newFileName, - name: extractNameFromKey(newFileName), - isDirectory: false - }] - } - }) - } - await fileManager.open(newName) - if (newName.includes('_test.sol')) { - plugin.events.trigger('newTestFileCreated', [newName]) + const addFile = async (parentFolder: string, newFileName: string) => { + if (parentFolder === name) { + setState(prevState => { + return { + ...prevState, + files: [...prevState.files, { + path: newFileName, + name: extractNameFromKey(newFileName), + isDirectory: false + }], + focusElement: [newFileName] } - } - }) - // }, null, true) - } - - const publishToGist = () => { - // modalDialogCustom.confirm( - // 'Create a public gist', - // 'Are you sure you want to publish all your files in browser directory anonymously as a public gist on github.com? Note: this will not include directories.', - // () => { this.toGist() } - toGist() - // ) - } + }) + } else { + const updatedFiles = await resolveDirectory(parentFolder, state.files) - const toGist = (id?: string) => { - const proccedResult = function (error, data) { - if (error) { - // modalDialogCustom.alert('Failed to manage gist: ' + error) - console.log('Failed to manage gist: ' + error) - } else { - if (data.html_url) { - // modalDialogCustom.confirm('Gist is ready', `The gist is at ${data.html_url}. Would you like to open it in a new window?`, () => { - // window.open(data.html_url, '_blank') - // }) - } else { - // modalDialogCustom.alert(data.message + ' ' + data.documentation_url + ' ' + JSON.stringify(data.errors, null, '\t')) - } - } + setState(prevState => { + return { ...prevState, files: updatedFiles, focusElement: [newFileName] } + }) } - - /** - * This function is to get the original content of given gist - * @params id is the gist id to fetch - */ - async function getOriginalFiles (id) { - if (!id) { - return [] - } - - const url = `https://api.github.com/gists/${id}` - const res = await fetch(url) - const data = await res.json() - return data.files || [] + if (newFileName.includes('_test.sol')) { + plugin.events.trigger('newTestFileCreated', [newFileName]) } - - // If 'id' is not defined, it is not a gist update but a creation so we have to take the files from the browser explorer. - const folder = id ? 'browser/gists/' + id : 'browser/' - packageFiles(files, folder, (error, packaged) => { - if (error) { - console.log(error) - // modalDialogCustom.alert('Failed to create gist: ' + error.message) - } else { - // check for token - if (!state.tokenAccess) { - // modalDialogCustom.alert( - // 'Remix requires an access token (which includes gists creation permission). Please go to the settings tab to create one.' - // ) - } else { - const description = 'Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. \n Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=' + - queryParams.get().version + '&optimize=' + queryParams.get().optimize + '&runs=' + queryParams.get().runs + '&gist=' - const gists = new Gists({ token: state.tokenAccess }) - - if (id) { - const originalFileList = getOriginalFiles(id) - // Telling the GIST API to remove files - const updatedFileList = Object.keys(packaged) - const allItems = Object.keys(originalFileList) - .filter(fileName => updatedFileList.indexOf(fileName) === -1) - .reduce((acc, deleteFileName) => ({ - ...acc, - [deleteFileName]: null - }), originalFileList) - // adding new files - updatedFileList.forEach((file) => { - const _items = file.split('/') - const _fileName = _items[_items.length - 1] - allItems[_fileName] = packaged[file] - }) - - // tooltip('Saving gist (' + id + ') ...') - gists.edit({ - description: description, - public: true, - files: allItems, - id: id - }, (error, result) => { - proccedResult(error, result) - if (!error) { - for (const key in allItems) { - if (allItems[key] === null) delete allItems[key] - } - } - }) - } else { - // id is not existing, need to create a new gist - // tooltip('Creating a new gist ...') - gists.create({ - description: description, - public: true, - files: packaged - }, (error, result) => { - proccedResult(error, result) - }) - } - } - } - }) } // self._components = {} @@ -445,52 +229,6 @@ export const FileExplorer = (props: FileExplorerProps) => { } } - const renderMenuItems = () => { - let items - if (state.menuItems) { - items = state.menuItems.map(({ action, title, icon }, index) => { - if (action === 'uploadFile') { - return ( - - ) - } else { - return ( - { - e.stopPropagation() - action === 'createNewFile' ? createNewFile() : state.actions[action]() - }} - className={'newFile ' + icon + ' remixui_newFile'} - title={title} - key={index} - > - - ) - } - }) - } - return ( - <> - { name } - {items} - - ) - } - const renderFiles = (file, index) => { if (file.isDirectory) { return ( @@ -566,7 +304,18 @@ export const FileExplorer = (props: FileExplorerProps) => { }} > - + + } + expand={true}> {(provided) => ( diff --git a/libs/remix-ui/file-explorer/src/lib/types/index.ts b/libs/remix-ui/file-explorer/src/lib/types/index.ts index e8cfa73f38..08ba0b9477 100644 --- a/libs/remix-ui/file-explorer/src/lib/types/index.ts +++ b/libs/remix-ui/file-explorer/src/lib/types/index.ts @@ -13,3 +13,12 @@ export interface File { isDirectory: boolean, child?: File[] } + +export interface FileExplorerMenuProps { + title: string, + menuItems: string[], + fileManager: any, + addFile: (parent: string, fileName: string) => void, + files: any, + accessToken: string +} From 8ffadf3742e547191bfb727cc620776e32cb7e6c Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Sun, 6 Dec 2020 20:00:35 +0100 Subject: [PATCH 13/99] Include context menu --- .../src/lib/file-explorer-menu.tsx | 25 +--- .../file-explorer/src/lib/file-explorer.tsx | 139 +++++++++++++++--- .../file-explorer/src/lib/types/index.ts | 1 + libs/remix-ui/tree-view/src/types/index.ts | 3 +- 4 files changed, 124 insertions(+), 44 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx index 1bf52d37f4..6c4b633a12 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx @@ -70,29 +70,6 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { }) }, []) - const createNewFile = (parentFolder = 'browser/Folder 2') => { - // const self = this - // modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => { - // if (!input) input = 'New file' - // get filename from state (state.newFileName) - const fileManager = props.fileManager - const newFileName = parentFolder + '/' + 'unnamed' + Math.floor(Math.random() * 101) - - helper.createNonClashingName(newFileName, props.files, async (error, newName) => { - // if (error) return tooltip('Failed to create file ' + newName + ' ' + error) - if (error) return - const createFile = await fileManager.writeFile(newName, '') - - if (!createFile) { - // tooltip('Failed to create file ' + newName) - } else { - props.addFile(parentFolder, newFileName) - await fileManager.open(newName) - } - }) - // }, null, true) - } - const uploadFile = (target) => { // TODO The file explorer is merely a view on the current state of // the files module. Please ask the user here if they want to overwrite @@ -267,7 +244,7 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { onClick={(e) => { e.stopPropagation() if (action === 'createNewFile') { - createNewFile() + props.createNewFile() } else if (action === 'publishToGist') { publishToGist() } else { diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index ca1e1d8cb9..ce956c59ea 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -3,12 +3,14 @@ import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-l import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd' // eslint-disable-line import { FileExplorerMenu } from './file-explorer-menu' // eslint-disable-line import { FileExplorerProps, File } from './types' +import * as helper from '../../../../../apps/remix-ide/src/lib/helper' import './css/file-explorer.css' export const FileExplorer = (props: FileExplorerProps) => { const { files, name, registry, plugin } = props const containerRef = useRef(null) + const contextMenuRef = useRef({}) const [state, setState] = useState({ focusElement: [], focusPath: null, @@ -16,7 +18,13 @@ export const FileExplorer = (props: FileExplorerProps) => { fileManager: null, accessToken: null, ctrlKey: false, - newFileName: '' + newFileName: '', + actions: [], + focusContext: { + element: null, + x: null, + y: null + } }) useEffect(() => { @@ -25,9 +33,25 @@ export const FileExplorer = (props: FileExplorerProps) => { const config = registry.get('config').api const accessToken = config.get('settings/gist-access-token') const files = await fetchDirectoryContent(name) + const actions = [{ + name: 'New File', + type: ['folder'] + }, { + name: 'New Folder', + type: ['folder'] + }, { + name: 'Rename', + type: ['file', 'folder'] + }, { + name: 'Delete', + type: ['file', 'folder'] + }, { + name: 'Push changes to gist', + type: [] + }] setState(prevState => { - return { ...prevState, fileManager, accessToken, files } + return { ...prevState, fileManager, accessToken, files, actions } }) })() }, []) @@ -91,6 +115,35 @@ export const FileExplorer = (props: FileExplorerProps) => { return keyPath[keyPath.length - 1] } + const extractParentFromKey = (key: string):string => { + const keyPath = key.split('/') + + return keyPath.pop() + } + + const createNewFile = (parentFolder?: string) => { + if (!parentFolder) parentFolder = extractParentFromKey(state.focusElement[0]) + // const self = this + // modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => { + // if (!input) input = 'New file' + const fileManager = state.fileManager + const newFileName = parentFolder + '/' + 'unnamed' + Math.floor(Math.random() * 101) // get filename from state (state.newFileName) + + helper.createNonClashingName(newFileName, props.files, async (error, newName) => { + // if (error) return tooltip('Failed to create file ' + newName + ' ' + error) + if (error) return + const createFile = await fileManager.writeFile(newName, '') + + if (!createFile) { + // tooltip('Failed to create file ' + newName) + } else { + addFile(parentFolder, newFileName) + await fileManager.open(newName) + } + }) + // }, null, true) + } + const addFile = async (parentFolder: string, newFileName: string) => { if (parentFolder === name) { setState(prevState => { @@ -181,7 +234,7 @@ export const FileExplorer = (props: FileExplorerProps) => { // } // } - const label = (data) => { + const label = (data: File) => { return (
    { ) } + const contextMenu = (actions: { name: string, type: string[] }[], index: number) => { + const menu = actions.map((item) => { + return
  • { + if (item.name === 'Create File') { + createNewFile() + } + setState(prevState => { + return { ...prevState, focusContext: { element: null, x: null, y: null } } + }) + }}>{item.name}
  • + }) + + return ( + + ) + } + const onDragEnd = result => { } @@ -206,7 +286,6 @@ export const FileExplorer = (props: FileExplorerProps) => { setState(prevState => { return { ...prevState, focusElement: [path] } }) - containerRef.current.focus() } const handleClickFolder = async (path) => { @@ -229,7 +308,18 @@ export const FileExplorer = (props: FileExplorerProps) => { } } - const renderFiles = (file, index) => { + const handleContextMenuFile = (pageX, pageY, label) => { + const menuItemsContainer = contextMenuRef.current + const boundary = menuItemsContainer.getBoundingClientRect() + + if (boundary.bottom > (window.innerHeight || document.documentElement.clientHeight)) { + menuItemsContainer.style.position = 'absolute' + menuItemsContainer.style.bottom = '10px' + menuItemsContainer.style.top = null + } + } + + const renderFiles = (file: File, index: number) => { if (file.isDirectory) { return ( @@ -248,6 +338,9 @@ export const FileExplorer = (props: FileExplorerProps) => { }} labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' } controlBehaviour={ state.ctrlKey } + onContextMenu={(e) => { + e.preventDefault() + }} > { file.child ? { @@ -266,20 +359,27 @@ export const FileExplorer = (props: FileExplorerProps) => { return ( {(provided) => ( - { - e.stopPropagation() - handleClickFile(file.path) - }} - icon='fa fa-file' - labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' } - /> + <> + { + e.stopPropagation() + handleClickFile(file.path) + }} + onContextMenu={(e) => { + e.preventDefault() + handleContextMenuFile() + }} + icon='fa fa-file' + labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' } + /> + { contextMenu(state.actions.filter(item => item.type.findIndex(name => name === 'file') !== -1), index) } + )} ) @@ -310,6 +410,7 @@ export const FileExplorer = (props: FileExplorerProps) => { title={name} menuItems={props.menuItems} addFile={addFile} + createNewFile={createNewFile} files={props.files} fileManager={state.fileManager} accessToken={state.accessToken} diff --git a/libs/remix-ui/file-explorer/src/lib/types/index.ts b/libs/remix-ui/file-explorer/src/lib/types/index.ts index 08ba0b9477..581d0acbf5 100644 --- a/libs/remix-ui/file-explorer/src/lib/types/index.ts +++ b/libs/remix-ui/file-explorer/src/lib/types/index.ts @@ -19,6 +19,7 @@ export interface FileExplorerMenuProps { menuItems: string[], fileManager: any, addFile: (parent: string, fileName: string) => void, + createNewFile: () => void, files: any, accessToken: string } diff --git a/libs/remix-ui/tree-view/src/types/index.ts b/libs/remix-ui/tree-view/src/types/index.ts index cf8f850b52..5ac48b2901 100644 --- a/libs/remix-ui/tree-view/src/types/index.ts +++ b/libs/remix-ui/tree-view/src/types/index.ts @@ -15,5 +15,6 @@ export interface TreeViewItemProps { icon?: string, labelClass?: string, controlBehaviour?: boolean - innerRef?: any + innerRef?: any, + onContextMenu?: (...args: any) => void } From d2e931d6a3b987c169d131b2b1fc26fbbeea5764 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Mon, 7 Dec 2020 12:10:57 +0100 Subject: [PATCH 14/99] Focus context menu --- .../lib/css/file-explorer-context-menu.css | 28 ++++++ .../src/lib/file-explorer-context-menu.tsx | 55 ++++++++++++ .../file-explorer/src/lib/file-explorer.tsx | 87 ++++++++----------- .../file-explorer/src/lib/types/index.ts | 10 ++- 4 files changed, 129 insertions(+), 51 deletions(-) create mode 100644 libs/remix-ui/file-explorer/src/lib/css/file-explorer-context-menu.css create mode 100644 libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx diff --git a/libs/remix-ui/file-explorer/src/lib/css/file-explorer-context-menu.css b/libs/remix-ui/file-explorer/src/lib/css/file-explorer-context-menu.css new file mode 100644 index 0000000000..f88c8825a8 --- /dev/null +++ b/libs/remix-ui/file-explorer/src/lib/css/file-explorer-context-menu.css @@ -0,0 +1,28 @@ +.remixui_contextContainer +{ + display: block; + position: fixed; + border-radius: 2px; + z-index: 1000; + box-shadow: 0 0 4px var(--dark); +} +.remixui_contextContainer:focus { + outline: none; +} +.remixui_liitem +{ + padding: 2px; + padding-left: 6px; + cursor: pointer; + color: var(--text-dark); + background-color: var(--light); +} +.remixui_liitem:hover +{ + background-color: var(--secondary); +} +#remixui_menuitems +{ + list-style: none; + margin: 0px; +} \ No newline at end of file diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx new file mode 100644 index 0000000000..6ea088ab44 --- /dev/null +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx @@ -0,0 +1,55 @@ +import React, { useRef, useEffect } from 'react' // eslint-disable-line +import { FileExplorerContextMenuProps } from './types' + +import './css/file-explorer-context-menu.css' + +export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => { + const { actions, createNewFile, hideContextMenu, pageX, pageY, ...otherProps } = props + const contextMenuRef = useRef(null) + + useEffect(() => { + contextMenuRef.current.focus() + }, []) + + useEffect(() => { + const menuItemsContainer = contextMenuRef.current + const boundary = menuItemsContainer.getBoundingClientRect() + + if (boundary.bottom > (window.innerHeight || document.documentElement.clientHeight)) { + menuItemsContainer.style.position = 'absolute' + menuItemsContainer.style.bottom = '10px' + menuItemsContainer.style.top = null + } + }, [pageX, pageY]) + + const menu = () => { + return actions.map((item, index) => { + return
  • { + if (item.name === 'Create File') { + createNewFile() + } + hideContextMenu() + }}>{item.name}
  • + }) + } + + return ( + + ) +} + +export default FileExplorerContextMenu diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index ce956c59ea..8a2e629e37 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -2,6 +2,7 @@ import React, { useEffect, useState, useRef } from 'react' // eslint-disable-lin import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd' // eslint-disable-line import { FileExplorerMenu } from './file-explorer-menu' // eslint-disable-line +import { FileExplorerContextMenu } from './file-explorer-context-menu' import { FileExplorerProps, File } from './types' import * as helper from '../../../../../apps/remix-ide/src/lib/helper' @@ -10,9 +11,11 @@ import './css/file-explorer.css' export const FileExplorer = (props: FileExplorerProps) => { const { files, name, registry, plugin } = props const containerRef = useRef(null) - const contextMenuRef = useRef({}) const [state, setState] = useState({ - focusElement: [], + focusElement: [{ + key: name, + type: 'folder' + }], focusPath: null, files: [], fileManager: null, @@ -116,13 +119,15 @@ export const FileExplorer = (props: FileExplorerProps) => { } const extractParentFromKey = (key: string):string => { + if (!key) return const keyPath = key.split('/') + keyPath.pop() - return keyPath.pop() + return keyPath.join('/') } const createNewFile = (parentFolder?: string) => { - if (!parentFolder) parentFolder = extractParentFromKey(state.focusElement[0]) + if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name // const self = this // modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => { // if (!input) input = 'New file' @@ -154,14 +159,14 @@ export const FileExplorer = (props: FileExplorerProps) => { name: extractNameFromKey(newFileName), isDirectory: false }], - focusElement: [newFileName] + focusElement: [{ key: newFileName, type: 'file' }] } }) } else { const updatedFiles = await resolveDirectory(parentFolder, state.files) setState(prevState => { - return { ...prevState, files: updatedFiles, focusElement: [newFileName] } + return { ...prevState, files: [...updatedFiles], focusElement: [{ key: newFileName, type: 'file' }] } }) } if (newFileName.includes('_test.sol')) { @@ -250,33 +255,6 @@ export const FileExplorer = (props: FileExplorerProps) => { ) } - const contextMenu = (actions: { name: string, type: string[] }[], index: number) => { - const menu = actions.map((item) => { - return
  • { - if (item.name === 'Create File') { - createNewFile() - } - setState(prevState => { - return { ...prevState, focusContext: { element: null, x: null, y: null } } - }) - }}>{item.name}
  • - }) - - return ( - - ) - } - const onDragEnd = result => { } @@ -284,39 +262,40 @@ export const FileExplorer = (props: FileExplorerProps) => { const handleClickFile = (path) => { state.fileManager.open(path) setState(prevState => { - return { ...prevState, focusElement: [path] } + return { ...prevState, focusElement: [{ key: path, type: 'file' }] } }) } const handleClickFolder = async (path) => { if (state.ctrlKey) { - if (state.focusElement.findIndex(item => item === path) !== -1) { + if (state.focusElement.findIndex(item => item.key === path) !== -1) { setState(prevState => { - return { ...prevState, focusElement: [...prevState.focusElement.filter(item => item !== path)] } + return { ...prevState, focusElement: [...prevState.focusElement.filter(item => item.key !== path)] } }) } else { setState(prevState => { - return { ...prevState, focusElement: [...prevState.focusElement, path] } + return { ...prevState, focusElement: [...prevState.focusElement, { key: path, type: 'folder' }] } }) } } else { const files = await resolveDirectory(path, state.files) setState(prevState => { - return { ...prevState, focusElement: [path], files } + return { ...prevState, focusElement: [{ key: path, type: 'folder' }], files } }) } } - const handleContextMenuFile = (pageX, pageY, label) => { - const menuItemsContainer = contextMenuRef.current - const boundary = menuItemsContainer.getBoundingClientRect() + const handleContextMenuFile = (pageX: number, pageY: number, path: string) => { + setState(prevState => { + return { ...prevState, focusContext: { element: path, x: pageX, y: pageY } } + }) + } - if (boundary.bottom > (window.innerHeight || document.documentElement.clientHeight)) { - menuItemsContainer.style.position = 'absolute' - menuItemsContainer.style.bottom = '10px' - menuItemsContainer.style.top = null - } + const hideContextMenu = () => { + setState(prevState => { + return { ...prevState, focusContext: { element: null, x: 0, y: 0 } } + }) } const renderFiles = (file: File, index: number) => { @@ -336,7 +315,7 @@ export const FileExplorer = (props: FileExplorerProps) => { e.stopPropagation() handleClickFolder(file.path) }} - labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' } + labelClass={ state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' } controlBehaviour={ state.ctrlKey } onContextMenu={(e) => { e.preventDefault() @@ -373,12 +352,20 @@ export const FileExplorer = (props: FileExplorerProps) => { }} onContextMenu={(e) => { e.preventDefault() - handleContextMenuFile() + handleContextMenuFile(e.pageX, e.pageY, file.path) }} icon='fa fa-file' - labelClass={ state.focusElement.findIndex(item => item === file.path) !== -1 ? 'bg-secondary' : '' } + labelClass={ state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' } /> - { contextMenu(state.actions.filter(item => item.type.findIndex(name => name === 'file') !== -1), index) } + { (state.focusContext.element === file.path) && + item.type.findIndex(name => name === 'file') !== -1) } + hideContextMenu={hideContextMenu} + createNewFile={createNewFile} + pageX={state.focusContext.x} + pageY={state.focusContext.y} + /> + } )} diff --git a/libs/remix-ui/file-explorer/src/lib/types/index.ts b/libs/remix-ui/file-explorer/src/lib/types/index.ts index 581d0acbf5..ac28a26570 100644 --- a/libs/remix-ui/file-explorer/src/lib/types/index.ts +++ b/libs/remix-ui/file-explorer/src/lib/types/index.ts @@ -19,7 +19,15 @@ export interface FileExplorerMenuProps { menuItems: string[], fileManager: any, addFile: (parent: string, fileName: string) => void, - createNewFile: () => void, + createNewFile: (parentFolder?: string) => void, files: any, accessToken: string } + +export interface FileExplorerContextMenuProps { + actions: { name: string, type: string[] }[], + createNewFile: (parentFolder?: string) => void + hideContextMenu: () => void, + pageX: number, + pageY: number +} From 3eaf4c52d9d7ee64edfb8be731a0673143938ff0 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Mon, 7 Dec 2020 16:29:33 +0100 Subject: [PATCH 15/99] Modify menu items --- .../src/lib/file-explorer-context-menu.tsx | 6 +- .../src/lib/file-explorer-menu.tsx | 2 +- .../file-explorer/src/lib/file-explorer.tsx | 73 ++++++++++++------- .../file-explorer/src/lib/types/index.ts | 9 ++- 4 files changed, 55 insertions(+), 35 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx index 6ea088ab44..aacfc140f0 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx @@ -4,7 +4,7 @@ import { FileExplorerContextMenuProps } from './types' import './css/file-explorer-context-menu.css' export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => { - const { actions, createNewFile, hideContextMenu, pageX, pageY, ...otherProps } = props + const { actions, createNewFile, hideContextMenu, pageX, pageY, folder, ...otherProps } = props const contextMenuRef = useRef(null) useEffect(() => { @@ -29,8 +29,8 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => key={index} className='remixui_liitem' onClick={() => { - if (item.name === 'Create File') { - createNewFile() + if (item.name === 'New File') { + createNewFile(folder) } hideContextMenu() }}>{item.name} diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx index 6c4b633a12..8d290ab8e8 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx @@ -38,7 +38,7 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { { action: 'createNewFile', title: 'Create New File', - icon: 'fas fa-plus-circle' + icon: 'far fa-file' }, { action: 'publishToGist', diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 8a2e629e37..62270ecb2c 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState, useRef } from 'react' // eslint-disable-lin import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd' // eslint-disable-line import { FileExplorerMenu } from './file-explorer-menu' // eslint-disable-line -import { FileExplorerContextMenu } from './file-explorer-context-menu' +import { FileExplorerContextMenu } from './file-explorer-context-menu' // eslint-disable-line import { FileExplorerProps, File } from './types' import * as helper from '../../../../../apps/remix-ide/src/lib/helper' @@ -292,6 +292,12 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } + const handleContextMenuFolder = (pageX: number, pageY: number, path: string) => { + setState(prevState => { + return { ...prevState, focusContext: { element: path, x: pageX, y: pageY } } + }) + } + const hideContextMenu = () => { setState(prevState => { return { ...prevState, focusContext: { element: null, x: 0, y: 0 } } @@ -303,34 +309,47 @@ export const FileExplorer = (props: FileExplorerProps) => { return ( {(provided) => ( - { - e.stopPropagation() - handleClickFolder(file.path) - }} - labelClass={ state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' } - controlBehaviour={ state.ctrlKey } - onContextMenu={(e) => { - e.preventDefault() - }} - > - { - file.child ? { - file.child.map((file, index) => { - return renderFiles(file, index) - }) + <> + { + e.stopPropagation() + handleClickFolder(file.path) + }} + onContextMenu={(e) => { + e.preventDefault() + handleContextMenuFolder(e.pageX, e.pageY, file.path) + }} + labelClass={ state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' } + controlBehaviour={ state.ctrlKey } + > + { + file.child ? { + file.child.map((file, index) => { + return renderFiles(file, index) + }) + } + : } - : + { provided.placeholder } + + { (state.focusContext.element === file.path) && + item.type.findIndex(name => name === 'folder') !== -1) } + hideContextMenu={hideContextMenu} + createNewFile={createNewFile} + pageX={state.focusContext.x} + pageY={state.focusContext.y} + folder={file.path} + /> } - { provided.placeholder } - + )} ) diff --git a/libs/remix-ui/file-explorer/src/lib/types/index.ts b/libs/remix-ui/file-explorer/src/lib/types/index.ts index ac28a26570..c752ab7ee1 100644 --- a/libs/remix-ui/file-explorer/src/lib/types/index.ts +++ b/libs/remix-ui/file-explorer/src/lib/types/index.ts @@ -18,16 +18,17 @@ export interface FileExplorerMenuProps { title: string, menuItems: string[], fileManager: any, - addFile: (parent: string, fileName: string) => void, - createNewFile: (parentFolder?: string) => void, + addFile: (parentFolder: string, fileName: string) => void, + createNewFile: (folder?: string) => void, files: any, accessToken: string } export interface FileExplorerContextMenuProps { actions: { name: string, type: string[] }[], - createNewFile: (parentFolder?: string) => void + createNewFile: (folder?: string) => void hideContextMenu: () => void, pageX: number, - pageY: number + pageY: number, + folder?: string } From 66a0ebb94e542b2117b28e59701163b5632cf000 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Tue, 8 Dec 2020 13:06:24 +0100 Subject: [PATCH 16/99] Create new folder --- apps/remix-ide/src/app/panels/file-panel.js | 2 +- .../src/lib/file-explorer-context-menu.tsx | 5 +- .../src/lib/file-explorer-menu.tsx | 11 +++- .../file-explorer/src/lib/file-explorer.tsx | 59 ++++++++++++++++++- .../file-explorer/src/lib/types/index.ts | 6 +- 5 files changed, 76 insertions(+), 7 deletions(-) diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js index 7ec0d7042b..24450ce050 100644 --- a/apps/remix-ide/src/app/panels/file-panel.js +++ b/apps/remix-ide/src/app/panels/file-panel.js @@ -96,7 +96,7 @@ module.exports = class Filepanel extends ViewPlugin { name='browser' registry={this._components.registry} files={this._deps.fileProviders.browser} - menuItems={['createNewFile', 'publishToGist', canUpload ? 'uploadFile' : '']} + menuItems={['createNewFile', 'createNewFolder', 'publishToGist', canUpload ? 'uploadFile' : '']} plugin={this} /> diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx index aacfc140f0..76fc221fc9 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx @@ -4,7 +4,8 @@ import { FileExplorerContextMenuProps } from './types' import './css/file-explorer-context-menu.css' export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => { - const { actions, createNewFile, hideContextMenu, pageX, pageY, folder, ...otherProps } = props + const { actions, createNewFile, createNewFolder, hideContextMenu, pageX, pageY, folder, ...otherProps } = props + console.log('folder: ', folder) const contextMenuRef = useRef(null) useEffect(() => { @@ -31,6 +32,8 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => onClick={() => { if (item.name === 'New File') { createNewFile(folder) + } else if (item.name === 'New Folder') { + createNewFolder(folder) } hideContextMenu() }}>{item.name} diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx index 8d290ab8e8..44ad137d02 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx @@ -40,6 +40,11 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { title: 'Create New File', icon: 'far fa-file' }, + { + action: 'createNewFolder', + title: 'Create New Folder', + icon: 'far fa-folder' + }, { action: 'publishToGist', title: 'Publish all [browser] explorer files to a github gist', @@ -47,8 +52,8 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { }, { action: 'uploadFile', - title: 'Add Local file to the Browser Storage Explorer', - icon: 'far fa-folder-open' + title: 'Upload Local files to the Browser Storage Explorer', + icon: 'fa fa-upload' }, { action: 'updateGist', @@ -245,6 +250,8 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { e.stopPropagation() if (action === 'createNewFile') { props.createNewFile() + } else if (action === 'createNewFolder') { + props.createNewFolder() } else if (action === 'publishToGist') { publishToGist() } else { diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 62270ecb2c..6b0c71caf0 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -127,7 +127,9 @@ export const FileExplorer = (props: FileExplorerProps) => { } const createNewFile = (parentFolder?: string) => { + console.log('parentFolderBefore: ', parentFolder) if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name + console.log('parentFolderAfter: ', parentFolder) // const self = this // modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => { // if (!input) input = 'New file' @@ -149,6 +151,33 @@ export const FileExplorer = (props: FileExplorerProps) => { // }, null, true) } + const createNewFolder = async (parentFolder?: string) => { + console.log('parentFolderBefore: ', parentFolder) + if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name + else if (parentFolder.indexOf('.sol') !== -1) parentFolder = extractParentFromKey(parentFolder) + console.log('parentFolderAfter: ', parentFolder) + // const self = this + // modalDialogCustom.prompt('Create new folder', '', 'New folder', (input) => { + // if (!input) { + // return tooltip('Failed to create folder. The name can not be empty') + // } + + const fileManager = state.fileManager + const newFolderName = parentFolder + '/' + 'unnamed' + Math.floor(Math.random() * 101) // get filename from state (state.newFileName) + const dirName = newFolderName + '/' + // if (error) return tooltip('Unexpected error while creating folder: ' + error) + const exists = fileManager.exists(dirName) + + if (exists) return + try { + await fileManager.mkdir(dirName) + addFolder(parentFolder, newFolderName) + } catch (e) { + // tooltip('Failed to create file ' + newName) + } + // }, null, true) + } + const addFile = async (parentFolder: string, newFileName: string) => { if (parentFolder === name) { setState(prevState => { @@ -166,7 +195,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const updatedFiles = await resolveDirectory(parentFolder, state.files) setState(prevState => { - return { ...prevState, files: [...updatedFiles], focusElement: [{ key: newFileName, type: 'file' }] } + return { ...prevState, files: updatedFiles, focusElement: [{ key: newFileName, type: 'file' }] } }) } if (newFileName.includes('_test.sol')) { @@ -174,6 +203,28 @@ export const FileExplorer = (props: FileExplorerProps) => { } } + const addFolder = async (parentFolder: string, newFolderName: string) => { + if (parentFolder === name) { + setState(prevState => { + return { + ...prevState, + files: [{ + path: newFolderName, + name: extractNameFromKey(newFolderName), + isDirectory: true + }, ...prevState.files], + focusElement: [{ key: newFolderName, type: 'folder' }] + } + }) + } else { + const updatedFiles = await resolveDirectory(parentFolder, state.files) + + setState(prevState => { + return { ...prevState, files: updatedFiles, focusElement: [{ key: newFolderName, type: 'folder' }] } + }) + } + } + // self._components = {} // self._components.registry = localRegistry || globalRegistry // self._deps = { @@ -293,6 +344,7 @@ export const FileExplorer = (props: FileExplorerProps) => { } const handleContextMenuFolder = (pageX: number, pageY: number, path: string) => { + console.log('path: ', path) setState(prevState => { return { ...prevState, focusContext: { element: path, x: pageX, y: pageY } } }) @@ -324,6 +376,7 @@ export const FileExplorer = (props: FileExplorerProps) => { }} onContextMenu={(e) => { e.preventDefault() + e.stopPropagation() handleContextMenuFolder(e.pageX, e.pageY, file.path) }} labelClass={ state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' } @@ -344,6 +397,7 @@ export const FileExplorer = (props: FileExplorerProps) => { actions={ state.actions.filter(item => item.type.findIndex(name => name === 'folder') !== -1) } hideContextMenu={hideContextMenu} createNewFile={createNewFile} + createNewFolder={createNewFolder} pageX={state.focusContext.x} pageY={state.focusContext.y} folder={file.path} @@ -371,6 +425,7 @@ export const FileExplorer = (props: FileExplorerProps) => { }} onContextMenu={(e) => { e.preventDefault() + e.stopPropagation() handleContextMenuFile(e.pageX, e.pageY, file.path) }} icon='fa fa-file' @@ -381,6 +436,7 @@ export const FileExplorer = (props: FileExplorerProps) => { actions={ state.actions.filter(item => item.type.findIndex(name => name === 'file') !== -1) } hideContextMenu={hideContextMenu} createNewFile={createNewFile} + createNewFolder={createNewFolder} pageX={state.focusContext.x} pageY={state.focusContext.y} /> @@ -417,6 +473,7 @@ export const FileExplorer = (props: FileExplorerProps) => { menuItems={props.menuItems} addFile={addFile} createNewFile={createNewFile} + createNewFolder={createNewFolder} files={props.files} fileManager={state.fileManager} accessToken={state.accessToken} diff --git a/libs/remix-ui/file-explorer/src/lib/types/index.ts b/libs/remix-ui/file-explorer/src/lib/types/index.ts index c752ab7ee1..0c8b1d8ca3 100644 --- a/libs/remix-ui/file-explorer/src/lib/types/index.ts +++ b/libs/remix-ui/file-explorer/src/lib/types/index.ts @@ -18,15 +18,17 @@ export interface FileExplorerMenuProps { title: string, menuItems: string[], fileManager: any, - addFile: (parentFolder: string, fileName: string) => void, + addFile: (folder: string, fileName: string) => void, createNewFile: (folder?: string) => void, + createNewFolder: (parentFolder?: string) => void, files: any, accessToken: string } export interface FileExplorerContextMenuProps { actions: { name: string, type: string[] }[], - createNewFile: (folder?: string) => void + createNewFile: (folder?: string) => void, + createNewFolder: (parentFolder?: string) => void, hideContextMenu: () => void, pageX: number, pageY: number, From c81b5ea79d510592ae846de689f2d122d19774da Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 9 Dec 2020 13:38:18 +0100 Subject: [PATCH 17/99] Make tree view editable --- .../src/lib/file-explorer-context-menu.tsx | 22 +- .../file-explorer/src/lib/file-explorer.tsx | 252 ++++++++++-------- .../file-explorer/src/lib/types/index.ts | 4 +- .../src/lib/tree-view-item/tree-view-item.tsx | 13 +- libs/remix-ui/tree-view/src/types/index.ts | 4 +- 5 files changed, 180 insertions(+), 115 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx index 76fc221fc9..2938bc0562 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx @@ -4,8 +4,7 @@ import { FileExplorerContextMenuProps } from './types' import './css/file-explorer-context-menu.css' export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => { - const { actions, createNewFile, createNewFolder, hideContextMenu, pageX, pageY, folder, ...otherProps } = props - console.log('folder: ', folder) + const { actions, createNewFile, createNewFolder, deletePath, renamePath, hideContextMenu, pageX, pageY, path, ...otherProps } = props const contextMenuRef = useRef(null) useEffect(() => { @@ -30,10 +29,21 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => key={index} className='remixui_liitem' onClick={() => { - if (item.name === 'New File') { - createNewFile(folder) - } else if (item.name === 'New Folder') { - createNewFolder(folder) + switch (item.name) { + case 'New File': + createNewFile(path) + break + case 'New Folder': + createNewFolder(path) + break + case 'Rename': + renamePath(path) + break + case 'Delete': + deletePath(path) + break + default: + break } hideContextMenu() }}>{item.name} diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 6b0c71caf0..0d6cb8b8cb 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -27,6 +27,9 @@ export const FileExplorer = (props: FileExplorerProps) => { element: null, x: null, y: null + }, + focusEdit: { + element: null } }) @@ -127,9 +130,7 @@ export const FileExplorer = (props: FileExplorerProps) => { } const createNewFile = (parentFolder?: string) => { - console.log('parentFolderBefore: ', parentFolder) if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name - console.log('parentFolderAfter: ', parentFolder) // const self = this // modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => { // if (!input) input = 'New file' @@ -152,10 +153,8 @@ export const FileExplorer = (props: FileExplorerProps) => { } const createNewFolder = async (parentFolder?: string) => { - console.log('parentFolderBefore: ', parentFolder) if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name else if (parentFolder.indexOf('.sol') !== -1) parentFolder = extractParentFromKey(parentFolder) - console.log('parentFolderAfter: ', parentFolder) // const self = this // modalDialogCustom.prompt('Create new folder', '', 'New folder', (input) => { // if (!input) { @@ -178,6 +177,39 @@ export const FileExplorer = (props: FileExplorerProps) => { // }, null, true) } + const deletePath = async (path: string) => { + // if (self.files.isReadOnly(key)) { return tooltip('cannot delete file. ' + self.files.type + ' is a read only explorer') } + if (files.isReadOnly(path)) return + // const currentFilename = extractNameFromKey(path) + + // modalDialogCustom.confirm( + // 'Delete file', `Are you sure you want to delete ${currentFilename} file?`, + // async () => { + try { + const fileManager = state.fileManager + + await fileManager.remove(path) + const files = removePath(path, state.files) + const updatedFiles = files.filter(file => file) + + setState(prevState => { + return { ...prevState, files: updatedFiles } + }) + } catch (e) { + console.log('e: ', e) + // tooltip(`Failed to remove file ${key}.`) + } + // }, + // () => {} + // ) + } + + const renamePath = async (path: string) => { + // if (self.files.isReadOnly(key)) { return tooltip('cannot rename folder. ' + self.files.type + ' is a read only explorer') } + if (files.isReadOnly(path)) return + editModeOn(path) + } + const addFile = async (parentFolder: string, newFileName: string) => { if (parentFolder === name) { setState(prevState => { @@ -225,6 +257,21 @@ export const FileExplorer = (props: FileExplorerProps) => { } } + const removePath = (path: string, files: File[]): File[] => { + return files.map(file => { + if (file.path === path) { + return null + } else if (file.child) { + const childFiles = removePath(path, file.child) + + file.child = childFiles.filter(file => file) + return file + } else { + return file + } + }) + } + // self._components = {} // self._components.registry = localRegistry || globalRegistry // self._deps = { @@ -344,7 +391,6 @@ export const FileExplorer = (props: FileExplorerProps) => { } const handleContextMenuFolder = (pageX: number, pageY: number, path: string) => { - console.log('path: ', path) setState(prevState => { return { ...prevState, focusContext: { element: path, x: pageX, y: pageY } } }) @@ -356,94 +402,101 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } + const editModeOn = (path) => { + setState(prevState => { + return { ...prevState, focusEdit: { element: path } } + }) + } + + const editModeOff = (path) => { + setState(prevState => { + return { ...prevState, focusEdit: { element: null } } + }) + } + const renderFiles = (file: File, index: number) => { if (file.isDirectory) { return ( - - {(provided) => ( - <> - { - e.stopPropagation() - handleClickFolder(file.path) - }} - onContextMenu={(e) => { - e.preventDefault() - e.stopPropagation() - handleContextMenuFolder(e.pageX, e.pageY, file.path) - }} - labelClass={ state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' } - controlBehaviour={ state.ctrlKey } - > - { - file.child ? { - file.child.map((file, index) => { - return renderFiles(file, index) - }) - } - : - } - { provided.placeholder } - - { (state.focusContext.element === file.path) && - item.type.findIndex(name => name === 'folder') !== -1) } - hideContextMenu={hideContextMenu} - createNewFile={createNewFile} - createNewFolder={createNewFolder} - pageX={state.focusContext.x} - pageY={state.focusContext.y} - folder={file.path} - /> + <> + { + e.stopPropagation() + handleClickFolder(file.path) + }} + onContextMenu={(e) => { + e.preventDefault() + e.stopPropagation() + handleContextMenuFolder(e.pageX, e.pageY, file.path) + }} + labelClass={ state.focusEdit.element === file.path ? 'bg-light' : state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' } + editable={state.focusEdit.element === file.path} + onBlur={() => editModeOff(file.path)} + controlBehaviour={ state.ctrlKey } + > + { + file.child ? { + file.child.map((file, index) => { + return renderFiles(file, index) + }) } - - )} - +
    : + } +
    + { (state.focusContext.element === file.path) && + item.type.findIndex(name => name === 'folder') !== -1) } + hideContextMenu={hideContextMenu} + createNewFile={createNewFile} + createNewFolder={createNewFolder} + deletePath={deletePath} + renamePath={renamePath} + pageX={state.focusContext.x} + pageY={state.focusContext.y} + path={file.path} + /> + } + ) } else { return ( - - {(provided) => ( - <> - { - e.stopPropagation() - handleClickFile(file.path) - }} - onContextMenu={(e) => { - e.preventDefault() - e.stopPropagation() - handleContextMenuFile(e.pageX, e.pageY, file.path) - }} - icon='fa fa-file' - labelClass={ state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' } - /> - { (state.focusContext.element === file.path) && - item.type.findIndex(name => name === 'file') !== -1) } - hideContextMenu={hideContextMenu} - createNewFile={createNewFile} - createNewFolder={createNewFolder} - pageX={state.focusContext.x} - pageY={state.focusContext.y} - /> - } - - )} - + <> + { + e.stopPropagation() + if (state.focusEdit.element !== file.path) handleClickFile(file.path) + }} + onContextMenu={(e) => { + e.preventDefault() + e.stopPropagation() + handleContextMenuFile(e.pageX, e.pageY, file.path) + }} + icon='fa fa-file' + labelClass={ state.focusEdit.element === file.path ? 'bg-light' : state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' } + editable={state.focusEdit.element === file.path} + onBlur={() => editModeOff(file.path)} + /> + { (state.focusContext.element === file.path) && + item.type.findIndex(name => name === 'file') !== -1) } + hideContextMenu={hideContextMenu} + createNewFile={createNewFile} + createNewFolder={createNewFolder} + deletePath={deletePath} + renamePath={renamePath} + pageX={state.focusContext.x} + pageY={state.focusContext.y} + path={file.path} + /> + } + ) } } @@ -480,24 +533,15 @@ export const FileExplorer = (props: FileExplorerProps) => { /> } expand={true}> - - - {(provided) => ( -
    - - { - state.files.map((file, index) => { - return renderFiles(file, index) - }) - } - - { provided.placeholder } -
    - )} -
    -
    +
    + + { + state.files.map((file, index) => { + return renderFiles(file, index) + }) + } + +
    diff --git a/libs/remix-ui/file-explorer/src/lib/types/index.ts b/libs/remix-ui/file-explorer/src/lib/types/index.ts index 0c8b1d8ca3..eef9b209ee 100644 --- a/libs/remix-ui/file-explorer/src/lib/types/index.ts +++ b/libs/remix-ui/file-explorer/src/lib/types/index.ts @@ -29,8 +29,10 @@ export interface FileExplorerContextMenuProps { actions: { name: string, type: string[] }[], createNewFile: (folder?: string) => void, createNewFolder: (parentFolder?: string) => void, + deletePath: (path: string) => void, + renamePath: (path: string) => void hideContextMenu: () => void, pageX: number, pageY: number, - folder?: string + path: string } diff --git a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx index c570de5f07..76b4e92b00 100644 --- a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx +++ b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx @@ -1,21 +1,28 @@ -import React, { useState, useEffect } from 'react' // eslint-disable-line +import React, { useState, useEffect, useRef } from 'react' // eslint-disable-line import { TreeViewItemProps } from '../../types' import './tree-view-item.css' export const TreeViewItem = (props: TreeViewItemProps) => { - const { id, children, label, labelClass, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon, controlBehaviour = false, innerRef, ...otherProps } = props + const { id, children, label, labelClass, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon, controlBehaviour = false, innerRef, editable, ...otherProps } = props const [isExpanded, setIsExpanded] = useState(false) + const contentRef = useRef(null) useEffect(() => { setIsExpanded(expand) }, [expand]) + useEffect(() => { + if (editable) { + contentRef.current.focus() + } + }, [editable]) + return (
  • !controlBehaviour && setIsExpanded(!isExpanded)}> { children ?
    : icon ?
    : null } - + { label }
    diff --git a/libs/remix-ui/tree-view/src/types/index.ts b/libs/remix-ui/tree-view/src/types/index.ts index 5ac48b2901..94a3edd4bb 100644 --- a/libs/remix-ui/tree-view/src/types/index.ts +++ b/libs/remix-ui/tree-view/src/types/index.ts @@ -16,5 +16,7 @@ export interface TreeViewItemProps { labelClass?: string, controlBehaviour?: boolean innerRef?: any, - onContextMenu?: (...args: any) => void + onContextMenu?: (...args: any) => void, + editable?: boolean, + onBlur?: (...args: any) => void } From 138208b9cfed2cc4ff0272b26d07ce536e374014 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 11 Dec 2020 11:23:53 +0100 Subject: [PATCH 18/99] Fixed rename bug --- apps/remix-ide/src/app/panels/file-panel.js | 2 +- .../src/lib/file-explorer-context-menu.tsx | 7 +- .../file-explorer/src/lib/file-explorer.tsx | 86 +++++++++++++------ .../file-explorer/src/lib/types/index.ts | 7 +- .../src/lib/tree-view-item/tree-view-item.tsx | 15 +++- libs/remix-ui/tree-view/src/types/index.ts | 1 + 6 files changed, 83 insertions(+), 35 deletions(-) diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js index 24450ce050..1be971fb35 100644 --- a/apps/remix-ide/src/app/panels/file-panel.js +++ b/apps/remix-ide/src/app/panels/file-panel.js @@ -95,7 +95,7 @@ module.exports = class Filepanel extends ViewPlugin { diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx index 2938bc0562..c8d4c5fb5f 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx @@ -4,7 +4,7 @@ import { FileExplorerContextMenuProps } from './types' import './css/file-explorer-context-menu.css' export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => { - const { actions, createNewFile, createNewFolder, deletePath, renamePath, hideContextMenu, pageX, pageY, path, ...otherProps } = props + const { actions, createNewFile, createNewFolder, deletePath, renamePath, hideContextMenu, pageX, pageY, path, type, ...otherProps } = props const contextMenuRef = useRef(null) useEffect(() => { @@ -23,12 +23,13 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => }, [pageX, pageY]) const menu = () => { - return actions.map((item, index) => { + return actions.filter(item => item.type.findIndex(name => name === type) !== -1).map((item, index) => { return
  • { + onClick={(e) => { + e.stopPropagation() switch (item.name) { case 'New File': createNewFile(path) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 0d6cb8b8cb..866ae26547 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -9,7 +9,7 @@ import * as helper from '../../../../../apps/remix-ide/src/lib/helper' import './css/file-explorer.css' export const FileExplorer = (props: FileExplorerProps) => { - const { files, name, registry, plugin } = props + const { filesProvider, name, registry, plugin } = props const containerRef = useRef(null) const [state, setState] = useState({ focusElement: [{ @@ -80,7 +80,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const fetchDirectoryContent = async (folderPath: string): Promise => { return new Promise((resolve) => { - files.resolveDirectory(folderPath, (error, fileTree) => { + filesProvider.resolveDirectory(folderPath, (error, fileTree) => { if (error) console.error(error) const files = normalize(folderPath, fileTree) @@ -137,7 +137,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const fileManager = state.fileManager const newFileName = parentFolder + '/' + 'unnamed' + Math.floor(Math.random() * 101) // get filename from state (state.newFileName) - helper.createNonClashingName(newFileName, props.files, async (error, newName) => { + helper.createNonClashingName(newFileName, filesProvider, async (error, newName) => { // if (error) return tooltip('Failed to create file ' + newName + ' ' + error) if (error) return const createFile = await fileManager.writeFile(newName, '') @@ -179,7 +179,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const deletePath = async (path: string) => { // if (self.files.isReadOnly(key)) { return tooltip('cannot delete file. ' + self.files.type + ' is a read only explorer') } - if (files.isReadOnly(path)) return + if (filesProvider.isReadOnly(path)) return // const currentFilename = extractNameFromKey(path) // modalDialogCustom.confirm( @@ -204,10 +204,22 @@ export const FileExplorer = (props: FileExplorerProps) => { // ) } - const renamePath = async (path: string) => { - // if (self.files.isReadOnly(key)) { return tooltip('cannot rename folder. ' + self.files.type + ' is a read only explorer') } - if (files.isReadOnly(path)) return - editModeOn(path) + const renamePath = async (oldPath: string, newPath: string) => { + try { + const fileManager = state.fileManager + const exists = fileManager.exists(newPath) + + if (exists) return + // modalDialogCustom.alert(File already exists.) + await fileManager.rename(oldPath, newPath) + const files = await replacePath(oldPath, newPath, state.files) + + setState(prevState => { + return { ...prevState, files } + }) + } catch (error) { + // modalDialogCustom.alert('Unexpected error while renaming: ' + error) + } } const addFile = async (parentFolder: string, newFileName: string) => { @@ -272,6 +284,24 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } + const replacePath = (oldPath: string, newPath: string, files: File[]): File[] => { + return files.map(file => { + if (file.path === oldPath) { + return { + ...file, + path: newPath, + name: extractNameFromKey(newPath) + } + } else if (file.child) { + file.child = replacePath(oldPath, newPath, file.child) + + return file + } else { + return file + } + }) + } + // self._components = {} // self._components.registry = localRegistry || globalRegistry // self._deps = { @@ -344,8 +374,6 @@ export const FileExplorer = (props: FileExplorerProps) => { title={data.path} className={'remixui_label ' + (data.isDirectory ? 'folder' : 'remixui_leaf')} data-path={data.path} - // onkeydown=${editModeOff} - // onblur=${editModeOff} > { data.path.split('/').pop() } @@ -353,18 +381,14 @@ export const FileExplorer = (props: FileExplorerProps) => { ) } - const onDragEnd = result => { - - } - - const handleClickFile = (path) => { + const handleClickFile = (path: string) => { state.fileManager.open(path) setState(prevState => { return { ...prevState, focusElement: [{ key: path, type: 'file' }] } }) } - const handleClickFolder = async (path) => { + const handleClickFolder = async (path: string) => { if (state.ctrlKey) { if (state.focusElement.findIndex(item => item.key === path) !== -1) { setState(prevState => { @@ -402,13 +426,23 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } - const editModeOn = (path) => { + const editModeOn = (path: string) => { + if (filesProvider.isReadOnly(path)) return setState(prevState => { return { ...prevState, focusEdit: { element: path } } }) } - const editModeOff = (path) => { + const editModeOff = (content: string) => { + if (!content) return + if (helper.checkSpecialChars(content)) { + // modalDialogCustom.alert('Special characters are not allowed') + } + const oldPath = state.focusEdit.element + const oldName = extractNameFromKey(oldPath) + const newPath = oldPath.replace(oldName, content) + + renamePath(oldPath, newPath) setState(prevState => { return { ...prevState, focusEdit: { element: null } } }) @@ -435,7 +469,7 @@ export const FileExplorer = (props: FileExplorerProps) => { }} labelClass={ state.focusEdit.element === file.path ? 'bg-light' : state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' } editable={state.focusEdit.element === file.path} - onBlur={() => editModeOff(file.path)} + onBlur={(value) => editModeOff(value)} controlBehaviour={ state.ctrlKey } > { @@ -449,15 +483,16 @@ export const FileExplorer = (props: FileExplorerProps) => { { (state.focusContext.element === file.path) && item.type.findIndex(name => name === 'folder') !== -1) } + actions={state.actions} hideContextMenu={hideContextMenu} createNewFile={createNewFile} createNewFolder={createNewFolder} deletePath={deletePath} - renamePath={renamePath} + renamePath={editModeOn} pageX={state.focusContext.x} pageY={state.focusContext.y} path={file.path} + type='folder' /> } @@ -481,19 +516,20 @@ export const FileExplorer = (props: FileExplorerProps) => { icon='fa fa-file' labelClass={ state.focusEdit.element === file.path ? 'bg-light' : state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' } editable={state.focusEdit.element === file.path} - onBlur={() => editModeOff(file.path)} + onBlur={(value) => editModeOff(value)} /> { (state.focusContext.element === file.path) && item.type.findIndex(name => name === 'file') !== -1) } + actions={state.actions} hideContextMenu={hideContextMenu} createNewFile={createNewFile} createNewFolder={createNewFolder} deletePath={deletePath} - renamePath={renamePath} + renamePath={editModeOn} pageX={state.focusContext.x} pageY={state.focusContext.y} path={file.path} + type='file' /> } @@ -527,7 +563,7 @@ export const FileExplorer = (props: FileExplorerProps) => { addFile={addFile} createNewFile={createNewFile} createNewFolder={createNewFolder} - files={props.files} + files={filesProvider} fileManager={state.fileManager} accessToken={state.accessToken} /> diff --git a/libs/remix-ui/file-explorer/src/lib/types/index.ts b/libs/remix-ui/file-explorer/src/lib/types/index.ts index eef9b209ee..09b24ebd7b 100644 --- a/libs/remix-ui/file-explorer/src/lib/types/index.ts +++ b/libs/remix-ui/file-explorer/src/lib/types/index.ts @@ -2,7 +2,7 @@ export interface FileExplorerProps { name: string, registry: any, - files: any, + filesProvider: any, menuItems?: string[], plugin: any } @@ -30,9 +30,10 @@ export interface FileExplorerContextMenuProps { createNewFile: (folder?: string) => void, createNewFolder: (parentFolder?: string) => void, deletePath: (path: string) => void, - renamePath: (path: string) => void + renamePath: (path: string) => void, hideContextMenu: () => void, pageX: number, pageY: number, - path: string + path: string, + type: string } diff --git a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx index 76b4e92b00..59d0b9821d 100644 --- a/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx +++ b/libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx @@ -4,7 +4,7 @@ import { TreeViewItemProps } from '../../types' import './tree-view-item.css' export const TreeViewItem = (props: TreeViewItemProps) => { - const { id, children, label, labelClass, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon, controlBehaviour = false, innerRef, editable, ...otherProps } = props + const { id, children, label, labelClass, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon, controlBehaviour = false, innerRef, editable, onBlur, ...otherProps } = props const [isExpanded, setIsExpanded] = useState(false) const contentRef = useRef(null) @@ -18,11 +18,20 @@ export const TreeViewItem = (props: TreeViewItemProps) => { } }, [editable]) + const handleInput = (event) => { + if (editable) { + if (event.which === 13) { + event.preventDefault() + onBlur && onBlur(contentRef.current.innerText) + } + } + } + return ( -
  • +
  • editable && onBlur(contentRef.current.innerText)} {...otherProps}>
    !controlBehaviour && setIsExpanded(!isExpanded)}> { children ?
    : icon ?
    : null } - + { label }
    diff --git a/libs/remix-ui/tree-view/src/types/index.ts b/libs/remix-ui/tree-view/src/types/index.ts index 94a3edd4bb..b5d0273c24 100644 --- a/libs/remix-ui/tree-view/src/types/index.ts +++ b/libs/remix-ui/tree-view/src/types/index.ts @@ -9,6 +9,7 @@ export interface TreeViewItemProps { label: string | number | React.ReactNode, expand?: boolean, onClick?: (...args: any) => void, + onInput?: (...args: any) => void, className?: string, iconX?: string, iconY?: string, From a25a12ea3de07b1c5ffc230566b7d41e0d7b513f Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Mon, 14 Dec 2020 12:44:24 +0100 Subject: [PATCH 19/99] Add new file throughinput --- apps/remix-ide/src/app/files/remixd-handle.js | 2 +- apps/remix-ide/src/app/panels/file-panel.js | 49 +++-- .../src/lib/file-explorer-context-menu.tsx | 2 +- .../file-explorer/src/lib/file-explorer.tsx | 199 ++++++++++++------ .../file-explorer/src/lib/types/index.ts | 2 +- 5 files changed, 163 insertions(+), 91 deletions(-) diff --git a/apps/remix-ide/src/app/files/remixd-handle.js b/apps/remix-ide/src/app/files/remixd-handle.js index 311883e020..8d706441d7 100644 --- a/apps/remix-ide/src/app/files/remixd-handle.js +++ b/apps/remix-ide/src/app/files/remixd-handle.js @@ -83,7 +83,7 @@ export class RemixdHandle extends WebsocketPlugin { this.canceled() } }, 3000) - this.locahostProvider.init(_ => this.fileSystemExplorer.ensureRoot()) + this.locahostProvider.init() this.call('manager', 'activatePlugin', 'git') } } diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js index 1be971fb35..9617ed68af 100644 --- a/apps/remix-ide/src/app/panels/file-panel.js +++ b/apps/remix-ide/src/app/panels/file-panel.js @@ -54,29 +54,40 @@ module.exports = class Filepanel extends ViewPlugin { fileManager: this._components.registry.get('filemanager').api, config: this._components.registry.get('config').api } - this.el = yo` + this.hideRemixdExplorer = true + this.remixdExplorer = { + hide: () => { + this.hideRemixdExplorer = true + this.renderComponent() + }, + show: () => { + this.hideRemixdExplorer = false + this.renderComponent() + } + } + this.el = yo`
    ` - this.remixdHandle = new RemixdHandle({}, this._deps.fileProviders.localhost, appManager) + this.remixdHandle = new RemixdHandle(this.remixdExplorer, this._deps.fileProviders.localhost, appManager) this.event = new EventManager() // fileExplorer.ensureRoot() this._deps.fileProviders.localhost.event.register('connecting', (event) => { }) - this._deps.fileProviders.localhost.event.register('connected', (event) => { - fileSystemExplorer.show() - }) + // this._deps.fileProviders.localhost.event.register('connected', (event) => { + // fileSystemExplorer.show() + // }) - this._deps.fileProviders.localhost.event.register('errored', (event) => { - fileSystemExplorer.hide() - }) + // this._deps.fileProviders.localhost.event.register('errored', (event) => { + // fileSystemExplorer.hide() + // }) - this._deps.fileProviders.localhost.event.register('closed', (event) => { - fileSystemExplorer.hide() - }) + // this._deps.fileProviders.localhost.event.register('closed', (event) => { + // fileSystemExplorer.hide() + // }) this.renderComponent() } @@ -101,13 +112,15 @@ module.exports = class Filepanel extends ViewPlugin { />
    - {/* */} + { !this.hideRemixdExplorer && + + }
    diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx index c8d4c5fb5f..01fb51d6fe 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx @@ -38,7 +38,7 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => createNewFolder(path) break case 'Rename': - renamePath(path) + renamePath(path, type) break case 'Delete': deletePath(path) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 866ae26547..55bec650c7 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -29,8 +29,11 @@ export const FileExplorer = (props: FileExplorerProps) => { y: null }, focusEdit: { - element: null - } + element: null, + type: '', + isNew: false + }, + fileExternallyChanged: false }) useEffect(() => { @@ -94,7 +97,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const files = [] const prefix = path.split('/')[0] - Object.keys(filesList).forEach(key => { + Object.keys(filesList || {}).forEach(key => { const path = prefix + '/' + key if (filesList[key].isDirectory) { @@ -129,15 +132,11 @@ export const FileExplorer = (props: FileExplorerProps) => { return keyPath.join('/') } - const createNewFile = (parentFolder?: string) => { - if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name - // const self = this - // modalDialogCustom.prompt('Create new file', 'File Name (e.g Untitled.sol)', 'Untitled.sol', (input) => { - // if (!input) input = 'New file' + const createNewFile = (parentFolder: string, newFilePath: string) => { + // if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name const fileManager = state.fileManager - const newFileName = parentFolder + '/' + 'unnamed' + Math.floor(Math.random() * 101) // get filename from state (state.newFileName) - helper.createNonClashingName(newFileName, filesProvider, async (error, newName) => { + helper.createNonClashingName(newFilePath, filesProvider, async (error, newName) => { // if (error) return tooltip('Failed to create file ' + newName + ' ' + error) if (error) return const createFile = await fileManager.writeFile(newName, '') @@ -145,7 +144,7 @@ export const FileExplorer = (props: FileExplorerProps) => { if (!createFile) { // tooltip('Failed to create file ' + newName) } else { - addFile(parentFolder, newFileName) + addFile(parentFolder, newFilePath) await fileManager.open(newName) } }) @@ -196,7 +195,6 @@ export const FileExplorer = (props: FileExplorerProps) => { return { ...prevState, files: updatedFiles } }) } catch (e) { - console.log('e: ', e) // tooltip(`Failed to remove file ${key}.`) } // }, @@ -212,7 +210,7 @@ export const FileExplorer = (props: FileExplorerProps) => { if (exists) return // modalDialogCustom.alert(File already exists.) await fileManager.rename(oldPath, newPath) - const files = await replacePath(oldPath, newPath, state.files) + const files = replacePath(oldPath, newPath, state.files) setState(prevState => { return { ...prevState, files } @@ -222,31 +220,60 @@ export const FileExplorer = (props: FileExplorerProps) => { } } - const addFile = async (parentFolder: string, newFileName: string) => { + const addFile = async (parentFolder: string, newFilePath: string) => { if (parentFolder === name) { setState(prevState => { return { ...prevState, files: [...prevState.files, { - path: newFileName, - name: extractNameFromKey(newFileName), + path: newFilePath, + name: extractNameFromKey(newFilePath), isDirectory: false }], - focusElement: [{ key: newFileName, type: 'file' }] + focusElement: [{ key: newFilePath, type: 'file' }] } }) } else { const updatedFiles = await resolveDirectory(parentFolder, state.files) setState(prevState => { - return { ...prevState, files: updatedFiles, focusElement: [{ key: newFileName, type: 'file' }] } + return { ...prevState, files: updatedFiles, focusElement: [{ key: newFilePath, type: 'file' }] } }) } - if (newFileName.includes('_test.sol')) { - plugin.events.trigger('newTestFileCreated', [newFileName]) + if (newFilePath.includes('_test.sol')) { + plugin.events.trigger('newTestFileCreated', [newFilePath]) } } + const addEmptyFile = (parentFolder: string, files: File[]): File[] => { + if (parentFolder === name) { + files.push({ + path: 'browser/blank', + name: '', + isDirectory: false + }) + return files + } + return files.map(file => { + if (file.child) { + if (file.path === parentFolder) { + file.child = [...file.child, { + path: file.path + '/blank', + name: '', + isDirectory: false + }] + return file + } else { + file.child = addEmptyFile(parentFolder, file.child) + + return file + } + } else { + return file + } + }) + } + const addFolder = async (parentFolder: string, newFolderName: string) => { if (parentFolder === name) { setState(prevState => { @@ -302,21 +329,6 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } - // self._components = {} - // self._components.registry = localRegistry || globalRegistry - // self._deps = { - // config: self._components.registry.get('config').api, - // editor: self._components.registry.get('editor').api, - // fileManager: self._components.registry.get('filemanager').api - // } - - // self._components.registry.put({ api: self, name: `fileexplorer/${self.files.type}` }) - - // warn if file changed outside of Remix - // function remixdDialog () { - // return yo`
    This file has been changed outside of Remix IDE.
    ` - // } - // props.files.event.register('fileExternallyChanged', (path, file) => { // if (self._deps.config.get('currentFile') === path && self._deps.editor.currentContent() && self._deps.editor.currentContent() !== file.content) { // if (this.files.isReadOnly(path)) return self._deps.editor.setText(file.content) @@ -367,20 +379,6 @@ export const FileExplorer = (props: FileExplorerProps) => { // } // } - const label = (data: File) => { - return ( -
    - - { data.path.split('/').pop() } - -
    - ) - } - const handleClickFile = (path: string) => { state.fileManager.open(path) setState(prevState => { @@ -426,32 +424,93 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } - const editModeOn = (path: string) => { + const editModeOn = (path: string, type: string, isNew: boolean = false) => { if (filesProvider.isReadOnly(path)) return setState(prevState => { - return { ...prevState, focusEdit: { element: path } } + return { ...prevState, focusEdit: { element: path, isNew, type } } }) } - const editModeOff = (content: string) => { - if (!content) return - if (helper.checkSpecialChars(content)) { + const editModeOff = async (content: string) => { + const parentFolder = state.focusEdit.type === 'folder' ? state.focusEdit.element : extractParentFromKey(state.focusEdit.element) + + if (!content || (content.trim() === '')) { + if (state.focusEdit.isNew) { + const files = removePath(state.focusEdit.element, state.files) + const updatedFiles = files.filter(file => file) + + setState(prevState => { + return { ...prevState, files: updatedFiles, focusEdit: { element: null, isNew: false, type: '' } } + }) + } else { + // modalDialogCustom.alert('Are you sure you want to delete this file?') + if (true) { // eslint-disable-line + await deletePath(state.focusEdit.element) + + setState(prevState => { + return { ...prevState, focusEdit: { element: null, isNew: false, type: '' } } + }) + } else { + + } + } + return + } + if (state.focusEdit.isNew) { + createNewFile(parentFolder, parentFolder + '/' + content) + const files = removePath(state.focusEdit.element, state.files) + const updatedFiles = files.filter(file => file) + + setState(prevState => { + return { ...prevState, files: updatedFiles } + }) + } else { + if (helper.checkSpecialChars(content)) return // modalDialogCustom.alert('Special characters are not allowed') + const oldPath: string = state.focusEdit.element + const oldName = extractNameFromKey(oldPath) + const newPath = oldPath.replace(oldName, content) + + renamePath(oldPath, newPath) } - const oldPath = state.focusEdit.element - const oldName = extractNameFromKey(oldPath) - const newPath = oldPath.replace(oldName, content) + setState(prevState => { + return { ...prevState, focusEdit: { element: null, isNew: false, type: '' } } + }) + } + + const handleNewFileInput = (parentFolder?: string) => { + if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name - renamePath(oldPath, newPath) + const files = addEmptyFile(parentFolder, state.files) setState(prevState => { - return { ...prevState, focusEdit: { element: null } } + return { ...prevState, files } }) + editModeOn(parentFolder + '/blank', 'file', true) + } + + // warn if file changed outside of Remix + const remixdDialog = () => { + return
    This file has been changed outside of Remix IDE.
    + } + + const label = (data: File) => { + return ( +
    + + { data.name } + +
    + ) } const renderFiles = (file: File, index: number) => { if (file.isDirectory) { return ( - <> +
    { } : } - - { (state.focusContext.element === file.path) && + { ((state.focusContext.element === file.path) && (state.focusEdit.element !== file.path)) && { path={file.path} type='folder' /> - } - + } + +
    ) } else { return ( - <> +
    { editable={state.focusEdit.element === file.path} onBlur={(value) => editModeOff(value)} /> - { (state.focusContext.element === file.path) && + { ((state.focusContext.element === file.path) && (state.focusEdit.element !== file.path)) && { type='file' /> } - +
    ) } } @@ -561,7 +620,7 @@ export const FileExplorer = (props: FileExplorerProps) => { title={name} menuItems={props.menuItems} addFile={addFile} - createNewFile={createNewFile} + createNewFile={handleNewFileInput} createNewFolder={createNewFolder} files={filesProvider} fileManager={state.fileManager} diff --git a/libs/remix-ui/file-explorer/src/lib/types/index.ts b/libs/remix-ui/file-explorer/src/lib/types/index.ts index 09b24ebd7b..2e18e13154 100644 --- a/libs/remix-ui/file-explorer/src/lib/types/index.ts +++ b/libs/remix-ui/file-explorer/src/lib/types/index.ts @@ -30,7 +30,7 @@ export interface FileExplorerContextMenuProps { createNewFile: (folder?: string) => void, createNewFolder: (parentFolder?: string) => void, deletePath: (path: string) => void, - renamePath: (path: string) => void, + renamePath: (path: string, type: string) => void, hideContextMenu: () => void, pageX: number, pageY: number, From e07b38f1566ad19536f8ce83ee8cc0e478f34e82 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Mon, 14 Dec 2020 18:59:31 +0100 Subject: [PATCH 20/99] Add folder from input in file-explorer --- .../file-explorer/src/lib/file-explorer.tsx | 75 ++++++++++++++----- 1 file changed, 57 insertions(+), 18 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 55bec650c7..50d44ccb9a 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -144,16 +144,16 @@ export const FileExplorer = (props: FileExplorerProps) => { if (!createFile) { // tooltip('Failed to create file ' + newName) } else { - addFile(parentFolder, newFilePath) + addFile(parentFolder, newName) await fileManager.open(newName) } }) // }, null, true) } - const createNewFolder = async (parentFolder?: string) => { - if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name - else if (parentFolder.indexOf('.sol') !== -1) parentFolder = extractParentFromKey(parentFolder) + const createNewFolder = async (parentFolder: string, newFolderPath: string) => { + // if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name + // else if (parentFolder.indexOf('.sol') !== -1) parentFolder = extractParentFromKey(parentFolder) // const self = this // modalDialogCustom.prompt('Create new folder', '', 'New folder', (input) => { // if (!input) { @@ -161,15 +161,14 @@ export const FileExplorer = (props: FileExplorerProps) => { // } const fileManager = state.fileManager - const newFolderName = parentFolder + '/' + 'unnamed' + Math.floor(Math.random() * 101) // get filename from state (state.newFileName) - const dirName = newFolderName + '/' + const dirName = newFolderPath + '/' // if (error) return tooltip('Unexpected error while creating folder: ' + error) const exists = fileManager.exists(dirName) if (exists) return try { await fileManager.mkdir(dirName) - addFolder(parentFolder, newFolderName) + addFolder(parentFolder, newFolderPath) } catch (e) { // tooltip('Failed to create file ' + newName) } @@ -296,6 +295,35 @@ export const FileExplorer = (props: FileExplorerProps) => { } } + const addEmptyFolder = (parentFolder: string, files: File[]): File[] => { + if (parentFolder === name) { + files.unshift({ + path: 'browser/blank', + name: '', + isDirectory: true + }) + return files + } + return files.map(file => { + if (file.child) { + if (file.path === parentFolder) { + file.child = [{ + path: file.path + '/blank', + name: '', + isDirectory: true + }, ...file.child] + return file + } else { + file.child = addEmptyFolder(parentFolder, file.child) + + return file + } + } else { + return file + } + }) + } + const removePath = (path: string, files: File[]): File[] => { return files.map(file => { if (file.path === path) { @@ -432,7 +460,7 @@ export const FileExplorer = (props: FileExplorerProps) => { } const editModeOff = async (content: string) => { - const parentFolder = state.focusEdit.type === 'folder' ? state.focusEdit.element : extractParentFromKey(state.focusEdit.element) + const parentFolder = extractParentFromKey(state.focusEdit.element) if (!content || (content.trim() === '')) { if (state.focusEdit.isNew) { @@ -457,7 +485,7 @@ export const FileExplorer = (props: FileExplorerProps) => { return } if (state.focusEdit.isNew) { - createNewFile(parentFolder, parentFolder + '/' + content) + state.focusEdit.type === 'file' ? createNewFile(parentFolder, parentFolder + '/' + content) : createNewFolder(parentFolder, parentFolder + '/' + content) const files = removePath(state.focusEdit.element, state.files) const updatedFiles = files.filter(file => file) @@ -480,14 +508,25 @@ export const FileExplorer = (props: FileExplorerProps) => { const handleNewFileInput = (parentFolder?: string) => { if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name - const files = addEmptyFile(parentFolder, state.files) + setState(prevState => { return { ...prevState, files } }) editModeOn(parentFolder + '/blank', 'file', true) } + const handleNewFolderInput = (parentFolder?: string) => { + if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name + else if (parentFolder.indexOf('.sol') !== -1) parentFolder = extractParentFromKey(parentFolder) + const files = addEmptyFolder(parentFolder, state.files) + + setState(prevState => { + return { ...prevState, files } + }) + editModeOn(parentFolder + '/blank', 'folder', true) + } + // warn if file changed outside of Remix const remixdDialog = () => { return
    This file has been changed outside of Remix IDE.
    @@ -539,12 +578,13 @@ export const FileExplorer = (props: FileExplorerProps) => { } : } - { ((state.focusContext.element === file.path) && (state.focusEdit.element !== file.path)) && + + { ((state.focusContext.element === file.path) && (state.focusEdit.element !== file.path)) && { path={file.path} type='folder' /> - } - + } ) } else { @@ -582,7 +621,7 @@ export const FileExplorer = (props: FileExplorerProps) => { actions={state.actions} hideContextMenu={hideContextMenu} createNewFile={handleNewFileInput} - createNewFolder={createNewFolder} + createNewFolder={handleNewFolderInput} deletePath={deletePath} renamePath={editModeOn} pageX={state.focusContext.x} @@ -601,7 +640,7 @@ export const FileExplorer = (props: FileExplorerProps) => { ref={containerRef} tabIndex={-1} onKeyDown={(e) => { - if (e.shiftKey) { + if (e.ctrlKey) { setState(prevState => { return { ...prevState, ctrlKey: true } }) @@ -621,14 +660,14 @@ export const FileExplorer = (props: FileExplorerProps) => { menuItems={props.menuItems} addFile={addFile} createNewFile={handleNewFileInput} - createNewFolder={createNewFolder} + createNewFolder={handleNewFolderInput} files={filesProvider} fileManager={state.fileManager} accessToken={state.accessToken} /> } expand={true}> -
    +
    { state.files.map((file, index) => { From 0a5c9de9b27e5e4e44a661abf81b57b8c9f2833c Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Tue, 15 Dec 2020 09:04:38 +0100 Subject: [PATCH 21/99] Show directory content for new input --- .../file-explorer/src/lib/file-explorer.tsx | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 50d44ccb9a..ecb1e01d34 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -33,7 +33,8 @@ export const FileExplorer = (props: FileExplorerProps) => { type: '', isNew: false }, - fileExternallyChanged: false + fileExternallyChanged: false, + expandPath: [] }) useEffect(() => { @@ -427,9 +428,16 @@ export const FileExplorer = (props: FileExplorerProps) => { } } else { const files = await resolveDirectory(path, state.files) + let expandPath = [] + + if (!state.expandPath.includes(path)) { + expandPath = [...state.expandPath, path] + } else { + expandPath = state.expandPath.filter(key => key !== path) + } setState(prevState => { - return { ...prevState, focusElement: [{ key: path, type: 'folder' }], files } + return { ...prevState, focusElement: [{ key: path, type: 'folder' }], files, expandPath } }) } } @@ -506,23 +514,27 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } - const handleNewFileInput = (parentFolder?: string) => { + const handleNewFileInput = async (parentFolder?: string) => { if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name - const files = addEmptyFile(parentFolder, state.files) + let files = await resolveDirectory(parentFolder, state.files) + const expandPath = [...state.expandPath, parentFolder] + files = addEmptyFile(parentFolder, files) setState(prevState => { - return { ...prevState, files } + return { ...prevState, files, expandPath } }) editModeOn(parentFolder + '/blank', 'file', true) } - const handleNewFolderInput = (parentFolder?: string) => { + const handleNewFolderInput = async (parentFolder?: string) => { if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name else if (parentFolder.indexOf('.sol') !== -1) parentFolder = extractParentFromKey(parentFolder) - const files = addEmptyFolder(parentFolder, state.files) + let files = await resolveDirectory(parentFolder, state.files) + const expandPath = [...state.expandPath, parentFolder] + files = addEmptyFolder(parentFolder, state.files) setState(prevState => { - return { ...prevState, files } + return { ...prevState, files, expandPath } }) editModeOn(parentFolder + '/blank', 'folder', true) } @@ -569,6 +581,7 @@ export const FileExplorer = (props: FileExplorerProps) => { editable={state.focusEdit.element === file.path} onBlur={(value) => editModeOff(value)} controlBehaviour={ state.ctrlKey } + expand={state.expandPath.includes(file.path)} > { file.child ? { From 87bb38838fb90a86bca02940c5c92908f352813f Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 16 Dec 2020 10:41:35 +0100 Subject: [PATCH 22/99] Listen to file added event when loading from gist. --- .env | 2 +- .../file-explorer/src/lib/file-explorer.tsx | 65 ++++++++++++++++++- 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/.env b/.env index 8db17993d7..644e8c49bd 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -gist_token= +gist_token=ef5df4e3822bf121f1aee4616ea110309e2d49f5 account_passphrase= account_password= NODE_OPTIONS=--max-old-space-size=2048 \ No newline at end of file diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index ecb1e01d34..dde43f8bdf 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -7,6 +7,7 @@ import { FileExplorerProps, File } from './types' import * as helper from '../../../../../apps/remix-ide/src/lib/helper' import './css/file-explorer.css' +import { constants } from 'os' export const FileExplorer = (props: FileExplorerProps) => { const { filesProvider, name, registry, plugin } = props @@ -133,6 +134,19 @@ export const FileExplorer = (props: FileExplorerProps) => { return keyPath.join('/') } + const buildTree = (paths: string[]) => { + if (paths.length > 0) { + return { + path: paths[0], + name: extractNameFromKey(paths[0]), + isDirectory: true, + child: [buildTree(paths.filter(item => item !== paths[0]))] + } + } else { + return [] + } + } + const createNewFile = (parentFolder: string, newFilePath: string) => { // if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name const fileManager = state.fileManager @@ -381,7 +395,54 @@ export const FileExplorer = (props: FileExplorerProps) => { // files.event.register('fileRemoved', fileRemoved) // files.event.register('fileRenamed', fileRenamed) // files.event.register('fileRenamedError', fileRenamedError) - // files.event.register('fileAdded', fileAdded) + props.filesProvider.event.register('fileAdded', async (filePath: string) => { + const pathArr = filePath.split('/') + const hasChild = pathArr.length > 2 + + if (hasChild) { + const expandPath = pathArr.map((path, index) => { + return [...pathArr.slice(0, index)].join('/') + }).filter(path => path && (path !== name)) + + if (state.files.findIndex(item => item.path === expandPath[0]) === -1) { + const dir = buildTree(expandPath) + let files = [dir, ...state.files] + + await Promise.all(expandPath.map(async path => { + files = await resolveDirectory(path, files) + })) + setState(prevState => { + return { ...prevState, files, expandPath: [...state.expandPath, ...expandPath] } + }) + } else { + if (state.files.findIndex(item => item.path === expandPath[expandPath.length - 1]) !== -1) return + const dir = state.files.find(item => item.path === expandPath[0]) + let files = [{ + ...dir, + child: [...(await fetchDirectoryContent(dir.path))] + }, ...state.files.filter(item => item.path !== expandPath[0])] + + await Promise.all(expandPath.map(async path => { + files = await resolveDirectory(path, files) + })) + const updatedPath = [state.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(expandPath[0]))] + + setState(prevState => { + return { ...prevState, files, expandPath: [...updatedPath, ...expandPath] } + }) + } + } else { + const files = [...state.files, { + path: filePath, + name: extractNameFromKey(filePath), + isDirectory: false + }] + + setState(prevState => { + return { ...prevState, files } + }) + } + }) // files.event.register('folderAdded', folderAdded) // function fileRenamedError (error) { @@ -433,7 +494,7 @@ export const FileExplorer = (props: FileExplorerProps) => { if (!state.expandPath.includes(path)) { expandPath = [...state.expandPath, path] } else { - expandPath = state.expandPath.filter(key => key !== path) + expandPath = state.expandPath.filter(key => !key.startsWith(path)) } setState(prevState => { From b8455eb48e7312aa5fc78b0155df3c23f4f522e9 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 16 Dec 2020 10:44:12 +0100 Subject: [PATCH 23/99] Fix expand path bug --- libs/remix-ui/file-explorer/src/lib/file-explorer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index dde43f8bdf..84dcb5a972 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -494,7 +494,7 @@ export const FileExplorer = (props: FileExplorerProps) => { if (!state.expandPath.includes(path)) { expandPath = [...state.expandPath, path] } else { - expandPath = state.expandPath.filter(key => !key.startsWith(path)) + expandPath = state.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(path)) } setState(prevState => { From 1be1c050b1b2a06445f71a872487886846d4aa16 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 16 Dec 2020 11:09:33 +0100 Subject: [PATCH 24/99] Fix expand path bug --- .../file-explorer/src/lib/file-explorer.tsx | 28 ++----------------- 1 file changed, 3 insertions(+), 25 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 84dcb5a972..2f36af1d92 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -394,7 +394,9 @@ export const FileExplorer = (props: FileExplorerProps) => { // register to event of the file provider // files.event.register('fileRemoved', fileRemoved) // files.event.register('fileRenamed', fileRenamed) - // files.event.register('fileRenamedError', fileRenamedError) + props.filesProvider.event.register('fileRenamedError', (error) => { + // modalDialogCustom.alert(error) + }) props.filesProvider.event.register('fileAdded', async (filePath: string) => { const pathArr = filePath.split('/') const hasChild = pathArr.length > 2 @@ -445,30 +447,6 @@ export const FileExplorer = (props: FileExplorerProps) => { }) // files.event.register('folderAdded', folderAdded) - // function fileRenamedError (error) { - // modalDialogCustom.alert(error) - // } - - // const fileAdded = (filepath) => { - // const folderpath = filepath.split('/').slice(0, -1).join('/') - // const currentTree = self.treeView.nodeAt(folderpath) - // if (!self.treeView.isExpanded(folderpath)) self.treeView.expand(folderpath) - // if (currentTree) { - // props.files.resolveDirectory(folderpath, (error, fileTree) => { - // if (error) console.error(error) - // if (!fileTree) return - // fileTree = normalize(folderpath, fileTree) - // self.treeView.updateNodeFromJSON(folderpath, fileTree, true) - // self.focusElement = self.treeView.labelAt(self.focusPath) - // // TODO: here we update the selected file (it applicable) - // // cause we are refreshing the interface of the whole directory when there's a new file. - // if (self.focusElement && !self.focusElement.classList.contains('bg-secondary')) { - // self.focusElement.classList.add('bg-secondary') - // } - // }) - // } - // } - const handleClickFile = (path: string) => { state.fileManager.open(path) setState(prevState => { From 6d4af9f6c3908cc585707dc3a2cedf20e332129e Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 17 Dec 2020 09:15:44 +0100 Subject: [PATCH 25/99] Debug events --- .../file-explorer/src/lib/file-explorer.tsx | 83 ++++++++++++++----- 1 file changed, 64 insertions(+), 19 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 2f36af1d92..6deec5326c 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -7,7 +7,7 @@ import { FileExplorerProps, File } from './types' import * as helper from '../../../../../apps/remix-ide/src/lib/helper' import './css/file-explorer.css' -import { constants } from 'os' +import { connected } from 'process' export const FileExplorer = (props: FileExplorerProps) => { const { filesProvider, name, registry, plugin } = props @@ -234,7 +234,7 @@ export const FileExplorer = (props: FileExplorerProps) => { } } - const addFile = async (parentFolder: string, newFilePath: string) => { + const addFile = async (parentFolder: string, newFilePath: string, files?: File[]) => { if (parentFolder === name) { setState(prevState => { return { @@ -248,7 +248,7 @@ export const FileExplorer = (props: FileExplorerProps) => { } }) } else { - const updatedFiles = await resolveDirectory(parentFolder, state.files) + const updatedFiles = await resolveDirectory(parentFolder, files || state.files) setState(prevState => { return { ...prevState, files: updatedFiles, focusElement: [{ key: newFilePath, type: 'file' }] } @@ -288,24 +288,24 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } - const addFolder = async (parentFolder: string, newFolderName: string) => { + const addFolder = async (parentFolder: string, newFolderPath: string, files?: File[]) => { if (parentFolder === name) { setState(prevState => { return { ...prevState, files: [{ - path: newFolderName, - name: extractNameFromKey(newFolderName), + path: newFolderPath, + name: extractNameFromKey(newFolderPath), isDirectory: true }, ...prevState.files], - focusElement: [{ key: newFolderName, type: 'folder' }] + focusElement: [{ key: newFolderPath, type: 'folder' }] } }) } else { - const updatedFiles = await resolveDirectory(parentFolder, state.files) + const updatedFiles = await resolveDirectory(parentFolder, files || state.files) setState(prevState => { - return { ...prevState, files: updatedFiles, focusElement: [{ key: newFolderName, type: 'folder' }] } + return { ...prevState, files: updatedFiles, focusElement: [{ key: newFolderPath, type: 'folder' }] } }) } } @@ -397,6 +397,7 @@ export const FileExplorer = (props: FileExplorerProps) => { props.filesProvider.event.register('fileRenamedError', (error) => { // modalDialogCustom.alert(error) }) + props.filesProvider.event.register('fileAdded', async (filePath: string) => { const pathArr = filePath.split('/') const hasChild = pathArr.length > 2 @@ -417,12 +418,15 @@ export const FileExplorer = (props: FileExplorerProps) => { return { ...prevState, files, expandPath: [...state.expandPath, ...expandPath] } }) } else { - if (state.files.findIndex(item => item.path === expandPath[expandPath.length - 1]) !== -1) return + console.log('called here again') + console.log('expandPath[expandPath.length - 1]: ', expandPath[expandPath.length - 1]) + if (state.expandPath.findIndex(path => path === expandPath[expandPath.length - 1]) !== -1) return const dir = state.files.find(item => item.path === expandPath[0]) let files = [{ ...dir, child: [...(await fetchDirectoryContent(dir.path))] }, ...state.files.filter(item => item.path !== expandPath[0])] + console.log('files: ', files) await Promise.all(expandPath.map(async path => { files = await resolveDirectory(path, files) @@ -434,18 +438,59 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } } else { - const files = [...state.files, { - path: filePath, - name: extractNameFromKey(filePath), - isDirectory: false - }] + addFile(pathArr[0], filePath) + } + }) - setState(prevState => { - return { ...prevState, files } - }) + props.filesProvider.event.register('folderAdded', async (folderpath: string) => { + const pathArr = folderpath.split('/') + const hasChild = pathArr.length > 2 + + if (hasChild) { + const expandPath = pathArr.map((path, index) => { + return [...pathArr.slice(0, index)].join('/') + }).filter(path => path && (path !== name)) + + if (state.files.findIndex(item => item.path === expandPath[0]) === -1) { + const dir = buildTree(expandPath) + let files = [dir, ...state.files] + + await Promise.all(expandPath.map(async path => { + files = await resolveDirectory(path, files) + })) + setState(prevState => { + return { ...prevState, files, expandPath: [...state.expandPath, ...expandPath] } + }) + } else { + if (state.files.findIndex(item => item.path === expandPath[expandPath.length - 1]) !== -1) return + const dir = state.files.find(item => item.path === expandPath[0]) + let files = [{ + ...dir, + child: [...(await fetchDirectoryContent(dir.path))] + }, ...state.files.filter(item => item.path !== expandPath[0])] + + await Promise.all(expandPath.map(async path => { + files = await resolveDirectory(path, files) + })) + const updatedPath = [state.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(expandPath[0]))] + + setState(prevState => { + return { ...prevState, files, expandPath: [...updatedPath, ...expandPath] } + }) + } + } else { + addFolder(pathArr[0], folderpath) } + + // folderpath = folderpath.split('/').slice(0, -1).join('/') + // self.files.resolveDirectory(folderpath, (error, fileTree) => { + // if (error) console.error(error) + // if (!fileTree) return + // fileTree = normalize(folderpath, fileTree) + // self.treeView.updateNodeFromJSON(folderpath, fileTree, true) + // if (!self.treeView.isExpanded(folderpath)) self.treeView.expand(folderpath) + // }) }) - // files.event.register('folderAdded', folderAdded) const handleClickFile = (path: string) => { state.fileManager.open(path) From f4051e79e894449cc09288e05a3dd7f48dcc39c3 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 17 Dec 2020 15:52:04 +0100 Subject: [PATCH 26/99] Pause events --- apps/remix-ide/src/app/panels/file-panel.js | 1 + .../file-explorer/src/lib/file-explorer.tsx | 186 +++++++++--------- package-lock.json | 102 +++++----- package.json | 2 +- 4 files changed, 141 insertions(+), 150 deletions(-) diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js index 9617ed68af..a445a78761 100644 --- a/apps/remix-ide/src/app/panels/file-panel.js +++ b/apps/remix-ide/src/app/panels/file-panel.js @@ -71,6 +71,7 @@ module.exports = class Filepanel extends ViewPlugin { ` this.remixdHandle = new RemixdHandle(this.remixdExplorer, this._deps.fileProviders.localhost, appManager) + this.gitHandle = new GitHandle() this.event = new EventManager() // fileExplorer.ensureRoot() diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 6deec5326c..9a7bbe17df 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -7,7 +7,6 @@ import { FileExplorerProps, File } from './types' import * as helper from '../../../../../apps/remix-ide/src/lib/helper' import './css/file-explorer.css' -import { connected } from 'process' export const FileExplorer = (props: FileExplorerProps) => { const { filesProvider, name, registry, plugin } = props @@ -394,103 +393,94 @@ export const FileExplorer = (props: FileExplorerProps) => { // register to event of the file provider // files.event.register('fileRemoved', fileRemoved) // files.event.register('fileRenamed', fileRenamed) - props.filesProvider.event.register('fileRenamedError', (error) => { - // modalDialogCustom.alert(error) - }) - - props.filesProvider.event.register('fileAdded', async (filePath: string) => { - const pathArr = filePath.split('/') - const hasChild = pathArr.length > 2 - - if (hasChild) { - const expandPath = pathArr.map((path, index) => { - return [...pathArr.slice(0, index)].join('/') - }).filter(path => path && (path !== name)) - - if (state.files.findIndex(item => item.path === expandPath[0]) === -1) { - const dir = buildTree(expandPath) - let files = [dir, ...state.files] - - await Promise.all(expandPath.map(async path => { - files = await resolveDirectory(path, files) - })) - setState(prevState => { - return { ...prevState, files, expandPath: [...state.expandPath, ...expandPath] } - }) - } else { - console.log('called here again') - console.log('expandPath[expandPath.length - 1]: ', expandPath[expandPath.length - 1]) - if (state.expandPath.findIndex(path => path === expandPath[expandPath.length - 1]) !== -1) return - const dir = state.files.find(item => item.path === expandPath[0]) - let files = [{ - ...dir, - child: [...(await fetchDirectoryContent(dir.path))] - }, ...state.files.filter(item => item.path !== expandPath[0])] - console.log('files: ', files) - - await Promise.all(expandPath.map(async path => { - files = await resolveDirectory(path, files) - })) - const updatedPath = [state.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(expandPath[0]))] - - setState(prevState => { - return { ...prevState, files, expandPath: [...updatedPath, ...expandPath] } - }) - } - } else { - addFile(pathArr[0], filePath) - } - }) - - props.filesProvider.event.register('folderAdded', async (folderpath: string) => { - const pathArr = folderpath.split('/') - const hasChild = pathArr.length > 2 - - if (hasChild) { - const expandPath = pathArr.map((path, index) => { - return [...pathArr.slice(0, index)].join('/') - }).filter(path => path && (path !== name)) - - if (state.files.findIndex(item => item.path === expandPath[0]) === -1) { - const dir = buildTree(expandPath) - let files = [dir, ...state.files] - - await Promise.all(expandPath.map(async path => { - files = await resolveDirectory(path, files) - })) - setState(prevState => { - return { ...prevState, files, expandPath: [...state.expandPath, ...expandPath] } - }) - } else { - if (state.files.findIndex(item => item.path === expandPath[expandPath.length - 1]) !== -1) return - const dir = state.files.find(item => item.path === expandPath[0]) - let files = [{ - ...dir, - child: [...(await fetchDirectoryContent(dir.path))] - }, ...state.files.filter(item => item.path !== expandPath[0])] - - await Promise.all(expandPath.map(async path => { - files = await resolveDirectory(path, files) - })) - const updatedPath = [state.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(expandPath[0]))] + // props.filesProvider.event.register('fileRenamedError', (error) => { + // // modalDialogCustom.alert(error) + // }) - setState(prevState => { - return { ...prevState, files, expandPath: [...updatedPath, ...expandPath] } - }) - } - } else { - addFolder(pathArr[0], folderpath) - } + // props.filesProvider.event.register('fileAdded', async (filePath: string) => { + // const pathArr = filePath.split('/') + // const hasChild = pathArr.length > 2 + + // if (hasChild) { + // const expandPath = pathArr.map((path, index) => { + // return [...pathArr.slice(0, index)].join('/') + // }).filter(path => path && (path !== name)) + + // if (state.files.findIndex(item => item.path === expandPath[0]) === -1) { + // const dir = buildTree(expandPath) + // let files = [dir, ...state.files] + + // await Promise.all(expandPath.map(async path => { + // files = await resolveDirectory(path, files) + // })) + // setState(prevState => { + // return { ...prevState, files, expandPath: [...state.expandPath, ...expandPath] } + // }) + // } else { + // console.log('called here again') + // console.log('expandPath[expandPath.length - 1]: ', expandPath[expandPath.length - 1]) + // if (state.expandPath.findIndex(path => path === expandPath[expandPath.length - 1]) !== -1) return + // const dir = state.files.find(item => item.path === expandPath[0]) + // let files = [{ + // ...dir, + // child: [...(await fetchDirectoryContent(dir.path))] + // }, ...state.files.filter(item => item.path !== expandPath[0])] + // console.log('files: ', files) + + // await Promise.all(expandPath.map(async path => { + // files = await resolveDirectory(path, files) + // })) + // const updatedPath = [state.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(expandPath[0]))] + + // setState(prevState => { + // return { ...prevState, files, expandPath: [...updatedPath, ...expandPath] } + // }) + // } + // } else { + // addFile(pathArr[0], filePath) + // } + // }) - // folderpath = folderpath.split('/').slice(0, -1).join('/') - // self.files.resolveDirectory(folderpath, (error, fileTree) => { - // if (error) console.error(error) - // if (!fileTree) return - // fileTree = normalize(folderpath, fileTree) - // self.treeView.updateNodeFromJSON(folderpath, fileTree, true) - // if (!self.treeView.isExpanded(folderpath)) self.treeView.expand(folderpath) - // }) - }) + // props.filesProvider.event.register('folderAdded', async (folderpath: string) => { + // const pathArr = folderpath.split('/') + // const hasChild = pathArr.length > 2 + + // if (hasChild) { + // const expandPath = pathArr.map((path, index) => { + // return [...pathArr.slice(0, index)].join('/') + // }).filter(path => path && (path !== name)) + + // if (state.files.findIndex(item => item.path === expandPath[0]) === -1) { + // const dir = buildTree(expandPath) + // let files = [dir, ...state.files] + + // await Promise.all(expandPath.map(async path => { + // files = await resolveDirectory(path, files) + // })) + // setState(prevState => { + // return { ...prevState, files, expandPath: [...state.expandPath, ...expandPath] } + // }) + // } else { + // if (state.files.findIndex(item => item.path === expandPath[expandPath.length - 1]) !== -1) return + // const dir = state.files.find(item => item.path === expandPath[0]) + // let files = [{ + // ...dir, + // child: [...(await fetchDirectoryContent(dir.path))] + // }, ...state.files.filter(item => item.path !== expandPath[0])] + + // await Promise.all(expandPath.map(async path => { + // files = await resolveDirectory(path, files) + // })) + // const updatedPath = [state.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(expandPath[0]))] + + // setState(prevState => { + // return { ...prevState, files, expandPath: [...updatedPath, ...expandPath] } + // }) + // } + // } else { + // addFolder(pathArr[0], folderpath) + // } + // }) const handleClickFile = (path: string) => { state.fileManager.open(path) @@ -648,8 +638,8 @@ export const FileExplorer = (props: FileExplorerProps) => {
    { diff --git a/package-lock.json b/package-lock.json index e2dbf90fc6..3597de461f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30555,19 +30555,19 @@ "dependencies": { "ansi-regex": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "code-point-at": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, "cross-spawn": { "version": "5.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { @@ -30578,13 +30578,13 @@ }, "decamelize": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "execa": { "version": "0.7.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { @@ -30599,7 +30599,7 @@ }, "find-up": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { @@ -30608,25 +30608,25 @@ }, "get-caller-file": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", "dev": true }, "get-stream": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, "invert-kv": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", "dev": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { @@ -30635,19 +30635,19 @@ }, "is-stream": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, "isexe": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "lcid": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { @@ -30656,7 +30656,7 @@ }, "locate-path": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { @@ -30666,7 +30666,7 @@ }, "lru-cache": { "version": "4.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", "dev": true, "requires": { @@ -30676,7 +30676,7 @@ }, "mem": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { @@ -30685,19 +30685,19 @@ }, "mimic-fn": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=", "dev": true }, "minimist": { "version": "0.0.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, "mkdirp": { "version": "0.5.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { @@ -30706,7 +30706,7 @@ }, "npm-run-path": { "version": "2.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { @@ -30715,13 +30715,13 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, "os-locale": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "dev": true, "requires": { @@ -30732,19 +30732,19 @@ }, "p-finally": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, "p-limit": { "version": "1.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=", "dev": true }, "p-locate": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { @@ -30753,43 +30753,43 @@ }, "path-exists": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, "path-key": { "version": "2.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, "pseudomap": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, "require-directory": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, "require-main-filename": { "version": "1.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, "set-blocking": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, "shebang-command": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { @@ -30798,19 +30798,19 @@ }, "shebang-regex": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, "signal-exit": { "version": "3.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, "string-width": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { @@ -30821,7 +30821,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -30830,13 +30830,13 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, "which": { "version": "1.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", "dev": true, "requires": { @@ -30845,13 +30845,13 @@ }, "which-module": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, "wrap-ansi": { "version": "2.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { @@ -30861,19 +30861,19 @@ }, "y18n": { "version": "3.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", "dev": true }, "yallist": { "version": "2.1.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true }, "yargs": { "version": "10.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.0.3.tgz", "integrity": "sha512-DqBpQ8NAUX4GyPP/ijDGHsJya4tYqLQrjPr95HNsr1YwL3+daCfvBwg7+gIC6IdJhR2kATh3hb61vjzMWEtjdw==", "dev": true, "requires": { @@ -30893,13 +30893,13 @@ "dependencies": { "ansi-regex": { "version": "3.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "cliui": { "version": "3.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "dev": true, "requires": { @@ -30910,7 +30910,7 @@ "dependencies": { "string-width": { "version": "1.0.2", - "resolved": false, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { @@ -30923,7 +30923,7 @@ }, "string-width": { "version": "2.1.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { @@ -30933,13 +30933,13 @@ "dependencies": { "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, "strip-ansi": { "version": "4.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { @@ -30952,7 +30952,7 @@ }, "yargs-parser": { "version": "8.0.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.0.0.tgz", "integrity": "sha1-IdR2Mw5agieaS4gTRb8GYQLiGcY=", "dev": true, "requires": { @@ -30961,7 +30961,7 @@ "dependencies": { "camelcase": { "version": "4.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true } diff --git a/package.json b/package.json index e232e3750a..917b16eb74 100644 --- a/package.json +++ b/package.json @@ -160,7 +160,7 @@ "time-stamp": "^2.2.0", "winston": "^3.3.3", "ws": "^7.3.0" - }, + }, "devDependencies": { "@babel/core": "^7.4.5", "@babel/plugin-transform-modules-amd": "^7.10.4", From 489a1d96a82ae54caba30f5ea5073da28575b355 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 17 Dec 2020 16:48:11 +0100 Subject: [PATCH 27/99] Run linting for tree view in circleci --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 917b16eb74..e207d2c802 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "workspace-schematic": "nx workspace-schematic", "dep-graph": "nx dep-graph", "help": "nx help", - "lint:libs": "nx run-many --target=lint --projects=remixd,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-file-explorer", + "lint:libs": "nx run-many --target=lint --projects=remixd,remix-ui-tree-view,remix-ui-modal-dialog,remix-ui-toaster,remix-ui-file-explorer", "build:libs": "nx run-many --target=build --parallel=false --with-deps=true --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd", "test:libs": "nx run-many --target=test --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd", "publish:libs": "npm run build:libs & lerna publish --skip-git & npm run bumpVersion:libs", From f08a72ef58a5f6c925847e773e2fb00541775415 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 18 Dec 2020 14:47:03 +0100 Subject: [PATCH 28/99] Display modal on delete --- .../file-explorer/src/lib/file-explorer.tsx | 132 ++++++++++++------ .../src/lib/remix-ui-modal-dialog.tsx | 77 +++++----- .../modal-dialog/src/lib/types/index.ts | 14 +- 3 files changed, 137 insertions(+), 86 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 9a7bbe17df..06cd4af7e5 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -3,6 +3,7 @@ import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-l import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd' // eslint-disable-line import { FileExplorerMenu } from './file-explorer-menu' // eslint-disable-line import { FileExplorerContextMenu } from './file-explorer-context-menu' // eslint-disable-line +import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line import { FileExplorerProps, File } from './types' import * as helper from '../../../../../apps/remix-ide/src/lib/helper' @@ -34,7 +35,21 @@ export const FileExplorer = (props: FileExplorerProps) => { isNew: false }, fileExternallyChanged: false, - expandPath: [] + expandPath: [], + modalOptions: { + hide: true, + title: '', + message: '', + ok: { + label: 'Ok', + fn: null + }, + cancel: { + label: 'Cancel', + fn: null + }, + handleHide: null + } }) useEffect(() => { @@ -147,7 +162,6 @@ export const FileExplorer = (props: FileExplorerProps) => { } const createNewFile = (parentFolder: string, newFilePath: string) => { - // if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name const fileManager = state.fileManager helper.createNonClashingName(newFilePath, filesProvider, async (error, newName) => { @@ -166,8 +180,6 @@ export const FileExplorer = (props: FileExplorerProps) => { } const createNewFolder = async (parentFolder: string, newFolderPath: string) => { - // if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name - // else if (parentFolder.indexOf('.sol') !== -1) parentFolder = extractParentFromKey(parentFolder) // const self = this // modalDialogCustom.prompt('Create new folder', '', 'New folder', (input) => { // if (!input) { @@ -192,27 +204,31 @@ export const FileExplorer = (props: FileExplorerProps) => { const deletePath = async (path: string) => { // if (self.files.isReadOnly(key)) { return tooltip('cannot delete file. ' + self.files.type + ' is a read only explorer') } if (filesProvider.isReadOnly(path)) return - // const currentFilename = extractNameFromKey(path) - // modalDialogCustom.confirm( // 'Delete file', `Are you sure you want to delete ${currentFilename} file?`, // async () => { - try { - const fileManager = state.fileManager + const isDir = state.fileManager.isDirectory(path) - await fileManager.remove(path) - const files = removePath(path, state.files) - const updatedFiles = files.filter(file => file) + showModal('Delete file', `Are you sure you want to delete ${path} ${isDir ? 'folder' : 'file'}?`, { + label: 'Ok', + fn: async () => { + try { + const fileManager = state.fileManager + await fileManager.remove(path) + const files = removePath(path, state.files) + const updatedFiles = files.filter(file => file) - setState(prevState => { - return { ...prevState, files: updatedFiles } - }) - } catch (e) { - // tooltip(`Failed to remove file ${key}.`) - } - // }, - // () => {} - // ) + setState(prevState => { + return { ...prevState, files: updatedFiles } + }) + } catch (e) { + // tooltip(`Failed to remove file ${key}.`) + } + } + }, { + label: 'Cancel', + fn: () => {} + }) } const renamePath = async (oldPath: string, newPath: string) => { @@ -482,6 +498,29 @@ export const FileExplorer = (props: FileExplorerProps) => { // } // }) + const handleHideModal = () => { + setState(prevState => { + return { ...prevState, modalOptions: { ...state.modalOptions, hide: true } } + }) + } + + const showModal = (title: string, message: string, ok: { label: string, fn: () => void }, cancel: { label: string, fn: () => void }) => { + setState(prevState => { + return { + ...prevState, + modalOptions: { + ...prevState.modalOptions, + hide: false, + message, + title, + ok, + cancel, + handleHide: handleHideModal + } + } + }) + } + const handleClickFile = (path: string) => { state.fileManager.open(path) setState(prevState => { @@ -564,28 +603,33 @@ export const FileExplorer = (props: FileExplorerProps) => { } } - return - } - if (state.focusEdit.isNew) { - state.focusEdit.type === 'file' ? createNewFile(parentFolder, parentFolder + '/' + content) : createNewFolder(parentFolder, parentFolder + '/' + content) - const files = removePath(state.focusEdit.element, state.files) - const updatedFiles = files.filter(file => file) - - setState(prevState => { - return { ...prevState, files: updatedFiles } - }) } else { - if (helper.checkSpecialChars(content)) return - // modalDialogCustom.alert('Special characters are not allowed') - const oldPath: string = state.focusEdit.element - const oldName = extractNameFromKey(oldPath) - const newPath = oldPath.replace(oldName, content) + if (helper.checkSpecialChars(content)) { + showModal('Validation Error', 'Special characters are not allowed', { + label: 'Ok', + fn: () => {} + }, null) + } else { + if (state.focusEdit.isNew) { + state.focusEdit.type === 'file' ? createNewFile(parentFolder, parentFolder + '/' + content) : createNewFolder(parentFolder, parentFolder + '/' + content) + const files = removePath(state.focusEdit.element, state.files) + const updatedFiles = files.filter(file => file) - renamePath(oldPath, newPath) + setState(prevState => { + return { ...prevState, files: updatedFiles } + }) + } else { + const oldPath: string = state.focusEdit.element + const oldName = extractNameFromKey(oldPath) + const newPath = oldPath.replace(oldName, content) + + renamePath(oldPath, newPath) + } + setState(prevState => { + return { ...prevState, focusEdit: { element: null, isNew: false, type: '' } } + }) + } } - setState(prevState => { - return { ...prevState, focusEdit: { element: null, isNew: false, type: '' } } - }) } const handleNewFileInput = async (parentFolder?: string) => { @@ -602,7 +646,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const handleNewFolderInput = async (parentFolder?: string) => { if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name - else if (parentFolder.indexOf('.sol') !== -1) parentFolder = extractParentFromKey(parentFolder) + else if ((parentFolder.indexOf('.sol') !== -1) || (parentFolder.indexOf('.js') !== -1)) parentFolder = extractParentFromKey(parentFolder) let files = await resolveDirectory(parentFolder, state.files) const expandPath = [...state.expandPath, parentFolder] @@ -765,6 +809,14 @@ export const FileExplorer = (props: FileExplorerProps) => {
    +
    ) } diff --git a/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx b/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx index 243bfd2161..f1b6ba4951 100644 --- a/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx +++ b/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx @@ -9,14 +9,12 @@ export const ModalDialog = (props: ModalDialogProps) => { }) const modal = useRef(null) const handleHide = () => { - props.hide() + props.handleHide() } - useEffect( - () => { - modal.current.focus() - }, [] - ) + useEffect(() => { + modal.current.focus() + }, [props.hide]) const modalKeyEvent = (keyCode) => { if (keyCode === 27) { // Esc @@ -41,74 +39,73 @@ export const ModalDialog = (props: ModalDialogProps) => { } handleHide() } - return (<> + + return ( - ) + ) } export default ModalDialog diff --git a/libs/remix-ui/modal-dialog/src/lib/types/index.ts b/libs/remix-ui/modal-dialog/src/lib/types/index.ts index b127b35bba..414613b361 100644 --- a/libs/remix-ui/modal-dialog/src/lib/types/index.ts +++ b/libs/remix-ui/modal-dialog/src/lib/types/index.ts @@ -1,9 +1,11 @@ export interface ModalDialogProps { title?: string, - content?: JSX.Element, - ok?: {label:string, fn: () => void}, - cancel?: {label:string, fn: () => void}, - focusSelector?: string, - opts?: {class: string, hideClose?: boolean}, - hide: () => void + message?: string, + ok?: { label: string, fn: () => void }, + cancel: { label: string, fn: () => void }, + modalClass?: string, + showCancelIcon?: boolean, + hide: boolean, + handleHide: (hideState?: boolean) => void, + children?: React.ReactNode } From a64cc67ad469519b5716a32b37a8dd639b43a102 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 18 Dec 2020 16:27:39 +0100 Subject: [PATCH 29/99] Debub editable content --- .../file-explorer/src/lib/file-explorer.tsx | 89 +++++++------------ 1 file changed, 32 insertions(+), 57 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 06cd4af7e5..aba532f4f1 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -11,7 +11,6 @@ import './css/file-explorer.css' export const FileExplorer = (props: FileExplorerProps) => { const { filesProvider, name, registry, plugin } = props - const containerRef = useRef(null) const [state, setState] = useState({ focusElement: [{ key: name, @@ -32,7 +31,8 @@ export const FileExplorer = (props: FileExplorerProps) => { focusEdit: { element: null, type: '', - isNew: false + isNew: false, + lastEdit: '' }, fileExternallyChanged: false, expandPath: [], @@ -180,12 +180,6 @@ export const FileExplorer = (props: FileExplorerProps) => { } const createNewFolder = async (parentFolder: string, newFolderPath: string) => { - // const self = this - // modalDialogCustom.prompt('Create new folder', '', 'New folder', (input) => { - // if (!input) { - // return tooltip('Failed to create folder. The name can not be empty') - // } - const fileManager = state.fileManager const dirName = newFolderPath + '/' // if (error) return tooltip('Unexpected error while creating folder: ' + error) @@ -198,18 +192,14 @@ export const FileExplorer = (props: FileExplorerProps) => { } catch (e) { // tooltip('Failed to create file ' + newName) } - // }, null, true) } const deletePath = async (path: string) => { // if (self.files.isReadOnly(key)) { return tooltip('cannot delete file. ' + self.files.type + ' is a read only explorer') } if (filesProvider.isReadOnly(path)) return - // modalDialogCustom.confirm( - // 'Delete file', `Are you sure you want to delete ${currentFilename} file?`, - // async () => { const isDir = state.fileManager.isDirectory(path) - showModal('Delete file', `Are you sure you want to delete ${path} ${isDir ? 'folder' : 'file'}?`, { + modal('Delete file', `Are you sure you want to delete ${path} ${isDir ? 'folder' : 'file'}?`, { label: 'Ok', fn: async () => { try { @@ -236,14 +226,19 @@ export const FileExplorer = (props: FileExplorerProps) => { const fileManager = state.fileManager const exists = fileManager.exists(newPath) - if (exists) return - // modalDialogCustom.alert(File already exists.) - await fileManager.rename(oldPath, newPath) - const files = replacePath(oldPath, newPath, state.files) + if (exists) { + return modal('Create File Failed', 'File already exists', { + label: 'Ok', + fn: async () => {} + }, null) + } else { + await fileManager.rename(oldPath, newPath) + const files = replacePath(oldPath, newPath, state.files) - setState(prevState => { - return { ...prevState, files } - }) + setState(prevState => { + return { ...prevState, files } + }) + } } catch (error) { // modalDialogCustom.alert('Unexpected error while renaming: ' + error) } @@ -504,7 +499,7 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } - const showModal = (title: string, message: string, ok: { label: string, fn: () => void }, cancel: { label: string, fn: () => void }) => { + const modal = (title: string, message: string, ok: { label: string, fn: () => void }, cancel: { label: string, fn: () => void }) => { setState(prevState => { return { ...prevState, @@ -555,15 +550,17 @@ export const FileExplorer = (props: FileExplorerProps) => { } } - const handleContextMenuFile = (pageX: number, pageY: number, path: string) => { + const handleContextMenuFile = (pageX: number, pageY: number, path: string, content: string) => { + if (!content) return setState(prevState => { - return { ...prevState, focusContext: { element: path, x: pageX, y: pageY } } + return { ...prevState, focusContext: { element: path, x: pageX, y: pageY }, focusEdit: { ...prevState.focusEdit, lastEdit: content } } }) } - const handleContextMenuFolder = (pageX: number, pageY: number, path: string) => { + const handleContextMenuFolder = (pageX: number, pageY: number, path: string, content: string) => { + if (!content) return setState(prevState => { - return { ...prevState, focusContext: { element: path, x: pageX, y: pageY } } + return { ...prevState, focusContext: { element: path, x: pageX, y: pageY }, focusEdit: { ...prevState.focusEdit, lastEdit: content } } }) } @@ -576,7 +573,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const editModeOn = (path: string, type: string, isNew: boolean = false) => { if (filesProvider.isReadOnly(path)) return setState(prevState => { - return { ...prevState, focusEdit: { element: path, isNew, type } } + return { ...prevState, focusEdit: { ...prevState.focusEdit, element: path, isNew, type } } }) } @@ -589,23 +586,16 @@ export const FileExplorer = (props: FileExplorerProps) => { const updatedFiles = files.filter(file => file) setState(prevState => { - return { ...prevState, files: updatedFiles, focusEdit: { element: null, isNew: false, type: '' } } + return { ...prevState, files: updatedFiles, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } } }) } else { - // modalDialogCustom.alert('Are you sure you want to delete this file?') - if (true) { // eslint-disable-line - await deletePath(state.focusEdit.element) - - setState(prevState => { - return { ...prevState, focusEdit: { element: null, isNew: false, type: '' } } - }) - } else { - - } + setState(prevState => { + return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } } + }) } } else { if (helper.checkSpecialChars(content)) { - showModal('Validation Error', 'Special characters are not allowed', { + modal('Validation Error', 'Special characters are not allowed', { label: 'Ok', fn: () => {} }, null) @@ -626,7 +616,7 @@ export const FileExplorer = (props: FileExplorerProps) => { renamePath(oldPath, newPath) } setState(prevState => { - return { ...prevState, focusEdit: { element: null, isNew: false, type: '' } } + return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } } }) } } @@ -693,7 +683,7 @@ export const FileExplorer = (props: FileExplorerProps) => { onContextMenu={(e) => { e.preventDefault() e.stopPropagation() - handleContextMenuFolder(e.pageX, e.pageY, file.path) + handleContextMenuFolder(e.pageX, e.pageY, file.path, e.target.textContent) }} labelClass={ state.focusEdit.element === file.path ? 'bg-light' : state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' } editable={state.focusEdit.element === file.path} @@ -740,7 +730,7 @@ export const FileExplorer = (props: FileExplorerProps) => { onContextMenu={(e) => { e.preventDefault() e.stopPropagation() - handleContextMenuFile(e.pageX, e.pageY, file.path) + handleContextMenuFile(e.pageX, e.pageY, file.path, e.target.textContent) }} icon='fa fa-file' labelClass={ state.focusEdit.element === file.path ? 'bg-light' : state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' } @@ -767,22 +757,7 @@ export const FileExplorer = (props: FileExplorerProps) => { } return ( -
    { - if (e.ctrlKey) { - setState(prevState => { - return { ...prevState, ctrlKey: true } - }) - } - }} - onKeyUp={() => { - setState(prevState => { - return { ...prevState, ctrlKey: false } - }) - }} - > +
    Date: Sun, 20 Dec 2020 17:07:10 +0100 Subject: [PATCH 30/99] Revert rename if empty --- .../file-explorer/src/lib/file-explorer.tsx | 74 +++++++++++++------ .../src/lib/tree-view-item/tree-view-item.tsx | 24 +----- libs/remix-ui/tree-view/src/types/index.ts | 1 - 3 files changed, 57 insertions(+), 42 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index aba532f4f1..8efcd45f6d 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -51,6 +51,11 @@ export const FileExplorer = (props: FileExplorerProps) => { handleHide: null } }) + const editRef = useRef(null) + + useEffect(() => { + editRef && editRef.current && editRef.current.focus() + }, [state.focusEdit.element]) useEffect(() => { (async () => { @@ -165,15 +170,20 @@ export const FileExplorer = (props: FileExplorerProps) => { const fileManager = state.fileManager helper.createNonClashingName(newFilePath, filesProvider, async (error, newName) => { - // if (error) return tooltip('Failed to create file ' + newName + ' ' + error) - if (error) return - const createFile = await fileManager.writeFile(newName, '') - - if (!createFile) { - // tooltip('Failed to create file ' + newName) + if (error) { + return modal('Create File Failed', error, { + label: 'Close', + fn: async () => {} + }, null) } else { - addFile(parentFolder, newName) - await fileManager.open(newName) + const createFile = await fileManager.writeFile(newName, '') + + if (!createFile) { + // tooltip('Failed to create file ' + newName) + } else { + addFile(parentFolder, newName) + await fileManager.open(newName) + } } }) // }, null, true) @@ -227,8 +237,8 @@ export const FileExplorer = (props: FileExplorerProps) => { const exists = fileManager.exists(newPath) if (exists) { - return modal('Create File Failed', 'File already exists', { - label: 'Ok', + return modal('Rename File Failed', 'File name already exists', { + label: 'Close', fn: async () => {} }, null) } else { @@ -240,7 +250,10 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } } catch (error) { - // modalDialogCustom.alert('Unexpected error while renaming: ' + error) + modal('Rename File Failed', 'Unexpected error while renaming: ' + error, { + label: 'Close', + fn: async () => {} + }, null) } } @@ -589,11 +602,17 @@ export const FileExplorer = (props: FileExplorerProps) => { return { ...prevState, files: updatedFiles, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } } }) } else { + editRef.current.textContent = state.focusEdit.lastEdit setState(prevState => { return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } } }) } } else { + if (state.focusEdit.lastEdit === content) { + return setState(prevState => { + return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } } + }) + } if (helper.checkSpecialChars(content)) { modal('Validation Error', 'Special characters are not allowed', { label: 'Ok', @@ -647,20 +666,37 @@ export const FileExplorer = (props: FileExplorerProps) => { editModeOn(parentFolder + '/blank', 'folder', true) } + const handleEditInput = (event) => { + if (event.which === 13) { + event.preventDefault() + editModeOff(editRef.current.innerText) + } + } + // warn if file changed outside of Remix const remixdDialog = () => { return
    This file has been changed outside of Remix IDE.
    } - const label = (data: File) => { + const label = (file: File) => { return ( -
    +
    { + e.stopPropagation() + editModeOff(editRef.current.innerText) + }} + > - { data.name } + { file.name }
    ) @@ -686,8 +722,6 @@ export const FileExplorer = (props: FileExplorerProps) => { handleContextMenuFolder(e.pageX, e.pageY, file.path, e.target.textContent) }} labelClass={ state.focusEdit.element === file.path ? 'bg-light' : state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' } - editable={state.focusEdit.element === file.path} - onBlur={(value) => editModeOff(value)} controlBehaviour={ state.ctrlKey } expand={state.expandPath.includes(file.path)} > @@ -734,8 +768,6 @@ export const FileExplorer = (props: FileExplorerProps) => { }} icon='fa fa-file' labelClass={ state.focusEdit.element === file.path ? 'bg-light' : state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' } - editable={state.focusEdit.element === file.path} - onBlur={(value) => editModeOff(value)} /> { ((state.focusContext.element === file.path) && (state.focusEdit.element !== file.path)) && { - const { id, children, label, labelClass, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon, controlBehaviour = false, innerRef, editable, onBlur, ...otherProps } = props + const { id, children, label, labelClass, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon, controlBehaviour = false, innerRef, ...otherProps } = props const [isExpanded, setIsExpanded] = useState(false) - const contentRef = useRef(null) useEffect(() => { setIsExpanded(expand) }, [expand]) - useEffect(() => { - if (editable) { - contentRef.current.focus() - } - }, [editable]) - - const handleInput = (event) => { - if (editable) { - if (event.which === 13) { - event.preventDefault() - onBlur && onBlur(contentRef.current.innerText) - } - } - } - return ( -
  • editable && onBlur(contentRef.current.innerText)} {...otherProps}> +
  • !controlBehaviour && setIsExpanded(!isExpanded)}> { children ?
    : icon ?
    : null } - + { label }
    diff --git a/libs/remix-ui/tree-view/src/types/index.ts b/libs/remix-ui/tree-view/src/types/index.ts index b5d0273c24..1710b461dd 100644 --- a/libs/remix-ui/tree-view/src/types/index.ts +++ b/libs/remix-ui/tree-view/src/types/index.ts @@ -18,6 +18,5 @@ export interface TreeViewItemProps { controlBehaviour?: boolean innerRef?: any, onContextMenu?: (...args: any) => void, - editable?: boolean, onBlur?: (...args: any) => void } From d23cb5a1f23ab7a92ebb0f647863e1722baa42b5 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Sat, 26 Dec 2020 09:36:24 +0100 Subject: [PATCH 31/99] Added toaster messages --- apps/remix-ide/src/app/panels/tab-proxy.js | 2 +- .../file-explorer/src/lib/file-explorer.tsx | 88 +++++++------------ libs/remix-ui/toaster/src/lib/toaster.tsx | 10 ++- 3 files changed, 41 insertions(+), 59 deletions(-) diff --git a/apps/remix-ide/src/app/panels/tab-proxy.js b/apps/remix-ide/src/app/panels/tab-proxy.js index dc571258e4..6af15ad7c3 100644 --- a/apps/remix-ide/src/app/panels/tab-proxy.js +++ b/apps/remix-ide/src/app/panels/tab-proxy.js @@ -194,7 +194,7 @@ export class TabProxy extends Plugin { } this._view.filetabs.addTab({ - id: name, + id: name.split(' ').join(''), title, icon, tooltip: name diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 8efcd45f6d..ffcabbf199 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -1,9 +1,10 @@ import React, { useEffect, useState, useRef } from 'react' // eslint-disable-line -import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd' // eslint-disable-line +import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line +import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line +import { Toaster } from '@remix-ui/toaster' // eslint-disable-line import { FileExplorerMenu } from './file-explorer-menu' // eslint-disable-line import { FileExplorerContextMenu } from './file-explorer-context-menu' // eslint-disable-line -import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line import { FileExplorerProps, File } from './types' import * as helper from '../../../../../apps/remix-ide/src/lib/helper' @@ -49,7 +50,8 @@ export const FileExplorer = (props: FileExplorerProps) => { fn: null }, handleHide: null - } + }, + toasterMsg: '' }) const editRef = useRef(null) @@ -83,6 +85,10 @@ export const FileExplorer = (props: FileExplorerProps) => { setState(prevState => { return { ...prevState, fileManager, accessToken, files, actions } }) + + if (props.filesProvider) { + props.filesProvider.event.register('fileAdded', fileAdded) + } })() }, []) @@ -166,7 +172,7 @@ export const FileExplorer = (props: FileExplorerProps) => { } } - const createNewFile = (parentFolder: string, newFilePath: string) => { + const createNewFile = (newFilePath: string) => { const fileManager = state.fileManager helper.createNonClashingName(newFilePath, filesProvider, async (error, newName) => { @@ -179,20 +185,17 @@ export const FileExplorer = (props: FileExplorerProps) => { const createFile = await fileManager.writeFile(newName, '') if (!createFile) { - // tooltip('Failed to create file ' + newName) - } else { - addFile(parentFolder, newName) - await fileManager.open(newName) + setState(prevState => { + return { ...prevState, toasterMsg: 'Failed to create file ' + newName } + }) } } }) - // }, null, true) } const createNewFolder = async (parentFolder: string, newFolderPath: string) => { const fileManager = state.fileManager const dirName = newFolderPath + '/' - // if (error) return tooltip('Unexpected error while creating folder: ' + error) const exists = fileManager.exists(dirName) if (exists) return @@ -200,13 +203,18 @@ export const FileExplorer = (props: FileExplorerProps) => { await fileManager.mkdir(dirName) addFolder(parentFolder, newFolderPath) } catch (e) { - // tooltip('Failed to create file ' + newName) + setState(prevState => { + return { ...prevState, toasterMsg: 'Failed to create folder: ' + newFolderPath } + }) } } const deletePath = async (path: string) => { - // if (self.files.isReadOnly(key)) { return tooltip('cannot delete file. ' + self.files.type + ' is a read only explorer') } - if (filesProvider.isReadOnly(path)) return + if (filesProvider.isReadOnly(path)) { + return setState(prevState => { + return { ...prevState, toasterMsg: 'cannot delete file. ' + name + ' is a read only explorer' } + }) + } const isDir = state.fileManager.isDirectory(path) modal('Delete file', `Are you sure you want to delete ${path} ${isDir ? 'folder' : 'file'}?`, { @@ -222,7 +230,9 @@ export const FileExplorer = (props: FileExplorerProps) => { return { ...prevState, files: updatedFiles } }) } catch (e) { - // tooltip(`Failed to remove file ${key}.`) + setState(prevState => { + return { ...prevState, toasterMsg: `Failed to remove file ${path}.` } + }) } } }, { @@ -421,49 +431,12 @@ export const FileExplorer = (props: FileExplorerProps) => { // // modalDialogCustom.alert(error) // }) - // props.filesProvider.event.register('fileAdded', async (filePath: string) => { - // const pathArr = filePath.split('/') - // const hasChild = pathArr.length > 2 - - // if (hasChild) { - // const expandPath = pathArr.map((path, index) => { - // return [...pathArr.slice(0, index)].join('/') - // }).filter(path => path && (path !== name)) - - // if (state.files.findIndex(item => item.path === expandPath[0]) === -1) { - // const dir = buildTree(expandPath) - // let files = [dir, ...state.files] - - // await Promise.all(expandPath.map(async path => { - // files = await resolveDirectory(path, files) - // })) - // setState(prevState => { - // return { ...prevState, files, expandPath: [...state.expandPath, ...expandPath] } - // }) - // } else { - // console.log('called here again') - // console.log('expandPath[expandPath.length - 1]: ', expandPath[expandPath.length - 1]) - // if (state.expandPath.findIndex(path => path === expandPath[expandPath.length - 1]) !== -1) return - // const dir = state.files.find(item => item.path === expandPath[0]) - // let files = [{ - // ...dir, - // child: [...(await fetchDirectoryContent(dir.path))] - // }, ...state.files.filter(item => item.path !== expandPath[0])] - // console.log('files: ', files) + const fileAdded = async (filePath: string) => { + const parentFolder = extractParentFromKey(filePath) - // await Promise.all(expandPath.map(async path => { - // files = await resolveDirectory(path, files) - // })) - // const updatedPath = [state.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(expandPath[0]))] - - // setState(prevState => { - // return { ...prevState, files, expandPath: [...updatedPath, ...expandPath] } - // }) - // } - // } else { - // addFile(pathArr[0], filePath) - // } - // }) + addFile(parentFolder, filePath) + await state.fileManager.open(filePath) + } // props.filesProvider.event.register('folderAdded', async (folderpath: string) => { // const pathArr = folderpath.split('/') @@ -620,7 +593,7 @@ export const FileExplorer = (props: FileExplorerProps) => { }, null) } else { if (state.focusEdit.isNew) { - state.focusEdit.type === 'file' ? createNewFile(parentFolder, parentFolder + '/' + content) : createNewFolder(parentFolder, parentFolder + '/' + content) + state.focusEdit.type === 'file' ? createNewFile(parentFolder + '/' + content) : createNewFolder(parentFolder, parentFolder + '/' + content) const files = removePath(state.focusEdit.element, state.files) const updatedFiles = files.filter(file => file) @@ -824,6 +797,7 @@ export const FileExplorer = (props: FileExplorerProps) => { cancel={ state.modalOptions.cancel } handleHide={ handleHideModal } /> + ) } diff --git a/libs/remix-ui/toaster/src/lib/toaster.tsx b/libs/remix-ui/toaster/src/lib/toaster.tsx index 6d3039dbc4..b7573f72cc 100644 --- a/libs/remix-ui/toaster/src/lib/toaster.tsx +++ b/libs/remix-ui/toaster/src/lib/toaster.tsx @@ -89,7 +89,15 @@ export const Toaster = (props: ToasterProps) => { return ( <> - {/* */} + {} + }} + hide={!state.showModal} + handleHide={hideFullMessage} + /> { !state.hide &&
    From 84b776599d9f565664cf6ab8a925f2a8b95eba02 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Mon, 28 Dec 2020 13:19:33 +0100 Subject: [PATCH 32/99] Fix modal conflict --- apps/remix-ide/src/app/ui/modaldialog.js | 12 ++-- .../file-explorer/src/lib/file-explorer.tsx | 61 +++++++++++++++---- .../src/lib/remix-ui-modal-dialog.tsx | 7 +-- 3 files changed, 58 insertions(+), 22 deletions(-) diff --git a/apps/remix-ide/src/app/ui/modaldialog.js b/apps/remix-ide/src/app/ui/modaldialog.js index 7d336a4121..1aeae287a4 100644 --- a/apps/remix-ide/src/app/ui/modaldialog.js +++ b/apps/remix-ide/src/app/ui/modaldialog.js @@ -6,10 +6,10 @@ module.exports = (title, content, ok, cancel, focusSelector, opts) => { let agreed = true let footerIsActive = false opts = opts || {} - var container = document.querySelector('.modal') + var container = document.getElementById('modal-dialog') if (!container) { document.querySelector('body').appendChild(html(opts)) - container = document.querySelector('.modal') + container = document.getElementById('modal-dialog') incomingModal = false } else incomingModal = true @@ -24,8 +24,8 @@ module.exports = (title, content, ok, cancel, focusSelector, opts) => { cancelDiv.innerHTML = (cancel && cancel.label !== undefined) ? cancel.label : 'Cancel' cancelDiv.style.display = cancelDiv.innerHTML === '' ? 'none' : 'inline-block' - var modal = document.querySelector('.modal-body') - var modalTitle = document.querySelector('.modal-header h6') + var modal = document.getElementById('modal-body-id') + var modalTitle = document.getElementById('modal-title-h6') modalTitle.innerHTML = '' if (title) modalTitle.innerText = title @@ -134,12 +134,12 @@ function html (opts) {
  • case 'Delete': deletePath(path) break + case 'Push changes to gist': + publishToGist() + break default: break } diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx index 44ad137d02..5f3376b057 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx @@ -1,36 +1,5 @@ import React, { useState, useEffect } from 'react' //eslint-disable-line import { FileExplorerMenuProps } from './types' -import * as helper from '../../../../../apps/remix-ide/src/lib/helper' -import * as async from 'async' -import Gists from 'gists' -import QueryParams from '../../../../../apps/remix-ide/src/lib/query-params' - -const queryParams = new QueryParams() - -function packageFiles (filesProvider, directory, callback) { - const ret = {} - filesProvider.resolveDirectory(directory, (error, files) => { - if (error) callback(error) - else { - async.eachSeries(Object.keys(files), (path, cb) => { - if (filesProvider.isDirectory(path)) { - cb() - } else { - filesProvider.get(path, (error, content) => { - if (error) return cb(error) - if (/^\s+$/.test(content) || !content.length) { - content = '// this line is added to create a gist. Empty file is not allowed.' - } - ret[path] = { content } - cb() - }) - } - }, (error) => { - callback(error, ret) - }) - } - }) -} export const FileExplorerMenu = (props: FileExplorerMenuProps) => { const [state, setState] = useState({ @@ -66,8 +35,7 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { useEffect(() => { const actions = { - updateGist: () => {}, - uploadFile + updateGist: () => {} } setState(prevState => { @@ -75,151 +43,6 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { }) }, []) - const uploadFile = (target) => { - // TODO The file explorer is merely a view on the current state of - // the files module. Please ask the user here if they want to overwrite - // a file and then just use `files.add`. The file explorer will - // pick that up via the 'fileAdded' event from the files module. - - [...target.files].forEach((file) => { - const files = props.files - - function loadFile (name: string): void { - const fileReader = new FileReader() - - fileReader.onload = async function (event) { - if (helper.checkSpecialChars(file.name)) { - // modalDialogCustom.alert('Special characters are not allowed') - return - } - const success = await files.set(name, event.target.result) - - if (!success) { - // modalDialogCustom.alert('Failed to create file ' + name) - } else { - props.addFile(props.title, name) - await props.fileManager.open(name) - } - } - fileReader.readAsText(file) - } - const name = files.type + '/' + file.name - - files.exists(name, (error, exist) => { - if (error) console.log(error) - if (!exist) { - loadFile(name) - } else { - // modalDialogCustom.confirm('Confirm overwrite', `The file ${name} already exists! Would you like to overwrite it?`, () => { loadFile() }) - } - }) - }) - } - - const publishToGist = () => { - // modalDialogCustom.confirm( - // 'Create a public gist', - // 'Are you sure you want to publish all your files in browser directory anonymously as a public gist on github.com? Note: this will not include directories.', - // () => { this.toGist() } - toGist() - // ) - } - - const toGist = (id?: string) => { - const proccedResult = function (error, data) { - if (error) { - // modalDialogCustom.alert('Failed to manage gist: ' + error) - console.log('Failed to manage gist: ' + error) - } else { - if (data.html_url) { - // modalDialogCustom.confirm('Gist is ready', `The gist is at ${data.html_url}. Would you like to open it in a new window?`, () => { - // window.open(data.html_url, '_blank') - // }) - } else { - // modalDialogCustom.alert(data.message + ' ' + data.documentation_url + ' ' + JSON.stringify(data.errors, null, '\t')) - } - } - } - - /** - * This function is to get the original content of given gist - * @params id is the gist id to fetch - */ - async function getOriginalFiles (id) { - if (!id) { - return [] - } - - const url = `https://api.github.com/gists/${id}` - const res = await fetch(url) - const data = await res.json() - return data.files || [] - } - - // If 'id' is not defined, it is not a gist update but a creation so we have to take the files from the browser explorer. - const folder = id ? 'browser/gists/' + id : 'browser/' - packageFiles(props.files, folder, (error, packaged) => { - if (error) { - console.log(error) - // modalDialogCustom.alert('Failed to create gist: ' + error.message) - } else { - // check for token - if (!props.accessToken) { - // modalDialogCustom.alert( - // 'Remix requires an access token (which includes gists creation permission). Please go to the settings tab to create one.' - // ) - } else { - const description = 'Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. \n Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=' + - queryParams.get().version + '&optimize=' + queryParams.get().optimize + '&runs=' + queryParams.get().runs + '&gist=' - const gists = new Gists({ token: props.accessToken }) - - if (id) { - const originalFileList = getOriginalFiles(id) - // Telling the GIST API to remove files - const updatedFileList = Object.keys(packaged) - const allItems = Object.keys(originalFileList) - .filter(fileName => updatedFileList.indexOf(fileName) === -1) - .reduce((acc, deleteFileName) => ({ - ...acc, - [deleteFileName]: null - }), originalFileList) - // adding new files - updatedFileList.forEach((file) => { - const _items = file.split('/') - const _fileName = _items[_items.length - 1] - allItems[_fileName] = packaged[file] - }) - - // tooltip('Saving gist (' + id + ') ...') - gists.edit({ - description: description, - public: true, - files: allItems, - id: id - }, (error, result) => { - proccedResult(error, result) - if (!error) { - for (const key in allItems) { - if (allItems[key] === null) delete allItems[key] - } - } - }) - } else { - // id is not existing, need to create a new gist - // tooltip('Creating a new gist ...') - gists.create({ - description: description, - public: true, - files: packaged - }, (error, result) => { - proccedResult(error, result) - }) - } - } - } - }) - } - return ( <> { props.title } @@ -236,7 +59,7 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { > { e.stopPropagation() - uploadFile(e.target) + props.uploadFile(e.target) }} multiple /> @@ -253,7 +76,7 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { } else if (action === 'createNewFolder') { props.createNewFolder() } else if (action === 'publishToGist') { - publishToGist() + props.publishToGist() } else { state.actions[action]() } diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 42d0106419..d4184671ca 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -3,13 +3,18 @@ import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd' // e import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line import { Toaster } from '@remix-ui/toaster' // eslint-disable-line +import * as async from 'async' +import Gists from 'gists' import { FileExplorerMenu } from './file-explorer-menu' // eslint-disable-line import { FileExplorerContextMenu } from './file-explorer-context-menu' // eslint-disable-line import { FileExplorerProps, File } from './types' import * as helper from '../../../../../apps/remix-ide/src/lib/helper' +import QueryParams from '../../../../../apps/remix-ide/src/lib/query-params' import './css/file-explorer.css' +const queryParams = new QueryParams() + export const FileExplorer = (props: FileExplorerProps) => { const { filesProvider, name, registry, plugin } = props const [state, setState] = useState({ @@ -79,7 +84,7 @@ export const FileExplorer = (props: FileExplorerProps) => { type: ['file', 'folder'] }, { name: 'Push changes to gist', - type: [] + type: ['browser/gists'] }] setState(prevState => { @@ -179,7 +184,7 @@ export const FileExplorer = (props: FileExplorerProps) => { helper.createNonClashingName(newFilePath, filesProvider, async (error, newName) => { if (error) { - return modal('Create File Failed', error, { + modal('Create File Failed', error, { label: 'Close', fn: async () => {} }, null) @@ -249,7 +254,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const exists = fileManager.exists(newPath) if (exists) { - return modal('Rename File Failed', 'File name already exists', { + modal('Rename File Failed', 'File name already exists', { label: 'Close', fn: async () => {} }, null) @@ -518,6 +523,179 @@ export const FileExplorer = (props: FileExplorerProps) => { // } // }) + const uploadFile = (target) => { + // TODO The file explorer is merely a view on the current state of + // the files module. Please ask the user here if they want to overwrite + // a file and then just use `files.add`. The file explorer will + // pick that up via the 'fileAdded' event from the files module. + + [...target.files].forEach((file) => { + const files = props.filesProvider + + const loadFile = (name: string): void => { + const fileReader = new FileReader() + + fileReader.onload = async function (event) { + if (helper.checkSpecialChars(file.name)) { + modal('File Upload Failed', 'Special characters are not allowed', { + label: 'Close', + fn: async () => {} + }, null) + return + } + const success = await files.set(name, event.target.result) + + if (!success) { + modal('File Upload Failed', 'Failed to create file ' + name, { + label: 'Close', + fn: async () => {} + }, null) + } + } + fileReader.readAsText(file) + } + const name = files.type + '/' + file.name + + files.exists(name, (error, exist) => { + if (error) console.log(error) + if (!exist) { + loadFile(name) + } else { + modal('Confirm overwrite', `The file ${name} already exists! Would you like to overwrite it?`, { + label: 'Ok', + fn: () => { + loadFile(name) + } + }, { + label: 'Cancel', + fn: () => {} + }) + } + }) + }) + } + + const publishToGist = () => { + modal('Create a public gist', 'Are you sure you want to publish all your files in browser directory anonymously as a public gist on github.com? Note: this will not include directories.', { + label: 'Ok', + fn: toGist + }, { + label: 'Cancel', + fn: () => {} + }) + } + + const toGist = (id?: string) => { + const proccedResult = function (error, data) { + if (error) { + modal('Publish to gist Failed', 'Failed to manage gist: ' + error, { + label: 'Close', + fn: async () => {} + }, null) + } else { + if (data.html_url) { + modal('Gist is ready', `The gist is at ${data.html_url}. Would you like to open it in a new window?`, { + label: 'Ok', + fn: () => { + window.open(data.html_url, '_blank') + } + }, { + label: 'Cancel', + fn: () => {} + }) + } else { + modal('Publish to gist Failed', data.message + ' ' + data.documentation_url + ' ' + JSON.stringify(data.errors, null, '\t'), { + label: 'Close', + fn: async () => {} + }, null) + } + } + } + + /** + * This function is to get the original content of given gist + * @params id is the gist id to fetch + */ + const getOriginalFiles = async (id) => { + if (!id) { + return [] + } + + const url = `https://api.github.com/gists/${id}` + const res = await fetch(url) + const data = await res.json() + return data.files || [] + } + + // If 'id' is not defined, it is not a gist update but a creation so we have to take the files from the browser explorer. + const folder = id ? 'browser/gists/' + id : 'browser/' + + packageFiles(props.filesProvider, folder, async (error, packaged) => { + if (error) { + console.log(error) + modal('Publish to gist Failed', 'Failed to create gist: ' + error.message, { + label: 'Close', + fn: async () => {} + }, null) + } else { + // check for token + if (!state.accessToken) { + modal('Authorize Token', 'Remix requires an access token (which includes gists creation permission). Please go to the settings tab to create one.', { + label: 'Close', + fn: async () => {} + }, null) + } else { + const description = 'Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. \n Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=' + + queryParams.get().version + '&optimize=' + queryParams.get().optimize + '&runs=' + queryParams.get().runs + '&gist=' + const gists = new Gists({ token: state.accessToken }) + + if (id) { + const originalFileList = await getOriginalFiles(id) + // Telling the GIST API to remove files + const updatedFileList = Object.keys(packaged) + const allItems = Object.keys(originalFileList) + .filter(fileName => updatedFileList.indexOf(fileName) === -1) + .reduce((acc, deleteFileName) => ({ + ...acc, + [deleteFileName]: null + }), originalFileList) + // adding new files + updatedFileList.forEach((file) => { + const _items = file.split('/') + const _fileName = _items[_items.length - 1] + allItems[_fileName] = packaged[file] + }) + + // tooltip('Saving gist (' + id + ') ...') + gists.edit({ + description: description, + public: true, + files: allItems, + id: id + }, (error, result) => { + proccedResult(error, result) + if (!error) { + for (const key in allItems) { + if (allItems[key] === null) delete allItems[key] + } + } + }) + } else { + // id is not existing, need to create a new gist + // tooltip('Creating a new gist ...') + gists.create({ + description: description, + public: true, + files: packaged + }, (error, result) => { + proccedResult(error, result) + }) + } + } + } + }) + } + const handleHideModal = () => { setState(prevState => { return { ...prevState, modalOptions: { ...state.modalOptions, hide: true } } @@ -754,6 +932,8 @@ export const FileExplorer = (props: FileExplorerProps) => { createNewFolder={handleNewFolderInput} deletePath={deletePath} renamePath={editModeOn} + extractParentFromKey={extractParentFromKey} + publishToGist={publishToGist} pageX={state.focusContext.x} pageY={state.focusContext.y} path={file.path} @@ -811,9 +991,9 @@ export const FileExplorer = (props: FileExplorerProps) => { addFile={addFile} createNewFile={handleNewFileInput} createNewFolder={handleNewFolderInput} - files={filesProvider} + publishToGist={publishToGist} + uploadFile={uploadFile} fileManager={state.fileManager} - accessToken={state.accessToken} /> } expand={true}> @@ -842,3 +1022,28 @@ export const FileExplorer = (props: FileExplorerProps) => { } export default FileExplorer + +function packageFiles (filesProvider, directory, callback) { + const ret = {} + filesProvider.resolveDirectory(directory, (error, files) => { + if (error) callback(error) + else { + async.eachSeries(Object.keys(files), (path, cb) => { + if (filesProvider.isDirectory(path)) { + cb() + } else { + filesProvider.get(path, (error, content) => { + if (error) return cb(error) + if (/^\s+$/.test(content) || !content.length) { + content = '// this line is added to create a gist. Empty file is not allowed.' + } + ret[path] = { content } + cb() + }) + } + }, (error) => { + callback(error, ret) + }) + } + }) +} diff --git a/libs/remix-ui/file-explorer/src/lib/types/index.ts b/libs/remix-ui/file-explorer/src/lib/types/index.ts index 2e18e13154..06ec2e9fae 100644 --- a/libs/remix-ui/file-explorer/src/lib/types/index.ts +++ b/libs/remix-ui/file-explorer/src/lib/types/index.ts @@ -21,8 +21,8 @@ export interface FileExplorerMenuProps { addFile: (folder: string, fileName: string) => void, createNewFile: (folder?: string) => void, createNewFolder: (parentFolder?: string) => void, - files: any, - accessToken: string + publishToGist: () => void, + uploadFile: (target: EventTarget & HTMLInputElement) => void } export interface FileExplorerContextMenuProps { @@ -32,6 +32,8 @@ export interface FileExplorerContextMenuProps { deletePath: (path: string) => void, renamePath: (path: string, type: string) => void, hideContextMenu: () => void, + extractParentFromKey?: (key: string) => string, + publishToGist?: () => void, pageX: number, pageY: number, path: string, From c70a463a37073202deb3c09966459b370ecba327 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 1 Jan 2021 18:31:27 +0100 Subject: [PATCH 34/99] Completed fileAdded event --- libs/remix-lib/src/eventManager.ts | 2 +- .../file-explorer/src/lib/file-explorer.tsx | 184 ++++++++---------- 2 files changed, 81 insertions(+), 105 deletions(-) diff --git a/libs/remix-lib/src/eventManager.ts b/libs/remix-lib/src/eventManager.ts index 7acff32cc2..1c3bdd760f 100644 --- a/libs/remix-lib/src/eventManager.ts +++ b/libs/remix-lib/src/eventManager.ts @@ -26,7 +26,7 @@ export class EventManager { obj = this.anonymous } for (const reg in this.registered[eventName]) { - if (this.registered[eventName][reg].obj === obj && this.registered[eventName][reg].func === func) { + if ((this.registered[eventName][reg].obj.toString() === obj.toString()) && (this.registered[eventName][reg].func.toString() === func.toString())) { this.registered[eventName].splice(reg, 1) } } diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index d4184671ca..5b9d7bc062 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState, useRef } from 'react' // eslint-disable-line -import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd' // eslint-disable-line +// import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd' // eslint-disable-line import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line import { ModalDialog } from '@remix-ui/modal-dialog' // eslint-disable-line import { Toaster } from '@remix-ui/toaster' // eslint-disable-line @@ -40,7 +40,6 @@ export const FileExplorer = (props: FileExplorerProps) => { isNew: false, lastEdit: '' }, - fileExternallyChanged: false, expandPath: [], modalOptions: { hide: true, @@ -95,14 +94,47 @@ export const FileExplorer = (props: FileExplorerProps) => { useEffect(() => { if (state.fileManager) { - props.filesProvider.event.register('fileAdded', fileAdded) + props.filesProvider.event.register('fileExternallyChanged', fileExternallyChanged) + props.filesProvider.event.register('fileRenamedError', fileRenamedError) } }, [state.fileManager]) + useEffect(() => { + const { expandPath } = state + + if (expandPath && expandPath.length > 0) { + expandPath.map(async (path, index) => { + console.log('path ' + index + ' :', path) + const files = await resolveDirectory(path, state.files) + + setState(prevState => { + return { ...prevState, files } + }) + }) + if (props.filesProvider.event.registered.fileAdded) { + // unregister event to update state in callback + props.filesProvider.event.unregister('fileAdded', fileAdded) + } + props.filesProvider.event.register('fileAdded', fileAdded) + } + }, [state.expandPath]) + const resolveDirectory = async (folderPath, dir: File[]): Promise => { dir = await Promise.all(dir.map(async (file) => { if (file.path === folderPath) { - file.child = await fetchDirectoryContent(folderPath) + if (file.child) { + const newInput = file.child.filter(({ path }) => path === 'browser/blank') + + if (newInput.length === 1) { + const dirContent = await fetchDirectoryContent(folderPath) + + file.child = newInput[0].isDirectory ? [...newInput, ...dirContent] : [...dirContent, ...newInput] + } else { + file.child = await fetchDirectoryContent(folderPath) + } + } else { + file.child = await fetchDirectoryContent(folderPath) + } return file } else if (file.child) { file.child = await resolveDirectory(folderPath, file.child) @@ -413,32 +445,6 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } - // props.files.event.register('fileExternallyChanged', (path, file) => { - // if (self._deps.config.get('currentFile') === path && self._deps.editor.currentContent() && self._deps.editor.currentContent() !== file.content) { - // if (this.files.isReadOnly(path)) return self._deps.editor.setText(file.content) - - // modalDialog(path + ' changed', remixdDialog(), - // { - // label: 'Replace by the new content', - // fn: () => { - // self._deps.editor.setText(file.content) - // } - // }, - // { - // label: 'Keep the content displayed in Remix', - // fn: () => {} - // } - // ) - // } - // }) - - // register to event of the file provider - // files.event.register('fileRemoved', fileRemoved) - // files.event.register('fileRenamed', fileRenamed) - // props.filesProvider.event.register('fileRenamedError', (error) => { - // // modalDialogCustom.alert(error) - // }) - const fileAdded = async (filePath: string) => { const pathArr = filePath.split('/') const hasChild = pathArr.length > 2 @@ -446,33 +452,23 @@ export const FileExplorer = (props: FileExplorerProps) => { if (hasChild) { const expandPath = pathArr.map((path, index) => { return [...pathArr.slice(0, index)].join('/') - }).filter(path => path && (path !== name)) + }).filter(path => path && (path !== props.name)) + const pathExist = state.files.findIndex(item => item.path === expandPath[0]) !== -1 - if (state.files.findIndex(item => item.path === expandPath[0]) === -1) { + if (!pathExist) { const dir = buildTree(expandPath) - let files = [dir, ...state.files] + const files = [dir, ...state.files] - await Promise.all(expandPath.map(async path => { - files = await resolveDirectory(path, files) - })) setState(prevState => { - return { ...prevState, files, expandPath: [...state.expandPath, ...expandPath] } + const uniquePaths = [...new Set([...prevState.expandPath, ...expandPath])] + + return { ...prevState, files, expandPath: uniquePaths } }) } else { - if (state.expandPath.findIndex(path => path === expandPath[expandPath.length - 1]) !== -1) return - const dir = state.files.find(item => item.path === expandPath[0]) - let files = [{ - ...dir, - child: [...(await fetchDirectoryContent(dir.path))] - }, ...state.files.filter(item => item.path !== expandPath[0])] - - await Promise.all(expandPath.map(async path => { - files = await resolveDirectory(path, files) - })) - const updatedPath = [state.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(expandPath[0]))] - setState(prevState => { - return { ...prevState, files, expandPath: [...updatedPath, ...expandPath] } + const uniquePaths = [...new Set([...expandPath])] + + return { ...prevState, expandPath: uniquePaths } }) } } else { @@ -482,46 +478,32 @@ export const FileExplorer = (props: FileExplorerProps) => { } } - // props.filesProvider.event.register('folderAdded', async (folderpath: string) => { - // const pathArr = folderpath.split('/') - // const hasChild = pathArr.length > 2 - - // if (hasChild) { - // const expandPath = pathArr.map((path, index) => { - // return [...pathArr.slice(0, index)].join('/') - // }).filter(path => path && (path !== name)) - - // if (state.files.findIndex(item => item.path === expandPath[0]) === -1) { - // const dir = buildTree(expandPath) - // let files = [dir, ...state.files] - - // await Promise.all(expandPath.map(async path => { - // files = await resolveDirectory(path, files) - // })) - // setState(prevState => { - // return { ...prevState, files, expandPath: [...state.expandPath, ...expandPath] } - // }) - // } else { - // if (state.files.findIndex(item => item.path === expandPath[expandPath.length - 1]) !== -1) return - // const dir = state.files.find(item => item.path === expandPath[0]) - // let files = [{ - // ...dir, - // child: [...(await fetchDirectoryContent(dir.path))] - // }, ...state.files.filter(item => item.path !== expandPath[0])] - - // await Promise.all(expandPath.map(async path => { - // files = await resolveDirectory(path, files) - // })) - // const updatedPath = [state.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(expandPath[0]))] - - // setState(prevState => { - // return { ...prevState, files, expandPath: [...updatedPath, ...expandPath] } - // }) - // } - // } else { - // addFolder(pathArr[0], folderpath) - // } - // }) + const fileExternallyChanged = (path: string, file: { content: string }) => { + const config = registry.get('config').api + + if (config.get('currentFile') === path && registry.editor.currentContent() && registry.editor.currentContent() !== file.content) { + if (filesProvider.isReadOnly(path)) return registry.editor.setText(file.content) + modal(path + ' changed', 'This file has been changed outside of Remix IDE.', { + label: 'Replace by the new content', + fn: () => { + registry.editor.setText(file.content) + } + }, { + label: 'Keep the content displayed in Remix', + fn: () => {} + }) + } + } + + // register to event of the file provider + // files.event.register('fileRemoved', fileRemoved) + // files.event.register('fileRenamed', fileRenamed) + const fileRenamedError = (error: string) => { + modal('File Renamed Failed', error, { + label: 'Close', + fn: () => {} + }, null) + } const uploadFile = (target) => { // TODO The file explorer is merely a view on the current state of @@ -738,17 +720,16 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } } else { - const files = await resolveDirectory(path, state.files) let expandPath = [] if (!state.expandPath.includes(path)) { - expandPath = [...state.expandPath, path] + expandPath = [...new Set([...state.expandPath, path])] } else { - expandPath = state.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(path)) + expandPath = [...new Set(state.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(path)))] } setState(prevState => { - return { ...prevState, focusElement: [{ key: path, type: 'folder' }], files, expandPath } + return { ...prevState, focusElement: [{ key: path, type: 'folder' }], expandPath } }) } } @@ -834,7 +815,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const handleNewFileInput = async (parentFolder?: string) => { if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name let files = await resolveDirectory(parentFolder, state.files) - const expandPath = [...state.expandPath, parentFolder] + const expandPath = [...new Set([...state.expandPath, parentFolder])] files = addEmptyFile(parentFolder, files) setState(prevState => { @@ -847,7 +828,7 @@ export const FileExplorer = (props: FileExplorerProps) => { if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name else if ((parentFolder.indexOf('.sol') !== -1) || (parentFolder.indexOf('.js') !== -1)) parentFolder = extractParentFromKey(parentFolder) let files = await resolveDirectory(parentFolder, state.files) - const expandPath = [...state.expandPath, parentFolder] + const expandPath = [...new Set([...state.expandPath, parentFolder])] files = addEmptyFolder(parentFolder, state.files) setState(prevState => { @@ -863,11 +844,6 @@ export const FileExplorer = (props: FileExplorerProps) => { } } - // warn if file changed outside of Remix - const remixdDialog = () => { - return
    This file has been changed outside of Remix IDE.
    - } - const label = (file: File) => { return (
    {
    { @@ -958,7 +934,7 @@ export const FileExplorer = (props: FileExplorerProps) => { e.stopPropagation() handleContextMenuFile(e.pageX, e.pageY, file.path, e.target.textContent) }} - icon='fa fa-file' + icon='far fa-file' labelClass={ state.focusEdit.element === file.path ? 'bg-light' : state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' } /> { ((state.focusContext.element === file.path) && (state.focusEdit.element !== file.path)) && From 012537c312b15a33bd03132e49bb21ee4e0d9e06 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 1 Jan 2021 20:01:09 +0100 Subject: [PATCH 35/99] Fixed new input bug --- libs/remix-ui/file-explorer/src/lib/file-explorer.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 5b9d7bc062..edaa52b748 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -103,8 +103,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const { expandPath } = state if (expandPath && expandPath.length > 0) { - expandPath.map(async (path, index) => { - console.log('path ' + index + ' :', path) + expandPath.map(async (path) => { const files = await resolveDirectory(path, state.files) setState(prevState => { @@ -123,7 +122,7 @@ export const FileExplorer = (props: FileExplorerProps) => { dir = await Promise.all(dir.map(async (file) => { if (file.path === folderPath) { if (file.child) { - const newInput = file.child.filter(({ path }) => path === 'browser/blank') + const newInput = file.child.filter(({ path }) => path.endsWith('/blank')) if (newInput.length === 1) { const dirContent = await fetchDirectoryContent(folderPath) @@ -880,7 +879,7 @@ export const FileExplorer = (props: FileExplorerProps) => { label={label(file)} onClick={(e) => { e.stopPropagation() - handleClickFolder(file.path) + if (state.focusEdit.element !== file.path) handleClickFolder(file.path) }} onContextMenu={(e) => { e.preventDefault() From f3f5934df892824a6f2398aed6523adfa97d8ae1 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Sat, 2 Jan 2021 18:45:37 +0100 Subject: [PATCH 36/99] Fixed file loaded bug --- .../file-explorer/src/lib/file-explorer.tsx | 147 ++++++++++++------ .../file-explorer/src/lib/types/index.ts | 1 - 2 files changed, 98 insertions(+), 50 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index edaa52b748..a473e104b1 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -60,7 +60,11 @@ export const FileExplorer = (props: FileExplorerProps) => { const editRef = useRef(null) useEffect(() => { - editRef && editRef.current && editRef.current.focus() + if (editRef && editRef.current) { + setTimeout(() => { + editRef.current.focus() + }, 150) + } }, [state.focusEdit.element]) useEffect(() => { @@ -96,10 +100,16 @@ export const FileExplorer = (props: FileExplorerProps) => { if (state.fileManager) { props.filesProvider.event.register('fileExternallyChanged', fileExternallyChanged) props.filesProvider.event.register('fileRenamedError', fileRenamedError) + props.filesProvider.event.register('fileAdded', fileAdded) } }, [state.fileManager]) useEffect(() => { + if (props.filesProvider.event.registered.fileAdded) { + // unregister event to update state in callback + props.filesProvider.event.unregister('fileAdded', fileAdded) + } + props.filesProvider.event.register('fileAdded', fileAdded) const { expandPath } = state if (expandPath && expandPath.length > 0) { @@ -110,19 +120,22 @@ export const FileExplorer = (props: FileExplorerProps) => { return { ...prevState, files } }) }) - if (props.filesProvider.event.registered.fileAdded) { - // unregister event to update state in callback - props.filesProvider.event.unregister('fileAdded', fileAdded) - } - props.filesProvider.event.register('fileAdded', fileAdded) } }, [state.expandPath]) + useEffect(() => { + if (props.filesProvider.event.registered.fileAdded) { + // unregister event to update state in callback + props.filesProvider.event.unregister('fileAdded', fileAdded) + } + props.filesProvider.event.register('fileAdded', fileAdded) + }, [state.files]) + const resolveDirectory = async (folderPath, dir: File[]): Promise => { dir = await Promise.all(dir.map(async (file) => { if (file.path === folderPath) { if (file.child) { - const newInput = file.child.filter(({ path }) => path.endsWith('/blank')) + const newInput = file.child.filter(({ path }) => path && path.endsWith('/blank')) if (newInput.length === 1) { const dirContent = await fetchDirectoryContent(folderPath) @@ -223,9 +236,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const createFile = await fileManager.writeFile(newName, '') if (!createFile) { - setState(prevState => { - return { ...prevState, toasterMsg: 'Failed to create file ' + newName } - }) + toast('Failed to create file ' + newName) } } }) @@ -241,17 +252,13 @@ export const FileExplorer = (props: FileExplorerProps) => { await fileManager.mkdir(dirName) addFolder(parentFolder, newFolderPath) } catch (e) { - setState(prevState => { - return { ...prevState, toasterMsg: 'Failed to create folder: ' + newFolderPath } - }) + toast('Failed to create folder: ' + newFolderPath) } } const deletePath = async (path: string) => { if (filesProvider.isReadOnly(path)) { - return setState(prevState => { - return { ...prevState, toasterMsg: 'cannot delete file. ' + name + ' is a read only explorer' } - }) + return toast('cannot delete file. ' + name + ' is a read only explorer') } const isDir = state.fileManager.isDirectory(path) @@ -268,9 +275,7 @@ export const FileExplorer = (props: FileExplorerProps) => { return { ...prevState, files: updatedFiles } }) } catch (e) { - setState(prevState => { - return { ...prevState, toasterMsg: `Failed to remove file ${path}.` } - }) + toast(`Failed to remove file ${path}.`) } } }, { @@ -305,32 +310,6 @@ export const FileExplorer = (props: FileExplorerProps) => { } } - const addFile = async (parentFolder: string, newFilePath: string) => { - if (parentFolder === name) { - setState(prevState => { - return { - ...prevState, - files: [...prevState.files, { - path: newFilePath, - name: extractNameFromKey(newFilePath), - isDirectory: false - }], - focusElement: [{ key: newFilePath, type: 'file' }] - } - }) - } else { - const updatedFiles = await resolveDirectory(parentFolder, state.files) - - setState(prevState => { - return { ...prevState, files: updatedFiles, focusElement: [{ key: newFilePath, type: 'file' }] } - }) - } - if (newFilePath.includes('_test.sol')) { - plugin.events.trigger('newTestFileCreated', [newFilePath]) - } - state.fileManager.open(newFilePath) - } - const addEmptyFile = (parentFolder: string, files: File[]): File[] => { if (parentFolder === name) { files.push({ @@ -448,6 +427,55 @@ export const FileExplorer = (props: FileExplorerProps) => { const pathArr = filePath.split('/') const hasChild = pathArr.length > 2 + if (hasChild) { + const expandPath = pathArr.map((path, index) => { + return [...pathArr.slice(0, index)].join('/') + }).filter(path => path && (path !== props.name)) + const pathExist = state.files.findIndex(item => item.path === expandPath[0]) !== -1 + + if (!pathExist) { + const dir = buildTree(expandPath) + const files = [dir, ...state.files] + + setState(prevState => { + const uniquePaths = [...new Set([...prevState.expandPath, ...expandPath])] + + return { ...prevState, files, expandPath: uniquePaths, focusElement: [{ key: filePath, type: 'file' }] } + }) + } else { + setState(prevState => { + const uniquePaths = [...new Set([...prevState.expandPath, ...expandPath])] + + return { ...prevState, expandPath: uniquePaths, focusElement: [{ key: filePath, type: 'file' }] } + }) + } + } else { + const parentFolder = extractParentFromKey(filePath) + + if (parentFolder === name) { + setState(prevState => { + return { + ...prevState, + files: [...prevState.files, { + path: filePath, + name: extractNameFromKey(filePath), + isDirectory: false + }], + focusElement: [{ key: filePath, type: 'file' }] + } + }) + } // else does not exist in explorer + } + if (filePath.includes('_test.sol')) { + plugin.event.trigger('newTestFileCreated', [filePath]) + } + // state.fileManager.open(filePath) + } + + const folderAdded = async (filePath: string) => { + const pathArr = filePath.split('/') + const hasChild = pathArr.length > 2 + if (hasChild) { const expandPath = pathArr.map((path, index) => { return [...pathArr.slice(0, index)].join('/') @@ -473,8 +501,24 @@ export const FileExplorer = (props: FileExplorerProps) => { } else { const parentFolder = extractParentFromKey(filePath) - addFile(parentFolder, filePath) + if (parentFolder === name) { + setState(prevState => { + return { + ...prevState, + files: [...prevState.files, { + path: filePath, + name: extractNameFromKey(filePath), + isDirectory: false + }], + focusElement: [{ key: filePath, type: 'file' }] + } + }) + } + } + if (filePath.includes('_test.sol')) { + plugin.event.trigger('newTestFileCreated', [filePath]) } + // state.fileManager.open(filePath) } const fileExternallyChanged = (path: string, file: { content: string }) => { @@ -647,7 +691,7 @@ export const FileExplorer = (props: FileExplorerProps) => { allItems[_fileName] = packaged[file] }) - // tooltip('Saving gist (' + id + ') ...') + toast('Saving gist (' + id + ') ...') gists.edit({ description: description, public: true, @@ -663,7 +707,7 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } else { // id is not existing, need to create a new gist - // tooltip('Creating a new gist ...') + toast('Creating a new gist ...') gists.create({ description: description, public: true, @@ -700,6 +744,12 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } + const toast = (message: string) => { + setState(prevState => { + return { ...prevState, toasterMsg: message } + }) + } + const handleClickFile = (path: string) => { state.fileManager.open(path) setState(prevState => { @@ -963,7 +1013,6 @@ export const FileExplorer = (props: FileExplorerProps) => { void, createNewFile: (folder?: string) => void, createNewFolder: (parentFolder?: string) => void, publishToGist: () => void, From cd2f3a53c5b617074f2dc20481e5d8e3ced2fc31 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Sun, 3 Jan 2021 16:47:16 +0100 Subject: [PATCH 37/99] Folder Added event --- .../file-explorer/src/lib/file-explorer.tsx | 65 +++++++------------ 1 file changed, 22 insertions(+), 43 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index a473e104b1..674d01f46d 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -101,15 +101,11 @@ export const FileExplorer = (props: FileExplorerProps) => { props.filesProvider.event.register('fileExternallyChanged', fileExternallyChanged) props.filesProvider.event.register('fileRenamedError', fileRenamedError) props.filesProvider.event.register('fileAdded', fileAdded) + props.filesProvider.event.register('folderAdded', folderAdded) } }, [state.fileManager]) useEffect(() => { - if (props.filesProvider.event.registered.fileAdded) { - // unregister event to update state in callback - props.filesProvider.event.unregister('fileAdded', fileAdded) - } - props.filesProvider.event.register('fileAdded', fileAdded) const { expandPath } = state if (expandPath && expandPath.length > 0) { @@ -124,12 +120,12 @@ export const FileExplorer = (props: FileExplorerProps) => { }, [state.expandPath]) useEffect(() => { - if (props.filesProvider.event.registered.fileAdded) { - // unregister event to update state in callback - props.filesProvider.event.unregister('fileAdded', fileAdded) - } + // unregister event to update state in callback + if (props.filesProvider.event.registered.fileAdded) props.filesProvider.event.unregister('fileAdded', fileAdded) + if (props.filesProvider.event.registered.folderAdded) props.filesProvider.event.unregister('folderAdded', folderAdded) props.filesProvider.event.register('fileAdded', fileAdded) - }, [state.files]) + props.filesProvider.event.register('folderAdded', folderAdded) + }, [state.files, state.expandPath]) const resolveDirectory = async (folderPath, dir: File[]): Promise => { dir = await Promise.all(dir.map(async (file) => { @@ -242,7 +238,7 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } - const createNewFolder = async (parentFolder: string, newFolderPath: string) => { + const createNewFolder = async (newFolderPath: string) => { const fileManager = state.fileManager const dirName = newFolderPath + '/' const exists = fileManager.exists(dirName) @@ -250,7 +246,7 @@ export const FileExplorer = (props: FileExplorerProps) => { if (exists) return try { await fileManager.mkdir(dirName) - addFolder(parentFolder, newFolderPath) + // addFolder(parentFolder, newFolderPath) } catch (e) { toast('Failed to create folder: ' + newFolderPath) } @@ -453,27 +449,20 @@ export const FileExplorer = (props: FileExplorerProps) => { const parentFolder = extractParentFromKey(filePath) if (parentFolder === name) { + const files = await fetchDirectoryContent(name) + setState(prevState => { - return { - ...prevState, - files: [...prevState.files, { - path: filePath, - name: extractNameFromKey(filePath), - isDirectory: false - }], - focusElement: [{ key: filePath, type: 'file' }] - } + return { ...prevState, files, focusElement: [{ key: filePath, type: 'file' }] } }) } // else does not exist in explorer } if (filePath.includes('_test.sol')) { plugin.event.trigger('newTestFileCreated', [filePath]) } - // state.fileManager.open(filePath) } - const folderAdded = async (filePath: string) => { - const pathArr = filePath.split('/') + const folderAdded = async (folderPath: string) => { + const pathArr = folderPath.split('/') const hasChild = pathArr.length > 2 if (hasChild) { @@ -489,36 +478,26 @@ export const FileExplorer = (props: FileExplorerProps) => { setState(prevState => { const uniquePaths = [...new Set([...prevState.expandPath, ...expandPath])] - return { ...prevState, files, expandPath: uniquePaths } + return { ...prevState, files, expandPath: uniquePaths, focusElement: [{ key: folderPath, type: 'folder' }] } }) } else { setState(prevState => { - const uniquePaths = [...new Set([...expandPath])] + const uniquePaths = [...new Set([...prevState.expandPath, ...expandPath])] - return { ...prevState, expandPath: uniquePaths } + return { ...prevState, expandPath: uniquePaths, focusElement: [{ key: folderPath, type: 'folder' }] } }) } } else { - const parentFolder = extractParentFromKey(filePath) + const parentFolder = extractParentFromKey(folderPath) if (parentFolder === name) { + const files = await fetchDirectoryContent(name) + setState(prevState => { - return { - ...prevState, - files: [...prevState.files, { - path: filePath, - name: extractNameFromKey(filePath), - isDirectory: false - }], - focusElement: [{ key: filePath, type: 'file' }] - } + return { ...prevState, files, focusElement: [{ key: folderPath, type: 'folder' }] } }) - } - } - if (filePath.includes('_test.sol')) { - plugin.event.trigger('newTestFileCreated', [filePath]) + } // else does not exist in explorer } - // state.fileManager.open(filePath) } const fileExternallyChanged = (path: string, file: { content: string }) => { @@ -840,7 +819,7 @@ export const FileExplorer = (props: FileExplorerProps) => { }, null) } else { if (state.focusEdit.isNew) { - state.focusEdit.type === 'file' ? createNewFile(parentFolder + '/' + content) : createNewFolder(parentFolder, parentFolder + '/' + content) + state.focusEdit.type === 'file' ? createNewFile(parentFolder + '/' + content) : createNewFolder(parentFolder + '/' + content) const files = removePath(state.focusEdit.element, state.files) const updatedFiles = files.filter(file => file) From aa212e7089a9edb80799dab837a487d307f10678 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Sun, 3 Jan 2021 17:50:59 +0100 Subject: [PATCH 38/99] File removed event --- .../file-explorer/src/lib/file-explorer.tsx | 64 ++++++++----------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 674d01f46d..1dd61e812f 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -102,6 +102,8 @@ export const FileExplorer = (props: FileExplorerProps) => { props.filesProvider.event.register('fileRenamedError', fileRenamedError) props.filesProvider.event.register('fileAdded', fileAdded) props.filesProvider.event.register('folderAdded', folderAdded) + props.filesProvider.event.register('fileRemoved', fileRemoved) + props.filesProvider.event.register('fileRenamed', fileRenamed) } }, [state.fileManager]) @@ -123,8 +125,12 @@ export const FileExplorer = (props: FileExplorerProps) => { // unregister event to update state in callback if (props.filesProvider.event.registered.fileAdded) props.filesProvider.event.unregister('fileAdded', fileAdded) if (props.filesProvider.event.registered.folderAdded) props.filesProvider.event.unregister('folderAdded', folderAdded) + if (props.filesProvider.event.registered.fileRemoved) props.filesProvider.event.unregister('fileRemoved', fileRemoved) + if (props.filesProvider.event.registered.fileRenamed) props.filesProvider.event.unregister('fileRenamed', fileRenamed) props.filesProvider.event.register('fileAdded', fileAdded) props.filesProvider.event.register('folderAdded', folderAdded) + props.filesProvider.event.register('fileRemoved', fileRemoved) + props.filesProvider.event.unregister('fileRenamed', fileRenamed) }, [state.files, state.expandPath]) const resolveDirectory = async (folderPath, dir: File[]): Promise => { @@ -264,12 +270,6 @@ export const FileExplorer = (props: FileExplorerProps) => { try { const fileManager = state.fileManager await fileManager.remove(path) - const files = removePath(path, state.files) - const updatedFiles = files.filter(file => file) - - setState(prevState => { - return { ...prevState, files: updatedFiles } - }) } catch (e) { toast(`Failed to remove file ${path}.`) } @@ -288,15 +288,13 @@ export const FileExplorer = (props: FileExplorerProps) => { if (exists) { modal('Rename File Failed', 'File name already exists', { label: 'Close', - fn: async () => {} + fn: () => { + console.log('called!') + editRef.current.textContent = extractNameFromKey(oldPath) + } }, null) } else { await fileManager.rename(oldPath, newPath) - const files = replacePath(oldPath, newPath, state.files) - - setState(prevState => { - return { ...prevState, files } - }) } } catch (error) { modal('Rename File Failed', 'Unexpected error while renaming: ' + error, { @@ -335,28 +333,6 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } - const addFolder = async (parentFolder: string, newFolderPath: string, files?: File[]) => { - if (parentFolder === name) { - setState(prevState => { - return { - ...prevState, - files: [{ - path: newFolderPath, - name: extractNameFromKey(newFolderPath), - isDirectory: true - }, ...prevState.files], - focusElement: [{ key: newFolderPath, type: 'folder' }] - } - }) - } else { - const updatedFiles = await resolveDirectory(parentFolder, files || state.files) - - setState(prevState => { - return { ...prevState, files: updatedFiles, focusElement: [{ key: newFolderPath, type: 'folder' }] } - }) - } - } - const addEmptyFolder = (parentFolder: string, files: File[]): File[] => { if (parentFolder === name) { files.unshift({ @@ -452,7 +428,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const files = await fetchDirectoryContent(name) setState(prevState => { - return { ...prevState, files, focusElement: [{ key: filePath, type: 'file' }] } + return { ...prevState, files, focusElement: [{ key: filePath, type: 'file' }], expandPath: [] } }) } // else does not exist in explorer } @@ -517,8 +493,24 @@ export const FileExplorer = (props: FileExplorerProps) => { } } + const fileRemoved = (filePath) => { + const files = removePath(filePath, state.files) + const updatedFiles = files.filter(file => file) + + setState(prevState => { + return { ...prevState, files: updatedFiles } + }) + } + + const fileRenamed = (oldName, newName) => { + const files = replacePath(oldName, newName, state.files) + + setState(prevState => { + return { ...prevState, files } + }) + } + // register to event of the file provider - // files.event.register('fileRemoved', fileRemoved) // files.event.register('fileRenamed', fileRenamed) const fileRenamedError = (error: string) => { modal('File Renamed Failed', error, { From 3aee21fa733bc71badd6a700e51ea837c169ae92 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 6 Jan 2021 16:14:29 +0100 Subject: [PATCH 39/99] Fixed edit mode bug --- .../file-explorer/src/lib/file-explorer.tsx | 160 +++++------------- 1 file changed, 47 insertions(+), 113 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 1dd61e812f..d3e4e84e4d 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -60,9 +60,11 @@ export const FileExplorer = (props: FileExplorerProps) => { const editRef = useRef(null) useEffect(() => { - if (editRef && editRef.current) { + if (state.focusEdit.element) { setTimeout(() => { - editRef.current.focus() + if (editRef && editRef.current) { + editRef.current.focus() + } }, 150) } }, [state.focusEdit.element]) @@ -100,24 +102,24 @@ export const FileExplorer = (props: FileExplorerProps) => { if (state.fileManager) { props.filesProvider.event.register('fileExternallyChanged', fileExternallyChanged) props.filesProvider.event.register('fileRenamedError', fileRenamedError) - props.filesProvider.event.register('fileAdded', fileAdded) - props.filesProvider.event.register('folderAdded', folderAdded) - props.filesProvider.event.register('fileRemoved', fileRemoved) - props.filesProvider.event.register('fileRenamed', fileRenamed) } }, [state.fileManager]) useEffect(() => { const { expandPath } = state + const expandFn = async () => { + let files = state.files - if (expandPath && expandPath.length > 0) { - expandPath.map(async (path) => { - const files = await resolveDirectory(path, state.files) - - setState(prevState => { + for (let i = 0; i < expandPath.length; i++) { + files = await resolveDirectory(expandPath[i], files) + await setState(prevState => { return { ...prevState, files } }) - }) + } + } + + if (expandPath && expandPath.length > 0) { + expandFn() } }, [state.expandPath]) @@ -130,22 +132,22 @@ export const FileExplorer = (props: FileExplorerProps) => { props.filesProvider.event.register('fileAdded', fileAdded) props.filesProvider.event.register('folderAdded', folderAdded) props.filesProvider.event.register('fileRemoved', fileRemoved) - props.filesProvider.event.unregister('fileRenamed', fileRenamed) - }, [state.files, state.expandPath]) + props.filesProvider.event.register('fileRenamed', fileRenamed) + }, [state.files]) const resolveDirectory = async (folderPath, dir: File[]): Promise => { dir = await Promise.all(dir.map(async (file) => { if (file.path === folderPath) { - if (file.child) { - const newInput = file.child.filter(({ path }) => path && path.endsWith('/blank')) - - if (newInput.length === 1) { - const dirContent = await fetchDirectoryContent(folderPath) - - file.child = newInput[0].isDirectory ? [...newInput, ...dirContent] : [...dirContent, ...newInput] - } else { - file.child = await fetchDirectoryContent(folderPath) - } + if ((extractParentFromKey(state.focusEdit.element) === folderPath) && state.focusEdit.isNew) { + file.child = state.focusEdit.type === 'file' ? [...await fetchDirectoryContent(folderPath), { + path: file.path + '/blank', + name: '', + isDirectory: false + }] : [{ + path: file.path + '/blank', + name: '', + isDirectory: true + }, ...await fetchDirectoryContent(folderPath)] } else { file.child = await fetchDirectoryContent(folderPath) } @@ -212,19 +214,6 @@ export const FileExplorer = (props: FileExplorerProps) => { return keyPath.join('/') } - const buildTree = (paths: string[]) => { - if (paths.length > 0) { - return { - path: paths[0], - name: extractNameFromKey(paths[0]), - isDirectory: true, - child: [buildTree(paths.filter(item => item !== paths[0]))] - } - } else { - return [] - } - } - const createNewFile = (newFilePath: string) => { const fileManager = state.fileManager @@ -269,6 +258,7 @@ export const FileExplorer = (props: FileExplorerProps) => { fn: async () => { try { const fileManager = state.fileManager + await fileManager.remove(path) } catch (e) { toast(`Failed to remove file ${path}.`) @@ -288,10 +278,7 @@ export const FileExplorer = (props: FileExplorerProps) => { if (exists) { modal('Rename File Failed', 'File name already exists', { label: 'Close', - fn: () => { - console.log('called!') - editRef.current.textContent = extractNameFromKey(oldPath) - } + fn: () => {} }, null) } else { await fileManager.rename(oldPath, newPath) @@ -397,41 +384,16 @@ export const FileExplorer = (props: FileExplorerProps) => { const fileAdded = async (filePath: string) => { const pathArr = filePath.split('/') - const hasChild = pathArr.length > 2 - - if (hasChild) { - const expandPath = pathArr.map((path, index) => { - return [...pathArr.slice(0, index)].join('/') - }).filter(path => path && (path !== props.name)) - const pathExist = state.files.findIndex(item => item.path === expandPath[0]) !== -1 - - if (!pathExist) { - const dir = buildTree(expandPath) - const files = [dir, ...state.files] - - setState(prevState => { - const uniquePaths = [...new Set([...prevState.expandPath, ...expandPath])] - - return { ...prevState, files, expandPath: uniquePaths, focusElement: [{ key: filePath, type: 'file' }] } - }) - } else { - setState(prevState => { - const uniquePaths = [...new Set([...prevState.expandPath, ...expandPath])] - - return { ...prevState, expandPath: uniquePaths, focusElement: [{ key: filePath, type: 'file' }] } - }) - } - } else { - const parentFolder = extractParentFromKey(filePath) + const expandPath = pathArr.map((path, index) => { + return [...pathArr.slice(0, index)].join('/') + }).filter(path => path && (path !== props.name)) + const files = await fetchDirectoryContent(props.name) - if (parentFolder === name) { - const files = await fetchDirectoryContent(name) + setState(prevState => { + const uniquePaths = [...new Set([...prevState.expandPath, ...expandPath])] - setState(prevState => { - return { ...prevState, files, focusElement: [{ key: filePath, type: 'file' }], expandPath: [] } - }) - } // else does not exist in explorer - } + return { ...prevState, files, expandPath: uniquePaths, focusElement: [{ key: filePath, type: 'file' }] } + }) if (filePath.includes('_test.sol')) { plugin.event.trigger('newTestFileCreated', [filePath]) } @@ -439,41 +401,16 @@ export const FileExplorer = (props: FileExplorerProps) => { const folderAdded = async (folderPath: string) => { const pathArr = folderPath.split('/') - const hasChild = pathArr.length > 2 - - if (hasChild) { - const expandPath = pathArr.map((path, index) => { - return [...pathArr.slice(0, index)].join('/') - }).filter(path => path && (path !== props.name)) - const pathExist = state.files.findIndex(item => item.path === expandPath[0]) !== -1 - - if (!pathExist) { - const dir = buildTree(expandPath) - const files = [dir, ...state.files] + const expandPath = pathArr.map((path, index) => { + return [...pathArr.slice(0, index)].join('/') + }).filter(path => path && (path !== props.name)) + const files = await fetchDirectoryContent(props.name) - setState(prevState => { - const uniquePaths = [...new Set([...prevState.expandPath, ...expandPath])] - - return { ...prevState, files, expandPath: uniquePaths, focusElement: [{ key: folderPath, type: 'folder' }] } - }) - } else { - setState(prevState => { - const uniquePaths = [...new Set([...prevState.expandPath, ...expandPath])] - - return { ...prevState, expandPath: uniquePaths, focusElement: [{ key: folderPath, type: 'folder' }] } - }) - } - } else { - const parentFolder = extractParentFromKey(folderPath) - - if (parentFolder === name) { - const files = await fetchDirectoryContent(name) + setState(prevState => { + const uniquePaths = [...new Set([...prevState.expandPath, ...expandPath])] - setState(prevState => { - return { ...prevState, files, focusElement: [{ key: folderPath, type: 'folder' }] } - }) - } // else does not exist in explorer - } + return { ...prevState, files, expandPath: uniquePaths, focusElement: [{ key: folderPath, type: 'folder' }] } + }) } const fileExternallyChanged = (path: string, file: { content: string }) => { @@ -823,6 +760,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const oldName = extractNameFromKey(oldPath) const newPath = oldPath.replace(oldName, content) + editRef.current.textContent = extractNameFromKey(oldPath) renamePath(oldPath, newPath) } setState(prevState => { @@ -834,12 +772,10 @@ export const FileExplorer = (props: FileExplorerProps) => { const handleNewFileInput = async (parentFolder?: string) => { if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name - let files = await resolveDirectory(parentFolder, state.files) const expandPath = [...new Set([...state.expandPath, parentFolder])] - files = addEmptyFile(parentFolder, files) setState(prevState => { - return { ...prevState, files, expandPath } + return { ...prevState, expandPath } }) editModeOn(parentFolder + '/blank', 'file', true) } @@ -847,12 +783,10 @@ export const FileExplorer = (props: FileExplorerProps) => { const handleNewFolderInput = async (parentFolder?: string) => { if (!parentFolder) parentFolder = state.focusElement[0] ? state.focusElement[0].type === 'folder' ? state.focusElement[0].key : extractParentFromKey(state.focusElement[0].key) : name else if ((parentFolder.indexOf('.sol') !== -1) || (parentFolder.indexOf('.js') !== -1)) parentFolder = extractParentFromKey(parentFolder) - let files = await resolveDirectory(parentFolder, state.files) const expandPath = [...new Set([...state.expandPath, parentFolder])] - files = addEmptyFolder(parentFolder, state.files) setState(prevState => { - return { ...prevState, files, expandPath } + return { ...prevState, expandPath } }) editModeOn(parentFolder + '/blank', 'folder', true) } From adcdb3d44061cd3933eca19c64831e1a1fb8e8bb Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 6 Jan 2021 19:24:41 +0100 Subject: [PATCH 40/99] display new file input in root of project --- .../file-explorer/src/lib/file-explorer.tsx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index d3e4e84e4d..7e16e39a90 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -136,15 +136,26 @@ export const FileExplorer = (props: FileExplorerProps) => { }, [state.files]) const resolveDirectory = async (folderPath, dir: File[]): Promise => { + if (extractParentFromKey(state.focusEdit.element) === name) { + dir = state.focusEdit.type === 'file' ? [...dir, { + path: state.focusEdit.element, + name: '', + isDirectory: false + }] : [{ + path: state.focusEdit.element, + name: '', + isDirectory: true + }, ...dir] + } dir = await Promise.all(dir.map(async (file) => { if (file.path === folderPath) { if ((extractParentFromKey(state.focusEdit.element) === folderPath) && state.focusEdit.isNew) { file.child = state.focusEdit.type === 'file' ? [...await fetchDirectoryContent(folderPath), { - path: file.path + '/blank', + path: state.focusEdit.element, name: '', isDirectory: false }] : [{ - path: file.path + '/blank', + path: state.focusEdit.element, name: '', isDirectory: true }, ...await fetchDirectoryContent(folderPath)] From 154b95d3aefe1989d24c4aa2d44488f6acf728da Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 7 Jan 2021 16:45:16 +0100 Subject: [PATCH 41/99] Include pattern for context menu --- .../src/lib/file-explorer-context-menu.tsx | 16 ++- .../file-explorer/src/lib/file-explorer.tsx | 121 +++++++----------- .../file-explorer/src/lib/types/index.ts | 3 +- 3 files changed, 59 insertions(+), 81 deletions(-) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx index 086d9087f9..81e427da87 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx @@ -4,7 +4,7 @@ import { FileExplorerContextMenuProps } from './types' import './css/file-explorer-context-menu.css' export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => { - const { actions, createNewFile, createNewFolder, deletePath, renamePath, hideContextMenu, extractParentFromKey, publishToGist, pageX, pageY, path, type, ...otherProps } = props + const { actions, createNewFile, createNewFolder, deletePath, renamePath, hideContextMenu, extractParentFromKey, publishToGist, runScript, pageX, pageY, path, type, ...otherProps } = props const contextMenuRef = useRef(null) useEffect(() => { @@ -23,10 +23,13 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => }, [pageX, pageY]) const menu = () => { - return actions.filter(item => item.type.findIndex(name => { - if ((name === 'browser/gists') && (type === 'folder') && (extractParentFromKey(path) === name)) return true // add publish to gist for gist folders - return name === type - }) !== -1).map((item, index) => { + return actions.filter(item => { + if (item.type.findIndex(name => name === type) !== -1) return true + else if (item.path.findIndex(key => key === path) !== -1) return true + else if (item.extension.findIndex(ext => path.endsWith(ext)) !== -1) return true + else if (item.pattern.filter(value => path.match(new RegExp(value))).length > 0) return true + else return false + }).map((item, index) => { return
  • case 'Push changes to gist': publishToGist() break + case 'Run': + runScript(path) + break default: break } diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 7e16e39a90..c3b6a276e6 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -77,19 +77,40 @@ export const FileExplorer = (props: FileExplorerProps) => { const files = await fetchDirectoryContent(name) const actions = [{ name: 'New File', - type: ['folder'] + type: ['folder'], + path: [], + extension: [], + pattern: [] }, { name: 'New Folder', - type: ['folder'] + type: ['folder'], + path: [], + extension: [], + pattern: [] }, { name: 'Rename', - type: ['file', 'folder'] + type: ['file', 'folder'], + path: [], + extension: [], + pattern: [] }, { name: 'Delete', - type: ['file', 'folder'] + type: ['file', 'folder'], + path: [], + extension: [], + pattern: [] }, { name: 'Push changes to gist', - type: ['browser/gists'] + type: [], + path: [], + extension: [], + pattern: ['^browser/gists/([0-9]|[a-z])*$'] + }, { + name: 'Run', + type: [], + path: [], + extension: ['.js'], + pattern: [] }] setState(prevState => { @@ -100,8 +121,8 @@ export const FileExplorer = (props: FileExplorerProps) => { useEffect(() => { if (state.fileManager) { - props.filesProvider.event.register('fileExternallyChanged', fileExternallyChanged) - props.filesProvider.event.register('fileRenamedError', fileRenamedError) + filesProvider.event.register('fileExternallyChanged', fileExternallyChanged) + filesProvider.event.register('fileRenamedError', fileRenamedError) } }, [state.fileManager]) @@ -125,14 +146,14 @@ export const FileExplorer = (props: FileExplorerProps) => { useEffect(() => { // unregister event to update state in callback - if (props.filesProvider.event.registered.fileAdded) props.filesProvider.event.unregister('fileAdded', fileAdded) - if (props.filesProvider.event.registered.folderAdded) props.filesProvider.event.unregister('folderAdded', folderAdded) - if (props.filesProvider.event.registered.fileRemoved) props.filesProvider.event.unregister('fileRemoved', fileRemoved) - if (props.filesProvider.event.registered.fileRenamed) props.filesProvider.event.unregister('fileRenamed', fileRenamed) - props.filesProvider.event.register('fileAdded', fileAdded) - props.filesProvider.event.register('folderAdded', folderAdded) - props.filesProvider.event.register('fileRemoved', fileRemoved) - props.filesProvider.event.register('fileRenamed', fileRenamed) + if (filesProvider.event.registered.fileAdded) filesProvider.event.unregister('fileAdded', fileAdded) + if (filesProvider.event.registered.folderAdded) filesProvider.event.unregister('folderAdded', folderAdded) + if (filesProvider.event.registered.fileRemoved) filesProvider.event.unregister('fileRemoved', fileRemoved) + if (filesProvider.event.registered.fileRenamed) filesProvider.event.unregister('fileRenamed', fileRenamed) + filesProvider.event.register('fileAdded', fileAdded) + filesProvider.event.register('folderAdded', folderAdded) + filesProvider.event.register('fileRemoved', fileRemoved) + filesProvider.event.register('fileRenamed', fileRenamed) }, [state.files]) const resolveDirectory = async (folderPath, dir: File[]): Promise => { @@ -302,64 +323,6 @@ export const FileExplorer = (props: FileExplorerProps) => { } } - const addEmptyFile = (parentFolder: string, files: File[]): File[] => { - if (parentFolder === name) { - files.push({ - path: 'browser/blank', - name: '', - isDirectory: false - }) - return files - } - return files.map(file => { - if (file.child) { - if (file.path === parentFolder) { - file.child = [...file.child, { - path: file.path + '/blank', - name: '', - isDirectory: false - }] - return file - } else { - file.child = addEmptyFile(parentFolder, file.child) - - return file - } - } else { - return file - } - }) - } - - const addEmptyFolder = (parentFolder: string, files: File[]): File[] => { - if (parentFolder === name) { - files.unshift({ - path: 'browser/blank', - name: '', - isDirectory: true - }) - return files - } - return files.map(file => { - if (file.child) { - if (file.path === parentFolder) { - file.child = [{ - path: file.path + '/blank', - name: '', - isDirectory: true - }, ...file.child] - return file - } else { - file.child = addEmptyFolder(parentFolder, file.child) - - return file - } - } else { - return file - } - }) - } - const removePath = (path: string, files: File[]): File[] => { return files.map(file => { if (file.path === path) { @@ -474,7 +437,7 @@ export const FileExplorer = (props: FileExplorerProps) => { // pick that up via the 'fileAdded' event from the files module. [...target.files].forEach((file) => { - const files = props.filesProvider + const files = filesProvider const loadFile = (name: string): void => { const fileReader = new FileReader() @@ -574,7 +537,7 @@ export const FileExplorer = (props: FileExplorerProps) => { // If 'id' is not defined, it is not a gist update but a creation so we have to take the files from the browser explorer. const folder = id ? 'browser/gists/' + id : 'browser/' - packageFiles(props.filesProvider, folder, async (error, packaged) => { + packageFiles(filesProvider, folder, async (error, packaged) => { if (error) { console.log(error) modal('Publish to gist Failed', 'Failed to create gist: ' + error.message, { @@ -640,6 +603,13 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } + const runScript = async (path: string) => { + filesProvider.get(path, (error, content: string) => { + if (error) return console.log(error) + plugin.call('scriptRunner', 'execute', content) + }) + } + const handleHideModal = () => { setState(prevState => { return { ...prevState, modalOptions: { ...state.modalOptions, hide: true } } @@ -910,6 +880,7 @@ export const FileExplorer = (props: FileExplorerProps) => { createNewFolder={handleNewFolderInput} deletePath={deletePath} renamePath={editModeOn} + runScript={runScript} pageX={state.focusContext.x} pageY={state.focusContext.y} path={file.path} diff --git a/libs/remix-ui/file-explorer/src/lib/types/index.ts b/libs/remix-ui/file-explorer/src/lib/types/index.ts index 73f78efec7..d87d71062c 100644 --- a/libs/remix-ui/file-explorer/src/lib/types/index.ts +++ b/libs/remix-ui/file-explorer/src/lib/types/index.ts @@ -25,7 +25,7 @@ export interface FileExplorerMenuProps { } export interface FileExplorerContextMenuProps { - actions: { name: string, type: string[] }[], + actions: { name: string, type: string[], path: string[], extension: string[], pattern: string[] }[], createNewFile: (folder?: string) => void, createNewFolder: (parentFolder?: string) => void, deletePath: (path: string) => void, @@ -33,6 +33,7 @@ export interface FileExplorerContextMenuProps { hideContextMenu: () => void, extractParentFromKey?: (key: string) => string, publishToGist?: () => void, + runScript?: (path: string) => void, pageX: number, pageY: number, path: string, From c1ec81530e0f33b8808e82d681d9de3c268b0f7a Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Sat, 9 Jan 2021 13:58:18 +0100 Subject: [PATCH 42/99] Wait for provider before loading remixd provider --- apps/remix-ide/src/app/files/remixd-handle.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/remix-ide/src/app/files/remixd-handle.js b/apps/remix-ide/src/app/files/remixd-handle.js index 8d706441d7..666ff495d1 100644 --- a/apps/remix-ide/src/app/files/remixd-handle.js +++ b/apps/remix-ide/src/app/files/remixd-handle.js @@ -47,7 +47,6 @@ export class RemixdHandle extends WebsocketPlugin { } activate () { - this.fileSystemExplorer.show() this.connectToLocalhost() } @@ -83,7 +82,9 @@ export class RemixdHandle extends WebsocketPlugin { this.canceled() } }, 3000) - this.locahostProvider.init() + this.locahostProvider.init(() => { + this.fileSystemExplorer.show() + }) this.call('manager', 'activatePlugin', 'git') } } From 071908978250b956ae6dbe43a04afc620918e49a Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Sat, 9 Jan 2021 15:26:47 +0100 Subject: [PATCH 43/99] Fixed remixd errors and added createDir api to remixd plugin --- apps/remix-ide/src/app/files/fileProvider.js | 4 +- .../remix-ide/src/app/files/remixDProvider.js | 7 +++ apps/remix-ide/src/app/files/remixd-handle.js | 2 +- .../file-explorer/src/lib/file-explorer.tsx | 56 ++++++++----------- libs/remixd/src/services/remixdClient.ts | 26 ++++++++- 5 files changed, 57 insertions(+), 38 deletions(-) diff --git a/apps/remix-ide/src/app/files/fileProvider.js b/apps/remix-ide/src/app/files/fileProvider.js index aa18cdf645..8f634d1b2a 100644 --- a/apps/remix-ide/src/app/files/fileProvider.js +++ b/apps/remix-ide/src/app/files/fileProvider.js @@ -63,10 +63,10 @@ class FileProvider { }) } - exists (path, cb) { + exists (path) { // todo check the type (directory/file) as well #2386 // currently it is not possible to have a file and folder with same path - return cb(null, this._exists(path)) + return this._exists(path) } _exists (path) { diff --git a/apps/remix-ide/src/app/files/remixDProvider.js b/apps/remix-ide/src/app/files/remixDProvider.js index ecbd416581..8579b516be 100644 --- a/apps/remix-ide/src/app/files/remixDProvider.js +++ b/apps/remix-ide/src/app/files/remixDProvider.js @@ -115,6 +115,13 @@ module.exports = class RemixDProvider { }) } + async createDir (path, cb) { + if (!this._isReady) return cb && cb('provider not ready') + const unprefixedpath = this.removePrefix(path) + + return this._appManager.call('remixd', 'createDir', { path: unprefixedpath }) + } + isReadOnly (path) { return this._readOnlyMode || this._readOnlyFiles[path] === 1 } diff --git a/apps/remix-ide/src/app/files/remixd-handle.js b/apps/remix-ide/src/app/files/remixd-handle.js index 666ff495d1..8d6bff9ee8 100644 --- a/apps/remix-ide/src/app/files/remixd-handle.js +++ b/apps/remix-ide/src/app/files/remixd-handle.js @@ -22,7 +22,7 @@ const profile = { name: 'remixd', displayName: 'RemixD', url: 'ws://127.0.0.1:65520', - methods: ['folderIsReadOnly', 'resolveDirectory', 'get', 'exists', 'isFile', 'set', 'rename', 'remove', 'isDirectory', 'list'], + methods: ['folderIsReadOnly', 'resolveDirectory', 'get', 'exists', 'isFile', 'set', 'rename', 'remove', 'isDirectory', 'list', 'createDir'], events: [], description: 'Using Remixd daemon, allow to access file system', kind: 'other', diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index c3b6a276e6..ebccbb8518 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -157,7 +157,7 @@ export const FileExplorer = (props: FileExplorerProps) => { }, [state.files]) const resolveDirectory = async (folderPath, dir: File[]): Promise => { - if (extractParentFromKey(state.focusEdit.element) === name) { + if ((extractParentFromKey(state.focusEdit.element) === name) && (dir.findIndex(({ path }) => path === state.focusEdit.element) === -1)) { dir = state.focusEdit.type === 'file' ? [...dir, { path: state.focusEdit.element, name: '', @@ -171,15 +171,19 @@ export const FileExplorer = (props: FileExplorerProps) => { dir = await Promise.all(dir.map(async (file) => { if (file.path === folderPath) { if ((extractParentFromKey(state.focusEdit.element) === folderPath) && state.focusEdit.isNew) { - file.child = state.focusEdit.type === 'file' ? [...await fetchDirectoryContent(folderPath), { - path: state.focusEdit.element, - name: '', - isDirectory: false - }] : [{ - path: state.focusEdit.element, - name: '', - isDirectory: true - }, ...await fetchDirectoryContent(folderPath)] + if (file.child && (file.child.findIndex(({ path }) => path === state.focusEdit.element) === -1)) { + file.child = state.focusEdit.type === 'file' ? [...await fetchDirectoryContent(folderPath), { + path: state.focusEdit.element, + name: '', + isDirectory: false + }] : [{ + path: state.focusEdit.element, + name: '', + isDirectory: true + }, ...await fetchDirectoryContent(folderPath)] + } else { + file.child = await fetchDirectoryContent(folderPath) + } } else { file.child = await fetchDirectoryContent(folderPath) } @@ -268,13 +272,15 @@ export const FileExplorer = (props: FileExplorerProps) => { const createNewFolder = async (newFolderPath: string) => { const fileManager = state.fileManager const dirName = newFolderPath + '/' - const exists = fileManager.exists(dirName) - if (exists) return try { + const exists = await fileManager.exists(dirName) + + if (exists) return await fileManager.mkdir(dirName) // addFolder(parentFolder, newFolderPath) } catch (e) { + console.log('error: ', e) toast('Failed to create folder: ' + newFolderPath) } } @@ -305,7 +311,7 @@ export const FileExplorer = (props: FileExplorerProps) => { const renamePath = async (oldPath: string, newPath: string) => { try { const fileManager = state.fileManager - const exists = fileManager.exists(newPath) + const exists = await fileManager.exists(newPath) if (exists) { modal('Rename File Failed', 'File name already exists', { @@ -338,24 +344,6 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } - const replacePath = (oldPath: string, newPath: string, files: File[]): File[] => { - return files.map(file => { - if (file.path === oldPath) { - return { - ...file, - path: newPath, - name: extractNameFromKey(newPath) - } - } else if (file.child) { - file.child = replacePath(oldPath, newPath, file.child) - - return file - } else { - return file - } - }) - } - const fileAdded = async (filePath: string) => { const pathArr = filePath.split('/') const expandPath = pathArr.map((path, index) => { @@ -413,11 +401,11 @@ export const FileExplorer = (props: FileExplorerProps) => { }) } - const fileRenamed = (oldName, newName) => { - const files = replacePath(oldName, newName, state.files) + const fileRenamed = async () => { + const files = await fetchDirectoryContent(props.name) setState(prevState => { - return { ...prevState, files } + return { ...prevState, files, expandPath: [...prevState.expandPath] } }) } diff --git a/libs/remixd/src/services/remixdClient.ts b/libs/remixd/src/services/remixdClient.ts index e769e31a14..4a48485c19 100644 --- a/libs/remixd/src/services/remixdClient.ts +++ b/libs/remixd/src/services/remixdClient.ts @@ -7,7 +7,7 @@ import * as fs from 'fs-extra' import * as isbinaryfile from 'isbinaryfile' export class RemixdClient extends PluginClient { - methods: ['folderIsReadOnly', 'resolveDirectory', 'get', 'exists', 'isFile', 'set', 'list', 'isDirectory'] + methods: ['folderIsReadOnly', 'resolveDirectory', 'get', 'exists', 'isFile', 'set', 'list', 'isDirectory', 'createDir'] trackDownStreamUpdate: TrackDownStreamUpdate = {} websocket: WS currentSharedFolder: string @@ -127,6 +127,30 @@ export class RemixdClient extends PluginClient { } } + createDir (args: SharedFolderArgs): Promise { + try { + return new Promise((resolve, reject) => { + if (this.readOnly) reject(new Error('Cannot create folder: read-only mode selected')) + const path = utils.absolutePath(args.path, this.currentSharedFolder) + const exists = fs.existsSync(path) + + if (exists && !isRealPath(path)) reject(new Error('')) + this.trackDownStreamUpdate[path] = path + fs.mkdirp(path).then(() => { + let splitPath = args.path.split('/') + + splitPath = splitPath.filter(dir => dir) + const dir = '/' + splitPath.join('/') + + this.emit('folderAdded', dir) + resolve() + }).catch((e: Error) => reject(e)) + }) + } catch (error) { + throw new Error(error) + } + } + rename (args: SharedFolderArgs): Promise { try { return new Promise((resolve, reject) => { From 861fcfa02810cd8619897c44dcc0a924863739dd Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Mon, 11 Jan 2021 17:25:37 +0100 Subject: [PATCH 44/99] Fixed fileExplorer bugs --- apps/remix-ide/src/app/files/fileProvider.js | 4 ++-- libs/remix-lib/src/eventManager.ts | 2 +- .../file-explorer/src/lib/file-explorer-context-menu.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/remix-ide/src/app/files/fileProvider.js b/apps/remix-ide/src/app/files/fileProvider.js index 8f634d1b2a..aa18cdf645 100644 --- a/apps/remix-ide/src/app/files/fileProvider.js +++ b/apps/remix-ide/src/app/files/fileProvider.js @@ -63,10 +63,10 @@ class FileProvider { }) } - exists (path) { + exists (path, cb) { // todo check the type (directory/file) as well #2386 // currently it is not possible to have a file and folder with same path - return this._exists(path) + return cb(null, this._exists(path)) } _exists (path) { diff --git a/libs/remix-lib/src/eventManager.ts b/libs/remix-lib/src/eventManager.ts index 1c3bdd760f..80280e8b27 100644 --- a/libs/remix-lib/src/eventManager.ts +++ b/libs/remix-lib/src/eventManager.ts @@ -26,7 +26,7 @@ export class EventManager { obj = this.anonymous } for (const reg in this.registered[eventName]) { - if ((this.registered[eventName][reg].obj.toString() === obj.toString()) && (this.registered[eventName][reg].func.toString() === func.toString())) { + if ((this.registered[eventName][reg].obj === obj) && (this.registered[eventName][reg].func.toString() === func.toString())) { this.registered[eventName].splice(reg, 1) } } diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx index 81e427da87..aebd8eb053 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx @@ -4,7 +4,7 @@ import { FileExplorerContextMenuProps } from './types' import './css/file-explorer-context-menu.css' export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => { - const { actions, createNewFile, createNewFolder, deletePath, renamePath, hideContextMenu, extractParentFromKey, publishToGist, runScript, pageX, pageY, path, type, ...otherProps } = props + const { actions, createNewFile, createNewFolder, deletePath, renamePath, hideContextMenu, publishToGist, runScript, pageX, pageY, path, type, ...otherProps } = props const contextMenuRef = useRef(null) useEffect(() => { From 5baa82c5466dfc27f5b97ea62a32a316d5ca35d7 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Tue, 12 Jan 2021 12:59:08 +0100 Subject: [PATCH 45/99] Fixed duplicate new file --- .env | 4 +-- apps/remix-ide-e2e/src/commands/addFile.ts | 19 ++++--------- .../file-explorer/src/lib/file-explorer.tsx | 28 ++++++++----------- 3 files changed, 19 insertions(+), 32 deletions(-) diff --git a/.env b/.env index 644e8c49bd..d26bff05b3 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ gist_token=ef5df4e3822bf121f1aee4616ea110309e2d49f5 -account_passphrase= -account_password= +account_passphrase=explain uniform adapt basic blue onion rebel pull rice erase volcano couple +account_password=remix_is_cool NODE_OPTIONS=--max-old-space-size=2048 \ No newline at end of file diff --git a/apps/remix-ide-e2e/src/commands/addFile.ts b/apps/remix-ide-e2e/src/commands/addFile.ts index 149d0fa43b..6a1bdfc6ef 100644 --- a/apps/remix-ide-e2e/src/commands/addFile.ts +++ b/apps/remix-ide-e2e/src/commands/addFile.ts @@ -15,20 +15,11 @@ class AddFile extends EventEmitter { function addFile (browser: NightwatchBrowser, name: string, content: NightwatchContractContent, done: VoidFunction) { browser.clickLaunchIcon('udapp').clickLaunchIcon('fileExplorers').click('.newFile') - .waitForElementVisible('#modal-dialog') - .perform((client, done) => { - browser.execute(function (fileName) { - if (fileName !== 'Untitled.sol') { - document.querySelector('#modal-dialog #prompt_text').setAttribute('value', fileName) - } - const elem = document.querySelector('#modal-footer-ok') as HTMLElement - - elem.click() - }, [name], function (result) { - console.log(result) - done() - }) - }) + .pause(2000) + .keys(name) + .keys(browser.Keys.ENTER) + .pause(1000) + .click('[data-id="treeViewLitreeViewItembrowser/Greet.sol"]') .setEditorValue(content.content) .pause(1000) .perform(function () { diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index ebccbb8518..63e421d084 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -156,8 +156,8 @@ export const FileExplorer = (props: FileExplorerProps) => { filesProvider.event.register('fileRenamed', fileRenamed) }, [state.files]) - const resolveDirectory = async (folderPath, dir: File[]): Promise => { - if ((extractParentFromKey(state.focusEdit.element) === name) && (dir.findIndex(({ path }) => path === state.focusEdit.element) === -1)) { + const resolveDirectory = async (folderPath, dir: File[], isChild = false): Promise => { + if (!isChild && (state.focusEdit.element === 'browser/blank') && state.focusEdit.isNew && (dir.findIndex(({ path }) => path === 'browser/blank') === -1)) { dir = state.focusEdit.type === 'file' ? [...dir, { path: state.focusEdit.element, name: '', @@ -171,25 +171,21 @@ export const FileExplorer = (props: FileExplorerProps) => { dir = await Promise.all(dir.map(async (file) => { if (file.path === folderPath) { if ((extractParentFromKey(state.focusEdit.element) === folderPath) && state.focusEdit.isNew) { - if (file.child && (file.child.findIndex(({ path }) => path === state.focusEdit.element) === -1)) { - file.child = state.focusEdit.type === 'file' ? [...await fetchDirectoryContent(folderPath), { - path: state.focusEdit.element, - name: '', - isDirectory: false - }] : [{ - path: state.focusEdit.element, - name: '', - isDirectory: true - }, ...await fetchDirectoryContent(folderPath)] - } else { - file.child = await fetchDirectoryContent(folderPath) - } + file.child = state.focusEdit.type === 'file' ? [...await fetchDirectoryContent(folderPath), { + path: state.focusEdit.element, + name: '', + isDirectory: false + }] : [{ + path: state.focusEdit.element, + name: '', + isDirectory: true + }, ...await fetchDirectoryContent(folderPath)] } else { file.child = await fetchDirectoryContent(folderPath) } return file } else if (file.child) { - file.child = await resolveDirectory(folderPath, file.child) + file.child = await resolveDirectory(folderPath, file.child, true) return file } else { return file From 308aca2a784237ba3f973184d014dccc913000bb Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Tue, 12 Jan 2021 13:07:49 +0100 Subject: [PATCH 46/99] Update addFile custom command. --- apps/remix-ide-e2e/src/commands/addFile.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/remix-ide-e2e/src/commands/addFile.ts b/apps/remix-ide-e2e/src/commands/addFile.ts index 6a1bdfc6ef..597f106a31 100644 --- a/apps/remix-ide-e2e/src/commands/addFile.ts +++ b/apps/remix-ide-e2e/src/commands/addFile.ts @@ -18,8 +18,7 @@ function addFile (browser: NightwatchBrowser, name: string, content: NightwatchC .pause(2000) .keys(name) .keys(browser.Keys.ENTER) - .pause(1000) - .click('[data-id="treeViewLitreeViewItembrowser/Greet.sol"]') + .openFile('browser/Greet.sol') .setEditorValue(content.content) .pause(1000) .perform(function () { From 5529219c2b1818a5494ae16c13a3ecdf750a9c52 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Tue, 12 Jan 2021 13:45:50 +0100 Subject: [PATCH 47/99] Update openFile custom command --- apps/remix-ide-e2e/src/commands/openFile.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/remix-ide-e2e/src/commands/openFile.ts b/apps/remix-ide-e2e/src/commands/openFile.ts index 262c9dddaf..00e411b234 100644 --- a/apps/remix-ide-e2e/src/commands/openFile.ts +++ b/apps/remix-ide-e2e/src/commands/openFile.ts @@ -16,8 +16,8 @@ class OpenFile extends EventEmitter { // click on fileExplorer can toggle it. We go through settings to be sure FE is open function openFile (browser: NightwatchBrowser, name: string, done: VoidFunction) { browser.clickLaunchIcon('settings').clickLaunchIcon('fileExplorers') - .waitForElementVisible('li[key="' + name + '"]') - .click('li[key="' + name + '"]') + .waitForElementVisible('li[data-id="treeViewLitreeViewItem' + name + '"') + .click('li[data-id="treeViewLitreeViewItem' + name + '"') .pause(2000) .perform(() => { done() From 65e6a32405300e03cf4616695c8b19dcc2e4ca46 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 13 Jan 2021 09:36:41 +0100 Subject: [PATCH 48/99] Skip ci steps --- .circleci/config.yml | 88 ++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a936e1eec6..1bdb4cd959 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,10 +21,10 @@ jobs: steps: - checkout - - run: npm install - - run: npm run lint:libs - - run: npm run build:libs - - run: npm run test:libs + # - run: npm install + # - run: npm run lint:libs + # - run: npm run build:libs + # - run: npm run test:libs remix-ide-chrome: docker: @@ -45,23 +45,23 @@ jobs: parallelism: 20 steps: - checkout - - run: npm install - - run: npm run lint - # - run: npm run lint remix-ide-e2e - - run: npm run build:libs - - run: npm run build - - run: - name: Download Selenium - command: ./node_modules/.bin/selenium-standalone install --drivers.chrome.version=2.39 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com - - run: - name: Start Selenium - command: ./node_modules/.bin/selenium-standalone start --drivers.chrome.version=2.39 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com - background: true - - run: ./apps/remix-ide/ci/browser_tests_chrome.sh - - store_test_results: - path: ./reports/tests - - store_artifacts: - path: ./reports/screenshots + # - run: npm install + # - run: npm run lint + # # - run: npm run lint remix-ide-e2e + # - run: npm run build:libs + # - run: npm run build + # - run: + # name: Download Selenium + # command: ./node_modules/.bin/selenium-standalone install --drivers.chrome.version=2.39 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com + # - run: + # name: Start Selenium + # command: ./node_modules/.bin/selenium-standalone start --drivers.chrome.version=2.39 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com + # background: true + # - run: ./apps/remix-ide/ci/browser_tests_chrome.sh + # - store_test_results: + # path: ./reports/tests + # - store_artifacts: + # path: ./reports/screenshots remix-ide-firefox: docker: @@ -82,29 +82,29 @@ jobs: parallelism: 20 steps: - checkout - - run: npm install - - run: npm run lint - # - run: npm run lint remix-ide-e2e - - run: npm run build:libs - - run: npm run build - - run: - name: Download Selenium - command: ./node_modules/.bin/selenium-standalone install --config=../remix-project/apps/remix-ide-e2e/seleniumConfig.js - - run: - name: Start Selenium - command: ./node_modules/.bin/selenium-standalone start --config=../remix-project/apps/remix-ide-e2e/seleniumConfig.js - background: true - - run: - name: Download Latest Firefox - command: sudo apt-get purge -y firefox && wget https://sourceforge.net/projects/ubuntuzilla/files/mozilla/apt/pool/main/f/firefox-mozilla-build/firefox-mozilla-build_73.0.1-0ubuntu1_amd64.deb - - run: - name: Install Firefox - command: sudo dpkg -i firefox-mozilla-build_73.0.1-0ubuntu1_amd64.deb - - run: ./apps/remix-ide/ci/browser_tests_firefox.sh - - store_test_results: - path: ./reports/tests - - store_artifacts: - path: ./reports/screenshots + # - run: npm install + # - run: npm run lint + # # - run: npm run lint remix-ide-e2e + # - run: npm run build:libs + # - run: npm run build + # - run: + # name: Download Selenium + # command: ./node_modules/.bin/selenium-standalone install --config=../remix-project/apps/remix-ide-e2e/seleniumConfig.js + # - run: + # name: Start Selenium + # command: ./node_modules/.bin/selenium-standalone start --config=../remix-project/apps/remix-ide-e2e/seleniumConfig.js + # background: true + # - run: + # name: Download Latest Firefox + # command: sudo apt-get purge -y firefox && wget https://sourceforge.net/projects/ubuntuzilla/files/mozilla/apt/pool/main/f/firefox-mozilla-build/firefox-mozilla-build_73.0.1-0ubuntu1_amd64.deb + # - run: + # name: Install Firefox + # command: sudo dpkg -i firefox-mozilla-build_73.0.1-0ubuntu1_amd64.deb + # - run: ./apps/remix-ide/ci/browser_tests_firefox.sh + # - store_test_results: + # path: ./reports/tests + # - store_artifacts: + # path: ./reports/screenshots remix-ide-run-deploy: docker: From dc8d5602fa97ee17fe145d16047f217fc1705cb5 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 13 Jan 2021 10:29:26 +0100 Subject: [PATCH 49/99] Re-enable e2e tests and disabled metamask test --- .circleci/config.yml | 80 ++++++++++---------- apps/remix-ide-e2e/src/tests/runAndDeploy.ts | 1 + 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1bdb4cd959..dc8b75889d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -45,23 +45,23 @@ jobs: parallelism: 20 steps: - checkout - # - run: npm install - # - run: npm run lint - # # - run: npm run lint remix-ide-e2e - # - run: npm run build:libs - # - run: npm run build - # - run: - # name: Download Selenium - # command: ./node_modules/.bin/selenium-standalone install --drivers.chrome.version=2.39 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com - # - run: - # name: Start Selenium - # command: ./node_modules/.bin/selenium-standalone start --drivers.chrome.version=2.39 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com - # background: true - # - run: ./apps/remix-ide/ci/browser_tests_chrome.sh - # - store_test_results: - # path: ./reports/tests - # - store_artifacts: - # path: ./reports/screenshots + - run: npm install + - run: npm run lint + # - run: npm run lint remix-ide-e2e + - run: npm run build:libs + - run: npm run build + - run: + name: Download Selenium + command: ./node_modules/.bin/selenium-standalone install --drivers.chrome.version=2.39 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com + - run: + name: Start Selenium + command: ./node_modules/.bin/selenium-standalone start --drivers.chrome.version=2.39 --drivers.chrome.baseURL=https://chromedriver.storage.googleapis.com + background: true + - run: ./apps/remix-ide/ci/browser_tests_chrome.sh + - store_test_results: + path: ./reports/tests + - store_artifacts: + path: ./reports/screenshots remix-ide-firefox: docker: @@ -82,29 +82,29 @@ jobs: parallelism: 20 steps: - checkout - # - run: npm install - # - run: npm run lint - # # - run: npm run lint remix-ide-e2e - # - run: npm run build:libs - # - run: npm run build - # - run: - # name: Download Selenium - # command: ./node_modules/.bin/selenium-standalone install --config=../remix-project/apps/remix-ide-e2e/seleniumConfig.js - # - run: - # name: Start Selenium - # command: ./node_modules/.bin/selenium-standalone start --config=../remix-project/apps/remix-ide-e2e/seleniumConfig.js - # background: true - # - run: - # name: Download Latest Firefox - # command: sudo apt-get purge -y firefox && wget https://sourceforge.net/projects/ubuntuzilla/files/mozilla/apt/pool/main/f/firefox-mozilla-build/firefox-mozilla-build_73.0.1-0ubuntu1_amd64.deb - # - run: - # name: Install Firefox - # command: sudo dpkg -i firefox-mozilla-build_73.0.1-0ubuntu1_amd64.deb - # - run: ./apps/remix-ide/ci/browser_tests_firefox.sh - # - store_test_results: - # path: ./reports/tests - # - store_artifacts: - # path: ./reports/screenshots + - run: npm install + - run: npm run lint + # - run: npm run lint remix-ide-e2e + - run: npm run build:libs + - run: npm run build + - run: + name: Download Selenium + command: ./node_modules/.bin/selenium-standalone install --config=../remix-project/apps/remix-ide-e2e/seleniumConfig.js + - run: + name: Start Selenium + command: ./node_modules/.bin/selenium-standalone start --config=../remix-project/apps/remix-ide-e2e/seleniumConfig.js + background: true + - run: + name: Download Latest Firefox + command: sudo apt-get purge -y firefox && wget https://sourceforge.net/projects/ubuntuzilla/files/mozilla/apt/pool/main/f/firefox-mozilla-build/firefox-mozilla-build_73.0.1-0ubuntu1_amd64.deb + - run: + name: Install Firefox + command: sudo dpkg -i firefox-mozilla-build_73.0.1-0ubuntu1_amd64.deb + - run: ./apps/remix-ide/ci/browser_tests_firefox.sh + - store_test_results: + path: ./reports/tests + - store_artifacts: + path: ./reports/screenshots remix-ide-run-deploy: docker: diff --git a/apps/remix-ide-e2e/src/tests/runAndDeploy.ts b/apps/remix-ide-e2e/src/tests/runAndDeploy.ts index d318ea4f9c..5d7218bd2c 100644 --- a/apps/remix-ide-e2e/src/tests/runAndDeploy.ts +++ b/apps/remix-ide-e2e/src/tests/runAndDeploy.ts @@ -128,6 +128,7 @@ module.exports = { .waitForElementPresent('.transaction-status--submitted') .pause(25000) .switchBrowserTab(0) + .end() }, 'Should connect to Ethereum Main Network using MetaMask': '' + function (browser: NightwatchBrowser) { From 8d386b9d68552e293614cf30083d4dde3d5c1604 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 13 Jan 2021 13:17:48 +0100 Subject: [PATCH 50/99] Update file-explorer tests --- .env | 2 +- .../src/commands/clearEditableContent.ts | 2 +- .../commands/{renameFile.ts => renamePath.ts} | 13 ++-- .../src/tests/fileExplorer.test.ts | 62 ++++++++++--------- apps/remix-ide-e2e/src/types/index.d.ts | 2 +- package.json | 2 +- 6 files changed, 42 insertions(+), 41 deletions(-) rename apps/remix-ide-e2e/src/commands/{renameFile.ts => renamePath.ts} (84%) diff --git a/.env b/.env index d26bff05b3..21f7eea1af 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -gist_token=ef5df4e3822bf121f1aee4616ea110309e2d49f5 +gist_token=51c492cff9ccd5b819b79ddf5ecd275c725d0d9e account_passphrase=explain uniform adapt basic blue onion rebel pull rice erase volcano couple account_password=remix_is_cool NODE_OPTIONS=--max-old-space-size=2048 \ No newline at end of file diff --git a/apps/remix-ide-e2e/src/commands/clearEditableContent.ts b/apps/remix-ide-e2e/src/commands/clearEditableContent.ts index ad433d3af1..8d15f50c96 100644 --- a/apps/remix-ide-e2e/src/commands/clearEditableContent.ts +++ b/apps/remix-ide-e2e/src/commands/clearEditableContent.ts @@ -22,7 +22,7 @@ function clearContent (browser: NightwatchBrowser, cssSelector: string, callback selection.removeAllRanges() selection.addRange(range) }, [cssSelector], function () { - browser.sendKeys(cssSelector, browser.Keys.BACK_SPACE) + browser.keys(browser.Keys.BACK_SPACE) .pause(5000) callback() }) diff --git a/apps/remix-ide-e2e/src/commands/renameFile.ts b/apps/remix-ide-e2e/src/commands/renamePath.ts similarity index 84% rename from apps/remix-ide-e2e/src/commands/renameFile.ts rename to apps/remix-ide-e2e/src/commands/renamePath.ts index 551ea3365c..fb1fdfeb05 100644 --- a/apps/remix-ide-e2e/src/commands/renameFile.ts +++ b/apps/remix-ide-e2e/src/commands/renamePath.ts @@ -1,10 +1,10 @@ import EventEmitter from 'events' import { NightwatchBrowser } from 'nightwatch' -class RenameFile extends EventEmitter { +class RenamePath extends EventEmitter { command (this: NightwatchBrowser, path: string, newFileName: string, renamedPath: string) { this.api.perform((done) => { - renameFile(this.api, path, newFileName, renamedPath, () => { + renamePath(this.api, path, newFileName, renamedPath, () => { done() this.emit('complete') }) @@ -13,7 +13,7 @@ class RenameFile extends EventEmitter { } } -function renameFile (browser: NightwatchBrowser, path: string, newFileName: string, renamedPath: string, done: VoidFunction) { +function renamePath (browser: NightwatchBrowser, path: string, newFileName: string, renamedPath: string, done: VoidFunction) { browser.execute(function (path: string) { function contextMenuClick (element) { const evt = element.ownerDocument.createEvent('MouseEvents') @@ -41,10 +41,9 @@ function renameFile (browser: NightwatchBrowser, path: string, newFileName: stri doneSetValue() }) }) - .click('body') // blur - .waitForElementVisible('#modal-footer-ok', 100000) + .pause(1000) + .keys(browser.Keys.ENTER) .pause(2000) - .click('#modal-footer-ok') .waitForElementNotPresent('[data-path="' + path + '"]') .waitForElementPresent('[data-path="' + renamedPath + '"]') .perform(() => { @@ -53,4 +52,4 @@ function renameFile (browser: NightwatchBrowser, path: string, newFileName: stri }) } -module.exports = RenameFile \ No newline at end of file +module.exports = RenamePath diff --git a/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts b/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts index b9e7f89fd4..f2d252f358 100644 --- a/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts +++ b/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts @@ -21,70 +21,72 @@ module.exports = { .clickLaunchIcon('fileExplorers') .assert.containsText('h6[data-id="sidePanelSwapitTitle"]', 'FILE EXPLORERS') .click('*[data-id="fileExplorerNewFilecreateNewFile"]') - .waitForElementVisible('*[data-id="modalDialogContainer"]') - .setValue('*[data-id="modalDialogCustomPromptText"]', '5_New_contract.sol') - .modalFooterOKClick() - .waitForElementVisible('*[data-id="treeViewLibrowser/5_New_contract.sol"]', 7000) + .pause(1000) + .keys('5_New_contract.sol') + .keys(browser.Keys.ENTER) + .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/5_New_contract.sol"]', 7000) }, 'Should rename `5_New_contract.sol` to 5_Renamed_Contract.sol': function (browser: NightwatchBrowser) { browser - .waitForElementVisible('*[data-id="treeViewLibrowser/5_New_contract.sol"]') - .renameFile('browser/5_New_contract.sol', '5_Renamed_Contract.sol', 'browser/5_Renamed_Contract.sol') - .waitForElementVisible('*[data-id="treeViewLibrowser/5_Renamed_Contract.sol"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/5_New_contract.sol"]') + .renamePath('browser/5_New_contract.sol', '5_Renamed_Contract.sol', 'browser/5_Renamed_Contract.sol') + .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/5_Renamed_Contract.sol"]') }, 'Should delete file `5_Renamed_Contract.sol` from file explorer': function (browser: NightwatchBrowser) { browser - .waitForElementVisible('*[data-id="treeViewLibrowser/5_Renamed_Contract.sol"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/5_Renamed_Contract.sol"]') .rightClick('[data-path="browser/5_Renamed_Contract.sol"]') .click('*[id="menuitemdelete"]') .waitForElementVisible('*[data-id="modalDialogContainer"]') - .modalFooterOKClick() - .waitForElementNotPresent('*[data-id="treeViewLibrowser/5_Renamed_Contract.sol"') + .pause(2000) + .click('.modal-ok') + .waitForElementNotPresent('*[data-id="treeViewLitreeViewItembrowser/5_Renamed_Contract.sol"') }, 'Should create a new folder': function (browser: NightwatchBrowser) { browser - .waitForElementVisible('*[data-id="treeViewLibrowser/README.txt"]') - .rightClick('[data-path="browser/README.txt"]') - .click('*[id="menuitemcreate folder"]') - .waitForElementVisible('*[data-id="modalDialogContainer"]') - .setValue('*[data-id="modalDialogCustomPromptText"]', 'Browser_Tests') - .modalFooterOKClick() - .waitForElementVisible('*[data-id="treeViewLibrowser/Browser_Tests"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/README.txt"]') + .click('[data-id="fileExplorerNewFilecreateNewFolder"]') + .pause(1000) + .keys('Browser_Tests') + .keys(browser.Keys.ENTER) + .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/Browser_Tests"]') }, 'Should rename Browser_Tests folder to Browser_E2E_Tests': function (browser: NightwatchBrowser) { browser - .waitForElementVisible('*[data-id="treeViewLibrowser/Browser_Tests"]') - .rightClick('[data-path="browser/Browser_Tests"]') - .click('*[id="menuitemrename"]') - .sendKeys('[data-path="browser/Browser_Tests"]', 'Browser_E2E_Tests') - .sendKeys('[data-path="browser/Browser_Tests"]', browser.Keys.ENTER) - .waitForElementVisible('*[data-id="treeViewLibrowser/Browser_E2E_Tests"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/Browser_Tests"]') + .renamePath('browser/Browser_Tests', 'Browser_E2E_Tests', 'browser/Browser_E2E_Tests') + .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/Browser_E2E_Tests"]') }, 'Should delete Browser_E2E_Tests folder': function (browser: NightwatchBrowser) { browser - .waitForElementVisible('*[data-id="treeViewLibrowser/Browser_E2E_Tests"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/Browser_E2E_Tests"]') .rightClick('[data-path="browser/Browser_E2E_Tests"]') .click('*[id="menuitemdelete"]') .waitForElementVisible('*[data-id="modalDialogContainer"]') - .modalFooterOKClick() - .waitForElementNotPresent('*[data-id="treeViewLibrowser/Browser_E2E_Tests"]') + .pause(2000) + .click('.modal-ok') + .waitForElementNotPresent('*[data-id="treeViewLitreeViewItembrowser/Browser_E2E_Tests"]') }, 'Should publish all explorer files to github gist': function (browser: NightwatchBrowser) { const runtimeBrowser = browser.options.desiredCapabilities.browserName - browser + browser.refresh() + .pause(10000) .waitForElementVisible('*[data-id="fileExplorerNewFilepublishToGist"]') .click('*[data-id="fileExplorerNewFilepublishToGist"]') .waitForElementVisible('*[data-id="modalDialogContainer"]') - .modalFooterOKClick() - .waitForElementVisible('*[data-id="modalDialogContainer"]', 7000) - .modalFooterOKClick() + .pause(2000) + .click('.modal-ok') + .pause(2000) + .waitForElementVisible('*[data-id="modalDialogContainer"]') + .pause(2000) + .click('.modal-ok') .pause(2000) .perform((done) => { if (runtimeBrowser === 'chrome') { diff --git a/apps/remix-ide-e2e/src/types/index.d.ts b/apps/remix-ide-e2e/src/types/index.d.ts index afd92f7e2f..83704e1b5c 100644 --- a/apps/remix-ide-e2e/src/types/index.d.ts +++ b/apps/remix-ide-e2e/src/types/index.d.ts @@ -28,7 +28,7 @@ declare module "nightwatch" { checkElementStyle(cssSelector: string, styleProperty: string, expectedResult: string): NightwatchBrowser, openFile(name: string): NightwatchBrowser, editorScroll(direction: 'up' | 'down', numberOfTimes: number): NightwatchBrowser, - renameFile(path: string, newFileName: string, renamedPath: string): NightwatchBrowser, + renamePath(path: string, newFileName: string, renamedPath: string): NightwatchBrowser, rightClick(cssSelector: string): NightwatchBrowser, waitForElementContainsText(id: string, value: string): NightwatchBrowser, getModalBody(callback: (value: string, cb: VoidFunction) => void): NightwatchBrowser, diff --git a/package.json b/package.json index e207d2c802..a5657ee525 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "nightwatch_local_editor": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/editor.test.js --env=chrome", "nightwatch_local_compiler": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/compiler_api.test.js --env=chrome", "nightwatch_local_txListener": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/txListener.test.js --env=chrome", - "nightwatch_local_fileManager": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/fileManager_api.test.js --env=chrome", + "nightwatch_local_fileManager": "npm run build:e2e; nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/fileManager_api.test.js --env=chrome", "nightwatch_local_runAndDeploy": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/runAndDeploy.js --env=chrome-runAndDeploy", "nightwatch_local_url": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/url.test.js --env=chrome", "onchange": "onchange apps/remix-ide/build/app.js -- npm-run-all lint", From b731274333f9b625281534ae48c1f1809d310277 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 13 Jan 2021 13:48:53 +0100 Subject: [PATCH 51/99] Fixed failing file-explorer tests. --- .env | 2 +- apps/remix-ide-e2e/src/tests/fileExplorer.test.ts | 6 +++--- apps/remix-ide-e2e/src/tests/remixd.test.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.env b/.env index 21f7eea1af..ca991985f2 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -gist_token=51c492cff9ccd5b819b79ddf5ecd275c725d0d9e +gist_token=3a9d5658e470d2003691d0e75f792abfe72e308a account_passphrase=explain uniform adapt basic blue onion rebel pull rice erase volcano couple account_password=remix_is_cool NODE_OPTIONS=--max-old-space-size=2048 \ No newline at end of file diff --git a/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts b/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts index f2d252f358..209b102d3e 100644 --- a/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts +++ b/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts @@ -103,9 +103,9 @@ module.exports = { .setValue('*[data-id="fileExplorerFileUpload"]', testData.testFile1) .setValue('*[data-id="fileExplorerFileUpload"]', testData.testFile2) .setValue('*[data-id="fileExplorerFileUpload"]', testData.testFile3) - .waitForElementVisible('*[key="browser/editor.test.js"]') - .waitForElementVisible('*[key="browser/fileExplorer.test.js"]') - .waitForElementVisible('*[key="browser/generalSettings.test.js"]') + .waitForElementVisible('[data-id="treeViewLitreeViewItembrowser/editor.test.js"]') + .waitForElementVisible('[data-id="treeViewLitreeViewItembrowser/fileExplorer.test.js"]') + .waitForElementVisible('[data-id="treeViewLitreeViewItembrowser/generalSettings.test.js"]') .end() }, diff --git a/apps/remix-ide-e2e/src/tests/remixd.test.ts b/apps/remix-ide-e2e/src/tests/remixd.test.ts index c45c95a660..d82f8a3800 100644 --- a/apps/remix-ide-e2e/src/tests/remixd.test.ts +++ b/apps/remix-ide-e2e/src/tests/remixd.test.ts @@ -121,7 +121,7 @@ function runTests (browser: NightwatchBrowser) { .setEditorValue('contract test1 { function get () returns (uint) { return 10; }}') .click('[data-path="localhost/folder1/contract_' + browserName + '.sol"]') // rename a file and check .pause(1000) - .renameFile('localhost/folder1/contract_' + browserName + '.sol', 'renamed_contract_' + browserName + '.sol', 'localhost/folder1/renamed_contract_' + browserName + '.sol') + .renamePath('localhost/folder1/contract_' + browserName + '.sol', 'renamed_contract_' + browserName + '.sol', 'localhost/folder1/renamed_contract_' + browserName + '.sol') .pause(1000) .removeFile('localhost/folder1/contract_' + browserName + '_toremove.sol') .perform(function (done) { From 2657f1a0cbdae82164ae6ddbb010dcd797106d1a Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 13 Jan 2021 13:50:18 +0100 Subject: [PATCH 52/99] Use default enviroment variables --- .env | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.env b/.env index ca991985f2..8db17993d7 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -gist_token=3a9d5658e470d2003691d0e75f792abfe72e308a -account_passphrase=explain uniform adapt basic blue onion rebel pull rice erase volcano couple -account_password=remix_is_cool +gist_token= +account_passphrase= +account_password= NODE_OPTIONS=--max-old-space-size=2048 \ No newline at end of file From 1815bc9e4a1b197533fabfc504735cb68ca4094e Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 13 Jan 2021 14:25:05 +0100 Subject: [PATCH 53/99] Fix e2e build --- apps/remix-ide-e2e/src/types/index.d.ts | 4 ++++ package.json | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/src/types/index.d.ts b/apps/remix-ide-e2e/src/types/index.d.ts index 83704e1b5c..320cee78a4 100644 --- a/apps/remix-ide-e2e/src/types/index.d.ts +++ b/apps/remix-ide-e2e/src/types/index.d.ts @@ -63,6 +63,10 @@ declare module "nightwatch" { sendKeys: (selector: string, inputValue: string | string[], callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void) => NightwatchBrowser } + export interface NightwatchAPI { + keys(keysToSend: string, callback?: (this: NightwatchAPI, result: NightwatchCallbackResult) => void): NightwatchAPI + } + export interface NightwatchContractContent { content: string; } diff --git a/package.json b/package.json index a5657ee525..e207d2c802 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "nightwatch_local_editor": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/editor.test.js --env=chrome", "nightwatch_local_compiler": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/compiler_api.test.js --env=chrome", "nightwatch_local_txListener": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/txListener.test.js --env=chrome", - "nightwatch_local_fileManager": "npm run build:e2e; nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/fileManager_api.test.js --env=chrome", + "nightwatch_local_fileManager": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/fileManager_api.test.js --env=chrome", "nightwatch_local_runAndDeploy": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/runAndDeploy.js --env=chrome-runAndDeploy", "nightwatch_local_url": "npm run build:e2e & nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js dist/apps/remix-ide-e2e/src/tests/url.test.js --env=chrome", "onchange": "onchange apps/remix-ide/build/app.js -- npm-run-all lint", From c55d864d9db860344d7f3c621fd43d45382e4779 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 13 Jan 2021 14:37:48 +0100 Subject: [PATCH 54/99] Fix generalSettings test --- apps/remix-ide-e2e/src/tests/generalSettings.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/src/tests/generalSettings.test.ts b/apps/remix-ide-e2e/src/tests/generalSettings.test.ts index daa94963d3..f06d093ea6 100644 --- a/apps/remix-ide-e2e/src/tests/generalSettings.test.ts +++ b/apps/remix-ide-e2e/src/tests/generalSettings.test.ts @@ -20,7 +20,7 @@ module.exports = { browser.waitForElementVisible('*[data-id="remixIdeSidePanel"]', 5000) .waitForElementVisible('*[data-id="settingsTabGenerateContractMetadataLabel"]', 5000) .click('*[data-id="verticalIconsFileExplorerIcons"]') - .click('*[data-id="treeViewTogglebrowser/contracts"]') + .click('[data-id="treeViewLitreeViewItembrowser/contracts"]') .openFile('browser/contracts/3_Ballot.sol') .click('*[data-id="verticalIconsKindsolidity"]') .pause(2000) From 3027c389f3862191c6a9d0f7e432a809afba182a Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 13 Jan 2021 14:59:13 +0100 Subject: [PATCH 55/99] Fixed failing publish contract test --- apps/remix-ide-e2e/src/tests/publishContract.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/publishContract.test.ts b/apps/remix-ide-e2e/src/tests/publishContract.test.ts index 01c22165ea..ac6f87b97d 100644 --- a/apps/remix-ide-e2e/src/tests/publishContract.test.ts +++ b/apps/remix-ide-e2e/src/tests/publishContract.test.ts @@ -16,7 +16,7 @@ module.exports = { browser .waitForElementVisible('#icon-panel', 10000) .clickLaunchIcon('fileExplorers') - .click('*[data-id="treeViewTogglebrowser/contracts"]') + .click('[data-id="treeViewLitreeViewItembrowser/contracts"]') .openFile('browser/contracts/3_Ballot.sol') .verifyContracts(['Ballot']) .click('#publishOnIpfs') @@ -43,8 +43,8 @@ module.exports = { browser .waitForElementVisible('#icon-panel') .clickLaunchIcon('fileExplorers') - .click('*[data-id="treeViewLibrowser/contracts"]') - .click('*[data-id="treeViewLibrowser/contracts"]') + // .click('*[data-id="treeViewLibrowser/contracts"]') + // .click('*[data-id="treeViewLibrowser/contracts"]') .openFile('browser/contracts/1_Storage.sol') .clickLaunchIcon('udapp') .waitForElementPresent('*[data-id="contractDropdownIpfsCheckbox"]') @@ -58,9 +58,9 @@ module.exports = { 'Should remember choice after page refresh': function (browser: NightwatchBrowser) { browser .refresh() - .waitForElementVisible('*[data-id="treeViewLibrowser/contracts"]') - .click('*[data-id="treeViewLibrowser/contracts"]') - .click('*[data-id="treeViewLibrowser/contracts"]') + .waitForElementVisible('[data-id="treeViewLitreeViewItembrowser/contracts"]') + .click('[data-id="treeViewLitreeViewItembrowser/contracts"]') + // .click('*[data-id="treeViewLibrowser/contracts"]') .openFile('browser/contracts/1_Storage.sol') .clickLaunchIcon('udapp') .waitForElementPresent('*[data-id="contractDropdownIpfsCheckbox"]') From d9e0ebfbd15b93c33c3d389e1f0d28653a8e046d Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 13 Jan 2021 15:14:54 +0100 Subject: [PATCH 56/99] Increase delay for modal display --- apps/remix-ide-e2e/src/tests/publishContract.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/remix-ide-e2e/src/tests/publishContract.test.ts b/apps/remix-ide-e2e/src/tests/publishContract.test.ts index ac6f87b97d..463e8ecf21 100644 --- a/apps/remix-ide-e2e/src/tests/publishContract.test.ts +++ b/apps/remix-ide-e2e/src/tests/publishContract.test.ts @@ -20,6 +20,7 @@ module.exports = { .openFile('browser/contracts/3_Ballot.sol') .verifyContracts(['Ballot']) .click('#publishOnIpfs') + .pause(5000) .getModalBody((value, done) => { if (value.indexOf('Metadata of "ballot" was published successfully.') === -1) browser.assert.fail('ipfs deploy failed', '', '') if (value.indexOf('dweb:/ipfs') === -1) browser.assert.fail('ipfs deploy failed', '', '') @@ -31,6 +32,7 @@ module.exports = { 'Publish on Swarm': '' + function (browser: NightwatchBrowser) { browser .click('#publishOnSwarm') + .pause(5000) .getModalBody((value, done) => { if (value.indexOf('Metadata of "ballot" was successfully.') === -1) browser.assert.fail('swarm deploy failed', '', '') if (value.indexOf('bzz') === -1) browser.assert.fail('swarm deploy failed', '', '') From f3910c5d89a32aadffdadb7c0292082ce6d23642 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 13 Jan 2021 16:09:01 +0100 Subject: [PATCH 57/99] Wait for modal visible --- apps/remix-ide-e2e/src/commands/getModalBody.ts | 2 +- apps/remix-ide-e2e/src/tests/publishContract.test.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/remix-ide-e2e/src/commands/getModalBody.ts b/apps/remix-ide-e2e/src/commands/getModalBody.ts index 85ee421aab..2b9012d8d1 100644 --- a/apps/remix-ide-e2e/src/commands/getModalBody.ts +++ b/apps/remix-ide-e2e/src/commands/getModalBody.ts @@ -3,7 +3,7 @@ import EventEmitter from "events" class GetModalBody extends EventEmitter { command (this: NightwatchBrowser, callback: (value: string, cb: VoidFunction) => void) { - this.api.waitForElementVisible('.modal-body') + this.api.waitForElementPresent('.modal-body') .getText('.modal-body', (result) => { console.log(result) const value = typeof result.value === 'string' ? result.value : null diff --git a/apps/remix-ide-e2e/src/tests/publishContract.test.ts b/apps/remix-ide-e2e/src/tests/publishContract.test.ts index 463e8ecf21..a028de6680 100644 --- a/apps/remix-ide-e2e/src/tests/publishContract.test.ts +++ b/apps/remix-ide-e2e/src/tests/publishContract.test.ts @@ -20,7 +20,7 @@ module.exports = { .openFile('browser/contracts/3_Ballot.sol') .verifyContracts(['Ballot']) .click('#publishOnIpfs') - .pause(5000) + .waitForElementVisible('*[data-id="modalDialogContainer"]') .getModalBody((value, done) => { if (value.indexOf('Metadata of "ballot" was published successfully.') === -1) browser.assert.fail('ipfs deploy failed', '', '') if (value.indexOf('dweb:/ipfs') === -1) browser.assert.fail('ipfs deploy failed', '', '') @@ -32,7 +32,7 @@ module.exports = { 'Publish on Swarm': '' + function (browser: NightwatchBrowser) { browser .click('#publishOnSwarm') - .pause(5000) + .waitForElementVisible('*[data-id="modalDialogContainer"]') .getModalBody((value, done) => { if (value.indexOf('Metadata of "ballot" was successfully.') === -1) browser.assert.fail('swarm deploy failed', '', '') if (value.indexOf('bzz') === -1) browser.assert.fail('swarm deploy failed', '', '') From c4052f02fea0465486d3bee18affa249e106ad16 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 13 Jan 2021 17:06:53 +0100 Subject: [PATCH 58/99] Debug ci --- apps/remix-ide-e2e/src/commands/getModalBody.ts | 2 +- apps/remix-ide-e2e/src/tests/publishContract.test.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/remix-ide-e2e/src/commands/getModalBody.ts b/apps/remix-ide-e2e/src/commands/getModalBody.ts index 2b9012d8d1..103044c0f2 100644 --- a/apps/remix-ide-e2e/src/commands/getModalBody.ts +++ b/apps/remix-ide-e2e/src/commands/getModalBody.ts @@ -4,7 +4,7 @@ import EventEmitter from "events" class GetModalBody extends EventEmitter { command (this: NightwatchBrowser, callback: (value: string, cb: VoidFunction) => void) { this.api.waitForElementPresent('.modal-body') - .getText('.modal-body', (result) => { + .getText('#modal-dialog', (result) => { console.log(result) const value = typeof result.value === 'string' ? result.value : null diff --git a/apps/remix-ide-e2e/src/tests/publishContract.test.ts b/apps/remix-ide-e2e/src/tests/publishContract.test.ts index a028de6680..b1aba271a8 100644 --- a/apps/remix-ide-e2e/src/tests/publishContract.test.ts +++ b/apps/remix-ide-e2e/src/tests/publishContract.test.ts @@ -20,7 +20,7 @@ module.exports = { .openFile('browser/contracts/3_Ballot.sol') .verifyContracts(['Ballot']) .click('#publishOnIpfs') - .waitForElementVisible('*[data-id="modalDialogContainer"]') + .pause(10000) .getModalBody((value, done) => { if (value.indexOf('Metadata of "ballot" was published successfully.') === -1) browser.assert.fail('ipfs deploy failed', '', '') if (value.indexOf('dweb:/ipfs') === -1) browser.assert.fail('ipfs deploy failed', '', '') @@ -32,7 +32,7 @@ module.exports = { 'Publish on Swarm': '' + function (browser: NightwatchBrowser) { browser .click('#publishOnSwarm') - .waitForElementVisible('*[data-id="modalDialogContainer"]') + .pause(10000) .getModalBody((value, done) => { if (value.indexOf('Metadata of "ballot" was successfully.') === -1) browser.assert.fail('swarm deploy failed', '', '') if (value.indexOf('bzz') === -1) browser.assert.fail('swarm deploy failed', '', '') From 5f52415f677efcd6f306f9dfcccb074f7c00f442 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 13 Jan 2021 17:14:50 +0100 Subject: [PATCH 59/99] Debug ci --- apps/remix-ide-e2e/src/tests/publishContract.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/src/tests/publishContract.test.ts b/apps/remix-ide-e2e/src/tests/publishContract.test.ts index b1aba271a8..3ff8e6a5a6 100644 --- a/apps/remix-ide-e2e/src/tests/publishContract.test.ts +++ b/apps/remix-ide-e2e/src/tests/publishContract.test.ts @@ -52,7 +52,7 @@ module.exports = { .waitForElementPresent('*[data-id="contractDropdownIpfsCheckbox"]') .click('*[data-id="contractDropdownIpfsCheckbox"]') .click('*[data-id="Deploy - transact (not payable)"]') - .pause(5000) + .pause(10000) .assert.containsText('*[data-id="modalDialogModalBody"]', 'Metadata of "storage" was published successfully.') .modalFooterOKClick() }, From 629544a0faeebc87d9312f1dcae52666c02b351d Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Wed, 13 Jan 2021 17:47:31 +0100 Subject: [PATCH 60/99] Fix publishContract tests --- apps/remix-ide-e2e/src/tests/publishContract.test.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/publishContract.test.ts b/apps/remix-ide-e2e/src/tests/publishContract.test.ts index 3ff8e6a5a6..72d9e2ecc9 100644 --- a/apps/remix-ide-e2e/src/tests/publishContract.test.ts +++ b/apps/remix-ide-e2e/src/tests/publishContract.test.ts @@ -20,7 +20,7 @@ module.exports = { .openFile('browser/contracts/3_Ballot.sol') .verifyContracts(['Ballot']) .click('#publishOnIpfs') - .pause(10000) + .pause(8000) .getModalBody((value, done) => { if (value.indexOf('Metadata of "ballot" was published successfully.') === -1) browser.assert.fail('ipfs deploy failed', '', '') if (value.indexOf('dweb:/ipfs') === -1) browser.assert.fail('ipfs deploy failed', '', '') @@ -32,7 +32,7 @@ module.exports = { 'Publish on Swarm': '' + function (browser: NightwatchBrowser) { browser .click('#publishOnSwarm') - .pause(10000) + .pause(8000) .getModalBody((value, done) => { if (value.indexOf('Metadata of "ballot" was successfully.') === -1) browser.assert.fail('swarm deploy failed', '', '') if (value.indexOf('bzz') === -1) browser.assert.fail('swarm deploy failed', '', '') @@ -52,8 +52,11 @@ module.exports = { .waitForElementPresent('*[data-id="contractDropdownIpfsCheckbox"]') .click('*[data-id="contractDropdownIpfsCheckbox"]') .click('*[data-id="Deploy - transact (not payable)"]') - .pause(10000) - .assert.containsText('*[data-id="modalDialogModalBody"]', 'Metadata of "storage" was published successfully.') + .pause(8000) + .getModalBody((value, done) => { + if (value.indexOf('Metadata of "storage" was published successfully.') === -1) browser.assert.fail('ipfs deploy failed', '', '') + done() + }) .modalFooterOKClick() }, From 670329ddd4714d45e18d2dda15d7895834727853 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 14 Jan 2021 09:47:56 +0100 Subject: [PATCH 61/99] Change data-id for react modal --- apps/remix-ide-e2e/src/tests/publishContract.test.ts | 3 --- .../modal-dialog/src/lib/remix-ui-modal-dialog.tsx | 8 ++++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/publishContract.test.ts b/apps/remix-ide-e2e/src/tests/publishContract.test.ts index 72d9e2ecc9..671893a26e 100644 --- a/apps/remix-ide-e2e/src/tests/publishContract.test.ts +++ b/apps/remix-ide-e2e/src/tests/publishContract.test.ts @@ -45,8 +45,6 @@ module.exports = { browser .waitForElementVisible('#icon-panel') .clickLaunchIcon('fileExplorers') - // .click('*[data-id="treeViewLibrowser/contracts"]') - // .click('*[data-id="treeViewLibrowser/contracts"]') .openFile('browser/contracts/1_Storage.sol') .clickLaunchIcon('udapp') .waitForElementPresent('*[data-id="contractDropdownIpfsCheckbox"]') @@ -65,7 +63,6 @@ module.exports = { .refresh() .waitForElementVisible('[data-id="treeViewLitreeViewItembrowser/contracts"]') .click('[data-id="treeViewLitreeViewItembrowser/contracts"]') - // .click('*[data-id="treeViewLibrowser/contracts"]') .openFile('browser/contracts/1_Storage.sol') .clickLaunchIcon('udapp') .waitForElementPresent('*[data-id="contractDropdownIpfsCheckbox"]') diff --git a/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx b/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx index c2401174a7..929c23786b 100644 --- a/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx +++ b/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx @@ -42,7 +42,7 @@ export const ModalDialog = (props: ModalDialogProps) => { return (
    { onKeyDown={({ keyCode }) => { modalKeyEvent(keyCode) }} >
    -
    +
    {props.title && props.title}
    {!props.showCancelIcon && @@ -70,10 +70,10 @@ export const ModalDialog = (props: ModalDialogProps) => { }
    -
    +
    { props.children ? props.children : props.message }
    -
    +
    {/* todo add autofocus ^^ */} { props.ok && Date: Thu, 14 Jan 2021 09:51:49 +0100 Subject: [PATCH 62/99] Update data-id for fileExplorer test --- apps/remix-ide-e2e/src/tests/fileExplorer.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts b/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts index 209b102d3e..6d59df6426 100644 --- a/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts +++ b/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts @@ -39,7 +39,7 @@ module.exports = { .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/5_Renamed_Contract.sol"]') .rightClick('[data-path="browser/5_Renamed_Contract.sol"]') .click('*[id="menuitemdelete"]') - .waitForElementVisible('*[data-id="modalDialogContainer"]') + .waitForElementVisible('*[data-id="modalDialogContainer-react"]') .pause(2000) .click('.modal-ok') .waitForElementNotPresent('*[data-id="treeViewLitreeViewItembrowser/5_Renamed_Contract.sol"') @@ -67,7 +67,7 @@ module.exports = { .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/Browser_E2E_Tests"]') .rightClick('[data-path="browser/Browser_E2E_Tests"]') .click('*[id="menuitemdelete"]') - .waitForElementVisible('*[data-id="modalDialogContainer"]') + .waitForElementVisible('*[data-id="modalDialogContainer-react"]') .pause(2000) .click('.modal-ok') .waitForElementNotPresent('*[data-id="treeViewLitreeViewItembrowser/Browser_E2E_Tests"]') @@ -80,11 +80,11 @@ module.exports = { .pause(10000) .waitForElementVisible('*[data-id="fileExplorerNewFilepublishToGist"]') .click('*[data-id="fileExplorerNewFilepublishToGist"]') - .waitForElementVisible('*[data-id="modalDialogContainer"]') + .waitForElementVisible('*[data-id="modalDialogContainer-react"]') .pause(2000) .click('.modal-ok') .pause(2000) - .waitForElementVisible('*[data-id="modalDialogContainer"]') + .waitForElementVisible('*[data-id="modalDialogContainer-react"]') .pause(2000) .click('.modal-ok') .pause(2000) From 95c2c2bea6033c2be00313b67fdaa679772269da Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 14 Jan 2021 11:15:19 +0100 Subject: [PATCH 63/99] open dynamic path --- apps/remix-ide-e2e/src/commands/addFile.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/src/commands/addFile.ts b/apps/remix-ide-e2e/src/commands/addFile.ts index 597f106a31..e3d8821a3c 100644 --- a/apps/remix-ide-e2e/src/commands/addFile.ts +++ b/apps/remix-ide-e2e/src/commands/addFile.ts @@ -18,7 +18,7 @@ function addFile (browser: NightwatchBrowser, name: string, content: NightwatchC .pause(2000) .keys(name) .keys(browser.Keys.ENTER) - .openFile('browser/Greet.sol') + .openFile('browser/' + name) .setEditorValue(content.content) .pause(1000) .perform(function () { From a960881da9cb8d89e216b63c3e47c2d64324b273 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 14 Jan 2021 12:04:07 +0100 Subject: [PATCH 64/99] Fixed terminal test --- apps/remix-ide-e2e/src/tests/terminal.test.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/remix-ide-e2e/src/tests/terminal.test.ts b/apps/remix-ide-e2e/src/tests/terminal.test.ts index 57edb3c1cd..3d8aa087c8 100644 --- a/apps/remix-ide-e2e/src/tests/terminal.test.ts +++ b/apps/remix-ide-e2e/src/tests/terminal.test.ts @@ -10,6 +10,7 @@ module.exports = { 'Should execution a simple console command': function (browser: NightwatchBrowser) { browser + .pause(10000) .waitForElementVisible('*[data-id="terminalCli"]', 10000) .executeScript('console.log(1 + 1)') .journalLastChild('2') @@ -97,6 +98,7 @@ module.exports = { 'Call Remix File Resolver (internal URL) from a script': function (browser: NightwatchBrowser) { browser .click('*[data-id="terminalClearConsole"]') // clear the terminal + .click('li[data-id="treeViewLitreeViewItembrowser/resolveExternalUrlAndSave.js"') .addFile('resolveUrl.js', { content: resolveUrl }) .openFile('browser/resolveUrl.js') .pause(1000) @@ -108,6 +110,7 @@ module.exports = { 'Call Remix File Resolver (internal URL) from a script and specify a path': function (browser: NightwatchBrowser) { browser .click('*[data-id="terminalClearConsole"]') // clear the terminal + .click('li[data-id="treeViewLitreeViewItembrowser/resolveUrl.js"') .addFile('resolveExternalUrlAndSaveToaPath.js', { content: resolveExternalUrlAndSaveToaPath }) .openFile('browser/resolveExternalUrlAndSaveToaPath.js') .pause(1000) From 25c39f39b89045e9efc936d94f577018ff416b39 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 14 Jan 2021 12:25:42 +0100 Subject: [PATCH 65/99] Fix debugger test --- apps/remix-ide-e2e/src/tests/debugger.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/src/tests/debugger.test.ts b/apps/remix-ide-e2e/src/tests/debugger.test.ts index 53095537f8..317ac50270 100644 --- a/apps/remix-ide-e2e/src/tests/debugger.test.ts +++ b/apps/remix-ide-e2e/src/tests/debugger.test.ts @@ -109,7 +109,8 @@ module.exports = { browser .clickLaunchIcon('solidity') .setSolidityCompilerVersion('soljson-v0.6.12+commit.27d51765.js') - .clickLaunchIcon('udapp') + .clickLaunchIcon('fileExplorers') + .click('li[data-id="treeViewLitreeViewItembrowser/externalImport.sol"') .testContracts('withABIEncoderV2.sol', sources[2]['browser/withABIEncoderV2.sol'], ['test']) .clickLaunchIcon('udapp') .selectContract('test') From e84d81bd7e9bf1a03643490233ea99f4cd4cb215 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 14 Jan 2021 12:43:56 +0100 Subject: [PATCH 66/99] Fix debugger test --- apps/remix-ide-e2e/src/tests/debugger.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/remix-ide-e2e/src/tests/debugger.test.ts b/apps/remix-ide-e2e/src/tests/debugger.test.ts index 317ac50270..4e7232ea8c 100644 --- a/apps/remix-ide-e2e/src/tests/debugger.test.ts +++ b/apps/remix-ide-e2e/src/tests/debugger.test.ts @@ -186,6 +186,8 @@ module.exports = { 'Should call the debugger api: getTrace': function (browser: NightwatchBrowser) { browser + .clickLaunchIcon('fileExplorers') + .click('li[data-id="treeViewLitreeViewItembrowser/externalImport.sol"') .addFile('test_jsGetTrace.js', { content: jsGetTrace }) .executeScript('remix.exeCurrent()') .pause(3000) From bd5c4521167e728c9840c7d3a71082a0332a75be Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 14 Jan 2021 14:34:08 +0100 Subject: [PATCH 67/99] Update gist test --- apps/remix-ide-e2e/src/tests/gist.test.ts | 24 +++++++++++-------- .../src/lib/remix-ui-modal-dialog.tsx | 1 + 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/gist.test.ts b/apps/remix-ide-e2e/src/tests/gist.test.ts index 9c75fced9a..5c4901f8a4 100644 --- a/apps/remix-ide-e2e/src/tests/gist.test.ts +++ b/apps/remix-ide-e2e/src/tests/gist.test.ts @@ -13,7 +13,7 @@ module.exports = { before: function (browser: NightwatchBrowser, done: VoidFunction) { init(browser, done) }, - 'UploadToGists': function (browser: NightwatchBrowser) { + UploadToGists: function (browser: NightwatchBrowser) { /* - set the access token - publish to gist @@ -24,18 +24,23 @@ module.exports = { const runtimeBrowser = browser.options.desiredCapabilities.browserName browser + .refresh() + .pause(10000) .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) .clickLaunchIcon('fileExplorers') - .rightClick('[data-path="browser/README.txt"]') - .click('*[id="menuitemcreate folder"]') - .waitForElementVisible('*[data-id="modalDialogContainer"]') - .setValue('*[data-id="modalDialogCustomPromptText"]', 'Browser_Tests') - .modalFooterOKClick() + .click('[data-id="fileExplorerNewFilecreateNewFolder"]') + .pause(1000) + .keys('Browser_Tests') + .keys(browser.Keys.ENTER) .waitForElementVisible('*[data-id="treeViewLibrowser/Browser_Tests"]') .addFile('File.sol', { content: '' }) .click('*[data-id="fileExplorerNewFilepublishToGist"]') - .modalFooterOKClick() - .getModalBody((value, done) => { + .waitForElementVisible('*[data-id="modalDialogContainer-react"]') + .pause(2000) + .click('.modal-ok') + .getText('[data-id="modalDialogModalBody-react"]', (result) => { + console.log(result) + const value = typeof result.value === 'string' ? result.value : null const reg = /gist.github.com\/([^.]+)/ const id = value.match(reg) @@ -45,13 +50,12 @@ module.exports = { } else { const gistid = id[1] browser - .modalFooterCancelClick() + .click('[data-id="modal-footer-cancel-react"]') .executeScript(`remix.loadgist('${gistid}')`) .perform((done) => { if (runtimeBrowser === 'chrome') { browser.openFile('browser/gists') } done() }) .waitForElementVisible(`li[key="browser/gists/${gistid}"]`) .click(`li[key="browser/gists/${gistid}"]`) .openFile(`browser/gists/${gistid}/README.txt`) - .perform(done) } }) }, diff --git a/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx b/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx index 929c23786b..154863fd44 100644 --- a/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx +++ b/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx @@ -88,6 +88,7 @@ export const ModalDialog = (props: ModalDialogProps) => { } { props.cancel && { From 4c911ab63ecde756c2d48f0b360f5cc274f3dea9 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 14 Jan 2021 15:25:04 +0100 Subject: [PATCH 68/99] Fix gist test --- .env | 2 +- apps/remix-ide-e2e/src/commands/addFile.ts | 15 ++++++++++----- apps/remix-ide-e2e/src/tests/gist.test.ts | 10 +++++----- apps/remix-ide-e2e/src/types/index.d.ts | 2 +- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/.env b/.env index 8db17993d7..e22d6a6ab8 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -gist_token= +gist_token=41ecc30018511d0eaecd7fa4bd479f3263b61a48 account_passphrase= account_password= NODE_OPTIONS=--max-old-space-size=2048 \ No newline at end of file diff --git a/apps/remix-ide-e2e/src/commands/addFile.ts b/apps/remix-ide-e2e/src/commands/addFile.ts index e3d8821a3c..07f0949ada 100644 --- a/apps/remix-ide-e2e/src/commands/addFile.ts +++ b/apps/remix-ide-e2e/src/commands/addFile.ts @@ -2,9 +2,9 @@ import { NightwatchBrowser, NightwatchContractContent } from 'nightwatch' import EventEmitter from "events" class AddFile extends EventEmitter { - command (this: NightwatchBrowser, name: string, content: NightwatchContractContent): NightwatchBrowser { + command (this: NightwatchBrowser, name: string, content: NightwatchContractContent, open = true): NightwatchBrowser { this.api.perform((done) => { - addFile(this.api, name, content, () => { + addFile(this.api, name, content, open, () => { done() this.emit('complete') }) @@ -13,13 +13,18 @@ class AddFile extends EventEmitter { } } -function addFile (browser: NightwatchBrowser, name: string, content: NightwatchContractContent, done: VoidFunction) { +function addFile (browser: NightwatchBrowser, name: string, content: NightwatchContractContent, open: boolean, done: VoidFunction) { browser.clickLaunchIcon('udapp').clickLaunchIcon('fileExplorers').click('.newFile') .pause(2000) .keys(name) .keys(browser.Keys.ENTER) - .openFile('browser/' + name) - .setEditorValue(content.content) + .perform((done) => { + if (open) { + browser.openFile('browser/' + name) + .setEditorValue(content.content) + } + done() + }) .pause(1000) .perform(function () { done() diff --git a/apps/remix-ide-e2e/src/tests/gist.test.ts b/apps/remix-ide-e2e/src/tests/gist.test.ts index 5c4901f8a4..9d3e8bb1db 100644 --- a/apps/remix-ide-e2e/src/tests/gist.test.ts +++ b/apps/remix-ide-e2e/src/tests/gist.test.ts @@ -27,17 +27,17 @@ module.exports = { .refresh() .pause(10000) .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) - .clickLaunchIcon('fileExplorers') .click('[data-id="fileExplorerNewFilecreateNewFolder"]') .pause(1000) .keys('Browser_Tests') .keys(browser.Keys.ENTER) - .waitForElementVisible('*[data-id="treeViewLibrowser/Browser_Tests"]') - .addFile('File.sol', { content: '' }) + .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/Browser_Tests"]') + .addFile('File.sol', { content: '' }, false) .click('*[data-id="fileExplorerNewFilepublishToGist"]') .waitForElementVisible('*[data-id="modalDialogContainer-react"]') .pause(2000) .click('.modal-ok') + .pause(10000) .getText('[data-id="modalDialogModalBody-react"]', (result) => { console.log(result) const value = typeof result.value === 'string' ? result.value : null @@ -53,8 +53,8 @@ module.exports = { .click('[data-id="modal-footer-cancel-react"]') .executeScript(`remix.loadgist('${gistid}')`) .perform((done) => { if (runtimeBrowser === 'chrome') { browser.openFile('browser/gists') } done() }) - .waitForElementVisible(`li[key="browser/gists/${gistid}"]`) - .click(`li[key="browser/gists/${gistid}"]`) + .waitForElementVisible(`[data-id="treeViewLitreeViewItembrowser/gists/${gistid}"]`) + .click(`[data-id="treeViewLitreeViewItembrowser/gists/${gistid}"]`) .openFile(`browser/gists/${gistid}/README.txt`) } }) diff --git a/apps/remix-ide-e2e/src/types/index.d.ts b/apps/remix-ide-e2e/src/types/index.d.ts index 320cee78a4..3490e90ade 100644 --- a/apps/remix-ide-e2e/src/types/index.d.ts +++ b/apps/remix-ide-e2e/src/types/index.d.ts @@ -10,7 +10,7 @@ declare module "nightwatch" { scrollInto(target: string): NightwatchBrowser, testContracts(fileName: string, contractCode: NightwatchContractContent, compiledContractNames: string[]): NightwatchBrowser, setEditorValue(value: string, callback?: () => void): NightwatchBrowser, - addFile(name: string, content: NightwatchContractContent): NightwatchBrowser, + addFile(name: string, content: NightwatchContractContent, open?: boolean): NightwatchBrowser, verifyContracts(compiledContractNames: string[], opts?: { wait: number, version?: string }): NightwatchBrowser, selectAccount(account?: string): NightwatchBrowser, clickFunction(fnFullName: string, expectedInput?: NightwatchClickFunctionExpectedInput): NightwatchBrowser, From 914ea80d4045ab82b0d9e9b0efccfee56f9b59d3 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Thu, 14 Jan 2021 15:54:07 +0100 Subject: [PATCH 69/99] Fix defaultLayout test --- .env | 2 +- .../src/tests/defaultLayout.test.ts | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.env b/.env index e22d6a6ab8..8db17993d7 100644 --- a/.env +++ b/.env @@ -1,4 +1,4 @@ -gist_token=41ecc30018511d0eaecd7fa4bd479f3263b61a48 +gist_token= account_passphrase= account_password= NODE_OPTIONS=--max-old-space-size=2048 \ No newline at end of file diff --git a/apps/remix-ide-e2e/src/tests/defaultLayout.test.ts b/apps/remix-ide-e2e/src/tests/defaultLayout.test.ts index 94ab72bd2b..3378a49c85 100644 --- a/apps/remix-ide-e2e/src/tests/defaultLayout.test.ts +++ b/apps/remix-ide-e2e/src/tests/defaultLayout.test.ts @@ -20,10 +20,10 @@ module.exports = { browser.waitForElementVisible('div[data-id="remixIdeSidePanel"]') .assert.containsText('h6[data-id="sidePanelSwapitTitle"]', 'FILE EXPLORERS') .waitForElementVisible('div[data-id="filePanelFileExplorerTree"]') - .waitForElementVisible('li[key="browser/contracts"]') - .waitForElementVisible('li[key="browser/scripts"]') - .waitForElementVisible('li[key="browser/tests"]') - .waitForElementVisible('li[key="browser/README.txt"]') + .waitForElementVisible('[data-id="treeViewLitreeViewItembrowser/contracts"]') + .waitForElementVisible('[data-id="treeViewLitreeViewItembrowser/scripts"]') + .waitForElementVisible('[data-id="treeViewLitreeViewItembrowser/tests"]') + .waitForElementVisible('[data-id="treeViewLitreeViewItembrowser/README.txt"]') }, 'Loads Main View': function (browser: NightwatchBrowser) { @@ -61,17 +61,17 @@ module.exports = { 'Toggles File Explorer Browser': function (browser: NightwatchBrowser) { browser .waitForElementVisible('div[data-id="filePanelFileExplorerTree"]') - .assert.visible('ul[key="browser"]') - .click('div[data-id="treeViewTogglebrowser"]') - .assert.hidden('ul[key="browser"]') - .click('div[data-id="treeViewTogglebrowser"]') - .assert.visible('ul[key="browser"]') + .waitForElementPresent('[data-id="treeViewLitreeViewItembrowser/contracts"]') + .click('[data-path="browser"]') + .waitForElementNotPresent('[data-id="treeViewLitreeViewItembrowser/contracts"]') + .click('[data-path="browser"]') + .waitForElementPresent('[data-id="treeViewLitreeViewItembrowser/contracts"]') }, 'Switch Tabs using tabs icon': function (browser: NightwatchBrowser) { browser .waitForElementVisible('div[data-id="filePanelFileExplorerTree"]') - .click('*[data-id="treeViewTogglebrowser/contracts"]') + .click('[data-id="treeViewLitreeViewItembrowser/contracts"]') .openFile('browser/contracts/3_Ballot.sol') .assert.containsText('div[title="browser/contracts/3_Ballot.sol"]', '3_Ballot.sol') .click('span[class^=dropdownCaret]') From 0537013e6854e6f5cd73ea93f06e2fbeb263f8bc Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 15 Jan 2021 11:15:09 +0100 Subject: [PATCH 70/99] Fix remixd tests --- apps/remix-ide-e2e/src/commands/removeFile.ts | 16 +++++++++++----- .../src/tests/fileExplorer.test.ts | 8 ++++---- apps/remix-ide-e2e/src/tests/gist.test.ts | 6 +++--- .../file-explorer/src/lib/file-explorer.tsx | 19 +++++++++++-------- .../src/lib/remix-ui-modal-dialog.tsx | 11 ++++++----- .../modal-dialog/src/lib/types/index.ts | 1 + 6 files changed, 36 insertions(+), 25 deletions(-) diff --git a/apps/remix-ide-e2e/src/commands/removeFile.ts b/apps/remix-ide-e2e/src/commands/removeFile.ts index 512f7c0c3b..89281eeb41 100644 --- a/apps/remix-ide-e2e/src/commands/removeFile.ts +++ b/apps/remix-ide-e2e/src/commands/removeFile.ts @@ -34,13 +34,19 @@ function removeFile (browser: NightwatchBrowser, path: string, done: VoidFunctio contextMenuClick(document.querySelector('[data-path="' + path + '"]')) }, [path], function () { browser - .waitForElementVisible('#menuitemdelete', 2000) + .waitForElementVisible('#menuitemdelete') .click('#menuitemdelete') - .pause(500) - .waitForElementVisible('#modal-footer-ok', 2000) - .click('#modal-footer-ok') - .waitForElementNotPresent('[data-path="' + path + '"]') + .pause(2000) .perform(() => { + if (path.indexOf('browser') !== -1) { + browser.waitForElementVisible('[data-id="browser-modal-footer-ok-react"]') + .click('[data-id="browser-modal-footer-ok-react"]') + .waitForElementNotPresent('[data-path="' + path + '"]') + } else if (path.indexOf('localhost') !== -1) { + browser.waitForElementVisible('[data-id="localhost-modal-footer-ok-react"]') + .click('[data-id="localhost-modal-footer-ok-react"]') + .waitForElementNotPresent('[data-path="' + path + '"]') + } done() }) }) diff --git a/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts b/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts index 6d59df6426..b4255ab51e 100644 --- a/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts +++ b/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts @@ -39,7 +39,7 @@ module.exports = { .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/5_Renamed_Contract.sol"]') .rightClick('[data-path="browser/5_Renamed_Contract.sol"]') .click('*[id="menuitemdelete"]') - .waitForElementVisible('*[data-id="modalDialogContainer-react"]') + .waitForElementVisible('*[data-id="browserModalDialogContainer-react"]') .pause(2000) .click('.modal-ok') .waitForElementNotPresent('*[data-id="treeViewLitreeViewItembrowser/5_Renamed_Contract.sol"') @@ -67,7 +67,7 @@ module.exports = { .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/Browser_E2E_Tests"]') .rightClick('[data-path="browser/Browser_E2E_Tests"]') .click('*[id="menuitemdelete"]') - .waitForElementVisible('*[data-id="modalDialogContainer-react"]') + .waitForElementVisible('*[data-id="browserModalDialogContainer-react"]') .pause(2000) .click('.modal-ok') .waitForElementNotPresent('*[data-id="treeViewLitreeViewItembrowser/Browser_E2E_Tests"]') @@ -80,11 +80,11 @@ module.exports = { .pause(10000) .waitForElementVisible('*[data-id="fileExplorerNewFilepublishToGist"]') .click('*[data-id="fileExplorerNewFilepublishToGist"]') - .waitForElementVisible('*[data-id="modalDialogContainer-react"]') + .waitForElementVisible('*[data-id="browserModalDialogContainer-react"]') .pause(2000) .click('.modal-ok') .pause(2000) - .waitForElementVisible('*[data-id="modalDialogContainer-react"]') + .waitForElementVisible('*[data-id="browserModalDialogContainer-react"]') .pause(2000) .click('.modal-ok') .pause(2000) diff --git a/apps/remix-ide-e2e/src/tests/gist.test.ts b/apps/remix-ide-e2e/src/tests/gist.test.ts index 9d3e8bb1db..ee9d3d128c 100644 --- a/apps/remix-ide-e2e/src/tests/gist.test.ts +++ b/apps/remix-ide-e2e/src/tests/gist.test.ts @@ -34,11 +34,11 @@ module.exports = { .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/Browser_Tests"]') .addFile('File.sol', { content: '' }, false) .click('*[data-id="fileExplorerNewFilepublishToGist"]') - .waitForElementVisible('*[data-id="modalDialogContainer-react"]') + .waitForElementVisible('*[data-id="browserModalDialogContainer-react"]') .pause(2000) .click('.modal-ok') .pause(10000) - .getText('[data-id="modalDialogModalBody-react"]', (result) => { + .getText('[data-id="browserModalDialogModalBody-react"]', (result) => { console.log(result) const value = typeof result.value === 'string' ? result.value : null const reg = /gist.github.com\/([^.]+)/ @@ -50,7 +50,7 @@ module.exports = { } else { const gistid = id[1] browser - .click('[data-id="modal-footer-cancel-react"]') + .click('[data-id="browser-modal-footer-ok-react"]') .executeScript(`remix.loadgist('${gistid}')`) .perform((done) => { if (runtimeBrowser === 'chrome') { browser.openFile('browser/gists') } done() }) .waitForElementVisible(`[data-id="treeViewLitreeViewItembrowser/gists/${gistid}"]`) diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx index 63e421d084..e02712a844 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer.tsx @@ -903,14 +903,17 @@ export const FileExplorer = (props: FileExplorerProps) => {
    - + { + props.name && + }
    ) diff --git a/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx b/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx index 154863fd44..410cb768e3 100644 --- a/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx +++ b/libs/remix-ui/modal-dialog/src/lib/remix-ui-modal-dialog.tsx @@ -42,7 +42,7 @@ export const ModalDialog = (props: ModalDialogProps) => { return (
    { onKeyDown={({ keyCode }) => { modalKeyEvent(keyCode) }} >
    -
    +
    {props.title && props.title}
    {!props.showCancelIcon && @@ -70,13 +70,14 @@ export const ModalDialog = (props: ModalDialogProps) => { }
    -
    +
    { props.children ? props.children : props.message }
    -
    +
    {/* todo add autofocus ^^ */} { props.ok && { if (props.ok.fn) props.ok.fn() @@ -88,7 +89,7 @@ export const ModalDialog = (props: ModalDialogProps) => { } { props.cancel && { diff --git a/libs/remix-ui/modal-dialog/src/lib/types/index.ts b/libs/remix-ui/modal-dialog/src/lib/types/index.ts index 414613b361..29c4d39505 100644 --- a/libs/remix-ui/modal-dialog/src/lib/types/index.ts +++ b/libs/remix-ui/modal-dialog/src/lib/types/index.ts @@ -1,4 +1,5 @@ export interface ModalDialogProps { + id?: string title?: string, message?: string, ok?: { label: string, fn: () => void }, From c7112981a7b92752f8a31b1679eb58c4f772d5cc Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 15 Jan 2021 11:56:39 +0100 Subject: [PATCH 71/99] Fixed editor test --- apps/remix-ide-e2e/src/tests/editor.test.ts | 27 +++++++++++---------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/editor.test.ts b/apps/remix-ide-e2e/src/tests/editor.test.ts index 37f69bf68e..28d67f3f42 100644 --- a/apps/remix-ide-e2e/src/tests/editor.test.ts +++ b/apps/remix-ide-e2e/src/tests/editor.test.ts @@ -14,7 +14,6 @@ module.exports = { browser.waitForElementVisible('div[data-id="mainPanelPluginsContainer"]') .clickLaunchIcon('fileExplorers') .waitForElementVisible('div[data-id="filePanelFileExplorerTree"]') - .click('*[data-id="treeViewLibrowser/contracts"]') .openFile('browser/contracts/1_Storage.sol') .waitForElementVisible('*[data-id="editorInput"]') .checkElementStyle('*[data-id="editorInput"]', 'font-size', '12px') @@ -81,7 +80,10 @@ module.exports = { 'Should highlight source code': function (browser: NightwatchBrowser) { // include all files here because switching between plugins in side-panel removes highlight - browser.addFile('sourcehighlight.js', sourcehighlightScript) + browser + .clickLaunchIcon('fileExplorers') + .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"') + .addFile('sourcehighlight.js', sourcehighlightScript) .addFile('removeSourcehighlightScript.js', removeSourcehighlightScript) .addFile('removeAllSourcehighlightScript.js', removeAllSourcehighlightScript) .openFile('browser/sourcehighlight.js') @@ -96,27 +98,26 @@ module.exports = { }, 'Should remove 1 highlight from source code': function (browser: NightwatchBrowser) { - browser.waitForElementVisible('li[key="browser/removeSourcehighlightScript.js"]') - .click('li[key="browser/removeSourcehighlightScript.js"]') + browser.waitForElementVisible('li[data-id="treeViewLitreeViewItembrowser/removeSourcehighlightScript.js"]') + .click('li[data-id="treeViewLitreeViewItembrowser/removeSourcehighlightScript.js"]') .pause(2000) .executeScript('remix.exeCurrent()') - .waitForElementVisible('li[key="browser/contracts"]') - .click('li[key="browser/contracts"]') // files don't appear, so we click twice to get the files - .click('li[key="browser/contracts"]') - .waitForElementVisible('li[key="browser/contracts/3_Ballot.sol"]') - .click('li[key="browser/contracts/3_Ballot.sol"]') + .waitForElementVisible('li[data-id="treeViewLitreeViewItembrowser/contracts"]') + .click('li[data-id="treeViewLitreeViewItembrowser/contracts"]') + .waitForElementVisible('li[data-id="treeViewLitreeViewItembrowser/contracts/3_Ballot.sol"]') + .click('li[data-id="treeViewLitreeViewItembrowser/contracts/3_Ballot.sol"]') .waitForElementNotPresent('.highlightLine32') .checkElementStyle('.highlightLine40', 'background-color', 'rgb(8, 108, 181)') .checkElementStyle('.highlightLine50', 'background-color', 'rgb(8, 108, 181)') }, 'Should remove all highlights from source code': function (browser: NightwatchBrowser) { - browser.waitForElementVisible('li[key="browser/removeAllSourcehighlightScript.js"]') - .click('li[key="browser/removeAllSourcehighlightScript.js"]') + browser.waitForElementVisible('li[data-id="treeViewLitreeViewItembrowser/removeAllSourcehighlightScript.js"]') + .click('li[data-id="treeViewLitreeViewItembrowser/removeAllSourcehighlightScript.js"]') .pause(2000) .executeScript('remix.exeCurrent()') - .waitForElementVisible('li[key="browser/contracts/3_Ballot.sol"]') - .click('li[key="browser/contracts/3_Ballot.sol"]') + .waitForElementVisible('li[data-id="treeViewLitreeViewItembrowser/contracts/3_Ballot.sol"]') + .click('li[data-id="treeViewLitreeViewItembrowser/contracts/3_Ballot.sol"]') .pause(2000) .waitForElementNotPresent('.highlightLine32') .waitForElementNotPresent('.highlightLine40') From 409523ed7f46beea6b5f6ab8101d970e27848801 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 15 Jan 2021 12:08:02 +0100 Subject: [PATCH 72/99] Fix filemanager_api test --- apps/remix-ide-e2e/src/tests/fileManager_api.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts b/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts index 80d0653a8e..94b545173d 100644 --- a/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts +++ b/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts @@ -63,7 +63,7 @@ module.exports = { .addFile('renameFile.js', { content: executeRename }) .executeScript(`remix.exeCurrent()`) .pause(2000) - .waitForElementPresent('[data-id="treeViewLibrowser/old_contract.sol"]') + .waitForElementPresent('[data-id="treeViewLitreeViewItembrowser/old_contract.sol"]') }, 'Should execute `mkdir` api from file manager external api': function (browser: NightwatchBrowser) { @@ -71,7 +71,7 @@ module.exports = { .addFile('mkdirFile.js', { content: executeMkdir }) .executeScript(`remix.exeCurrent()`) .pause(2000) - .waitForElementPresent('[data-id="treeViewLibrowser/Test_Folder"]') + .waitForElementPresent('[data-id="treeViewLitreeViewItembrowser/Test_Folder"]') }, 'Should execute `readdir` api from file manager external api': function (browser: NightwatchBrowser) { @@ -87,7 +87,7 @@ module.exports = { .addFile('removeFile.js', { content: executeRemove }) .executeScript(`remix.exeCurrent()`) .pause(2000) - .waitForElementNotPresent('[data-id="treeViewLibrowser/old_contract.sol"]') + .waitForElementNotPresent('[data-id="treeViewLitreeViewItembrowser/old_contract.sol"]') }, 'Should execute `remove` api from file manager external api on a folder': function (browser: NightwatchBrowser) { @@ -95,7 +95,7 @@ module.exports = { .addFile('test_jsRemoveFolder.js', { content: executeRemoveOnFolder }) .executeScript('remix.exeCurrent()') .pause(2000) - .waitForElementNotPresent('*[key="browser/tests"]') + .waitForElementNotPresent('[data-id="treeViewLitreeViewItembrowser/tests"]') .end() }, From 330d5002471039d93b603db26c6998e10c91a744 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 15 Jan 2021 12:25:06 +0100 Subject: [PATCH 73/99] Update filemanager_api test --- apps/remix-ide-e2e/src/tests/fileManager_api.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts b/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts index 94b545173d..b27236cb6f 100644 --- a/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts +++ b/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts @@ -76,6 +76,7 @@ module.exports = { 'Should execute `readdir` api from file manager external api': function (browser: NightwatchBrowser) { browser + .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"') .addFile('readdirFile.js', { content: executeReaddir }) .executeScript(`remix.exeCurrent()`) .pause(2000) From 00efb1d44b38a745274f42e3b8b21ddcb5913fcd Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 15 Jan 2021 12:38:23 +0100 Subject: [PATCH 74/99] Update filemanager_api test --- apps/remix-ide-e2e/src/tests/fileManager_api.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts b/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts index b27236cb6f..c963c626fc 100644 --- a/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts +++ b/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts @@ -91,7 +91,8 @@ module.exports = { .waitForElementNotPresent('[data-id="treeViewLitreeViewItembrowser/old_contract.sol"]') }, - 'Should execute `remove` api from file manager external api on a folder': function (browser: NightwatchBrowser) { + // TODO: Fix remove root directory prefix for browser and localhost + 'Should execute `remove` api from file manager external api on a folder': '' + function (browser: NightwatchBrowser) { browser .addFile('test_jsRemoveFolder.js', { content: executeRemoveOnFolder }) .executeScript('remix.exeCurrent()') From 107542433d1639b9cc3728e04bb76c646d222bec Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 15 Jan 2021 12:43:25 +0100 Subject: [PATCH 75/99] Fix solidity imports --- apps/remix-ide-e2e/src/tests/solidityImport.test.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/remix-ide-e2e/src/tests/solidityImport.test.ts b/apps/remix-ide-e2e/src/tests/solidityImport.test.ts index e559e7805f..5cfcda761a 100644 --- a/apps/remix-ide-e2e/src/tests/solidityImport.test.ts +++ b/apps/remix-ide-e2e/src/tests/solidityImport.test.ts @@ -40,6 +40,8 @@ module.exports = { 'Test Github Import - from other branch': function (browser: NightwatchBrowser) { browser .setSolidityCompilerVersion('soljson-v0.5.0+commit.1d4f565a.js') // switch back to 0.5.0 : release-v2.3.0 branch is not solidity 0.6 compliant + .clickLaunchIcon('fileExplorers') + .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"') .addFile('Untitled5.sol', sources[4]['browser/Untitled5.sol']) .clickLaunchIcon('fileExplorers') .verifyContracts(['test8', 'ERC20', 'SafeMath'], {wait: 10000}) @@ -48,6 +50,8 @@ module.exports = { 'Test Github Import - no branch specified': function (browser: NightwatchBrowser) { browser .setSolidityCompilerVersion('soljson-v0.6.2+commit.bacdbe57.js') // open-zeppelin moved to pragma ^0.6.0 (master branch) + .clickLaunchIcon('fileExplorers') + .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"') .addFile('Untitled6.sol', sources[5]['browser/Untitled6.sol']) .clickLaunchIcon('fileExplorers') .verifyContracts(['test10', 'ERC20', 'SafeMath'], {wait: 10000}) @@ -55,6 +59,8 @@ module.exports = { 'Test Github Import - raw URL': function (browser: NightwatchBrowser) { browser + .clickLaunchIcon('fileExplorers') + .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"') .addFile('Untitled7.sol', sources[6]['browser/Untitled7.sol']) .clickLaunchIcon('fileExplorers') .verifyContracts(['test11', 'ERC20', 'SafeMath'], {wait: 10000}) @@ -63,6 +69,8 @@ module.exports = { 'Test switch to a github import from a solidity warning': function (browser: NightwatchBrowser) { browser .setSolidityCompilerVersion('soljson-v0.7.4+commit.3f05b770.js') + .clickLaunchIcon('fileExplorers') + .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"') .addFile('Untitled8.sol', sources[7]['browser/Untitled8.sol']) .clickLaunchIcon('fileExplorers') .clickLaunchIcon('solidity') From 46d3f6aa34d363dccea4fb3522273bffde8e5270 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 15 Jan 2021 13:35:15 +0100 Subject: [PATCH 76/99] Fix solidity unittests tes --- .../src/tests/solidityUnittests.test.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts b/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts index 6a465b9e7a..d9048b716f 100644 --- a/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts +++ b/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts @@ -42,7 +42,7 @@ module.exports = { 'Should run simple unit test `simple_storage_test.sol` ': function (browser: NightwatchBrowser) { browser.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]') - .addFile('tests/simple_storage_test.sol', sources[0]['browser/tests/simple_storage_test.sol']) + .addFile('simple_storage_test.sol', sources[0]['browser/tests/simple_storage_test.sol']) .click('*[data-id="verticalIconsKindsolidityUnitTesting"]') .waitForElementPresent('*[data-id="testTabCheckAllTests"]') .click('*[data-id="testTabCheckAllTests"]') @@ -62,7 +62,7 @@ module.exports = { 'Should run advance unit test using natspec and experimental ABIEncoderV2 `ks2b_test.sol` ': function (browser: NightwatchBrowser) { browser.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]') .clickLaunchIcon('fileExplorers') - .addFile('tests/ks2b_test.sol', sources[0]['browser/tests/ks2b_test.sol']) + .addFile('ks2b_test.sol', sources[0]['browser/tests/ks2b_test.sol']) .click('*[data-id="verticalIconsKindsolidityUnitTesting"]') .waitForElementPresent('*[data-id="testTabCheckAllTests"]') .click('*[data-id="testTabCheckAllTests"]') @@ -102,7 +102,7 @@ module.exports = { 'Should fail on compilation': function (browser: NightwatchBrowser) { browser.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]') - .addFile('tests/compilationError_test.sol', sources[0]['browser/compilationError_test.sol']) + .addFile('compilationError_test.sol', sources[0]['browser/compilationError_test.sol']) .clickLaunchIcon('fileExplorers') .openFile('browser/tests/compilationError_test.sol') .clickLaunchIcon('solidityUnitTesting') @@ -117,7 +117,7 @@ module.exports = { 'Should fail on deploy': function (browser: NightwatchBrowser) { browser.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]') - .addFile('tests/deployError_test.sol', sources[0]['browser/tests/deployError_test.sol']) + .addFile('deployError_test.sol', sources[0]['browser/tests/deployError_test.sol']) .clickLaunchIcon('fileExplorers') .openFile('browser/tests/deployError_test.sol') .clickLaunchIcon('solidityUnitTesting') @@ -131,7 +131,7 @@ module.exports = { 'Should fail when parameters are to method in test contract': function (browser: NightwatchBrowser) { browser.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]') - .addFile('tests/methodFailure_test.sol', sources[0]['browser/tests/methodFailure_test.sol']) + .addFile('methodFailure_test.sol', sources[0]['browser/tests/methodFailure_test.sol']) .clickLaunchIcon('fileExplorers') .openFile('browser/tests/methodFailure_test.sol') .clickLaunchIcon('solidityUnitTesting') @@ -144,7 +144,10 @@ module.exports = { }, 'Changing current path': function (browser: NightwatchBrowser) { - browser.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]') + browser + .clickLaunchIcon('fileExplorers') + .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"') + .waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]') .addFile('myTests/simple_storage_test.sol', sources[0]['browser/tests/simple_storage_test.sol']) .clickLaunchIcon('solidityUnitTesting') .setValue('*[data-id="uiPathInput"]', 'browser/myTests') @@ -167,7 +170,7 @@ function runTests (browser: NightwatchBrowser) { browser .waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]') .clickLaunchIcon('fileExplorers') - .click('*[data-id="treeViewTogglebrowser/contracts"]') + .click('*[data-id="treeViewLitreeViewItembrowser/contracts"]') .openFile('browser/contracts/3_Ballot.sol') .clickLaunchIcon('solidityUnitTesting') .pause(500) From f3a07ddb625cfcc6d62126eb38f3cda695acd186 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 15 Jan 2021 14:29:07 +0100 Subject: [PATCH 77/99] Update solidityUnitTests test --- apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts b/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts index d9048b716f..482a3f8a25 100644 --- a/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts +++ b/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts @@ -42,7 +42,7 @@ module.exports = { 'Should run simple unit test `simple_storage_test.sol` ': function (browser: NightwatchBrowser) { browser.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]') - .addFile('simple_storage_test.sol', sources[0]['browser/tests/simple_storage_test.sol']) + .addFile('simple_storage_test.sol', sources[0]['browser/tests/simple_storage_test.sol'], false) .click('*[data-id="verticalIconsKindsolidityUnitTesting"]') .waitForElementPresent('*[data-id="testTabCheckAllTests"]') .click('*[data-id="testTabCheckAllTests"]') @@ -62,7 +62,7 @@ module.exports = { 'Should run advance unit test using natspec and experimental ABIEncoderV2 `ks2b_test.sol` ': function (browser: NightwatchBrowser) { browser.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]') .clickLaunchIcon('fileExplorers') - .addFile('ks2b_test.sol', sources[0]['browser/tests/ks2b_test.sol']) + .addFile('ks2b_test.sol', sources[0]['browser/tests/ks2b_test.sol'], false) .click('*[data-id="verticalIconsKindsolidityUnitTesting"]') .waitForElementPresent('*[data-id="testTabCheckAllTests"]') .click('*[data-id="testTabCheckAllTests"]') From 2600fd00c64e0f5938a070c5500eec2e473dc9b0 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 15 Jan 2021 18:21:01 +0100 Subject: [PATCH 78/99] Fixed test-tab undefined error --- apps/remix-ide/src/app/tabs/test-tab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/remix-ide/src/app/tabs/test-tab.js b/apps/remix-ide/src/app/tabs/test-tab.js index 807e7b5c34..e1853ae500 100644 --- a/apps/remix-ide/src/app/tabs/test-tab.js +++ b/apps/remix-ide/src/app/tabs/test-tab.js @@ -52,7 +52,7 @@ module.exports = class TestTab extends ViewPlugin { listenToEvents () { this.filePanel.event.register('newTestFileCreated', file => { - var testList = this.view.querySelector("[class^='testList']") + var testList = this._view.el.querySelector("[class^='testList']") var test = this.createSingleTest(file) testList.appendChild(test) this.data.allTests.push(file) From e54320442e1b557dd3fe9293f36ce46fcf2a59c9 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 15 Jan 2021 19:08:57 +0100 Subject: [PATCH 79/99] Modify addFile command --- apps/remix-ide-e2e/src/commands/addFile.ts | 22 +++++++++---------- apps/remix-ide-e2e/src/tests/debugger.test.ts | 2 -- apps/remix-ide-e2e/src/tests/editor.test.ts | 2 -- .../src/tests/fileManager_api.test.ts | 1 - apps/remix-ide-e2e/src/tests/gist.test.ts | 2 +- .../src/tests/solidityImport.test.ts | 2 -- .../src/tests/solidityUnittests.test.ts | 10 ++++----- apps/remix-ide-e2e/src/tests/terminal.test.ts | 2 -- .../src/tests/usingWebWorker.test.ts | 2 +- apps/remix-ide-e2e/src/types/index.d.ts | 2 +- 10 files changed, 18 insertions(+), 29 deletions(-) diff --git a/apps/remix-ide-e2e/src/commands/addFile.ts b/apps/remix-ide-e2e/src/commands/addFile.ts index 07f0949ada..918819640f 100644 --- a/apps/remix-ide-e2e/src/commands/addFile.ts +++ b/apps/remix-ide-e2e/src/commands/addFile.ts @@ -2,9 +2,9 @@ import { NightwatchBrowser, NightwatchContractContent } from 'nightwatch' import EventEmitter from "events" class AddFile extends EventEmitter { - command (this: NightwatchBrowser, name: string, content: NightwatchContractContent, open = true): NightwatchBrowser { + command (this: NightwatchBrowser, name: string, content: NightwatchContractContent): NightwatchBrowser { this.api.perform((done) => { - addFile(this.api, name, content, open, () => { + addFile(this.api, name, content, () => { done() this.emit('complete') }) @@ -13,18 +13,18 @@ class AddFile extends EventEmitter { } } -function addFile (browser: NightwatchBrowser, name: string, content: NightwatchContractContent, open: boolean, done: VoidFunction) { - browser.clickLaunchIcon('udapp').clickLaunchIcon('fileExplorers').click('.newFile') +function addFile (browser: NightwatchBrowser, name: string, content: NightwatchContractContent, done: VoidFunction) { + browser.clickLaunchIcon('udapp') + .clickLaunchIcon('fileExplorers') + .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"]') // focus on root directory + .click('.newFile') .pause(2000) .keys(name) .keys(browser.Keys.ENTER) - .perform((done) => { - if (open) { - browser.openFile('browser/' + name) - .setEditorValue(content.content) - } - done() - }) + .pause(2000) + .waitForElementVisible(`li[data-id="treeViewLitreeViewItembrowser/${name}"]`) + .click(`li[data-id="treeViewLitreeViewItembrowser/${name}"]`) + .setEditorValue(content.content) .pause(1000) .perform(function () { done() diff --git a/apps/remix-ide-e2e/src/tests/debugger.test.ts b/apps/remix-ide-e2e/src/tests/debugger.test.ts index 4e7232ea8c..317ac50270 100644 --- a/apps/remix-ide-e2e/src/tests/debugger.test.ts +++ b/apps/remix-ide-e2e/src/tests/debugger.test.ts @@ -186,8 +186,6 @@ module.exports = { 'Should call the debugger api: getTrace': function (browser: NightwatchBrowser) { browser - .clickLaunchIcon('fileExplorers') - .click('li[data-id="treeViewLitreeViewItembrowser/externalImport.sol"') .addFile('test_jsGetTrace.js', { content: jsGetTrace }) .executeScript('remix.exeCurrent()') .pause(3000) diff --git a/apps/remix-ide-e2e/src/tests/editor.test.ts b/apps/remix-ide-e2e/src/tests/editor.test.ts index 28d67f3f42..e6ef792298 100644 --- a/apps/remix-ide-e2e/src/tests/editor.test.ts +++ b/apps/remix-ide-e2e/src/tests/editor.test.ts @@ -81,8 +81,6 @@ module.exports = { 'Should highlight source code': function (browser: NightwatchBrowser) { // include all files here because switching between plugins in side-panel removes highlight browser - .clickLaunchIcon('fileExplorers') - .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"') .addFile('sourcehighlight.js', sourcehighlightScript) .addFile('removeSourcehighlightScript.js', removeSourcehighlightScript) .addFile('removeAllSourcehighlightScript.js', removeAllSourcehighlightScript) diff --git a/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts b/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts index c963c626fc..2eb4c73d00 100644 --- a/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts +++ b/apps/remix-ide-e2e/src/tests/fileManager_api.test.ts @@ -76,7 +76,6 @@ module.exports = { 'Should execute `readdir` api from file manager external api': function (browser: NightwatchBrowser) { browser - .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"') .addFile('readdirFile.js', { content: executeReaddir }) .executeScript(`remix.exeCurrent()`) .pause(2000) diff --git a/apps/remix-ide-e2e/src/tests/gist.test.ts b/apps/remix-ide-e2e/src/tests/gist.test.ts index ee9d3d128c..2381f9c8d7 100644 --- a/apps/remix-ide-e2e/src/tests/gist.test.ts +++ b/apps/remix-ide-e2e/src/tests/gist.test.ts @@ -32,7 +32,7 @@ module.exports = { .keys('Browser_Tests') .keys(browser.Keys.ENTER) .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/Browser_Tests"]') - .addFile('File.sol', { content: '' }, false) + .addFile('File.sol', { content: '' }) .click('*[data-id="fileExplorerNewFilepublishToGist"]') .waitForElementVisible('*[data-id="browserModalDialogContainer-react"]') .pause(2000) diff --git a/apps/remix-ide-e2e/src/tests/solidityImport.test.ts b/apps/remix-ide-e2e/src/tests/solidityImport.test.ts index 5cfcda761a..a34e974f50 100644 --- a/apps/remix-ide-e2e/src/tests/solidityImport.test.ts +++ b/apps/remix-ide-e2e/src/tests/solidityImport.test.ts @@ -40,8 +40,6 @@ module.exports = { 'Test Github Import - from other branch': function (browser: NightwatchBrowser) { browser .setSolidityCompilerVersion('soljson-v0.5.0+commit.1d4f565a.js') // switch back to 0.5.0 : release-v2.3.0 branch is not solidity 0.6 compliant - .clickLaunchIcon('fileExplorers') - .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"') .addFile('Untitled5.sol', sources[4]['browser/Untitled5.sol']) .clickLaunchIcon('fileExplorers') .verifyContracts(['test8', 'ERC20', 'SafeMath'], {wait: 10000}) diff --git a/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts b/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts index 482a3f8a25..d2f1061aef 100644 --- a/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts +++ b/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts @@ -42,7 +42,7 @@ module.exports = { 'Should run simple unit test `simple_storage_test.sol` ': function (browser: NightwatchBrowser) { browser.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]') - .addFile('simple_storage_test.sol', sources[0]['browser/tests/simple_storage_test.sol'], false) + .addFile('tests/simple_storage_test.sol', sources[0]['browser/tests/simple_storage_test.sol']) .click('*[data-id="verticalIconsKindsolidityUnitTesting"]') .waitForElementPresent('*[data-id="testTabCheckAllTests"]') .click('*[data-id="testTabCheckAllTests"]') @@ -62,7 +62,7 @@ module.exports = { 'Should run advance unit test using natspec and experimental ABIEncoderV2 `ks2b_test.sol` ': function (browser: NightwatchBrowser) { browser.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]') .clickLaunchIcon('fileExplorers') - .addFile('ks2b_test.sol', sources[0]['browser/tests/ks2b_test.sol'], false) + .addFile('tests/ks2b_test.sol', sources[0]['browser/tests/ks2b_test.sol']) .click('*[data-id="verticalIconsKindsolidityUnitTesting"]') .waitForElementPresent('*[data-id="testTabCheckAllTests"]') .click('*[data-id="testTabCheckAllTests"]') @@ -117,7 +117,7 @@ module.exports = { 'Should fail on deploy': function (browser: NightwatchBrowser) { browser.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]') - .addFile('deployError_test.sol', sources[0]['browser/tests/deployError_test.sol']) + .addFile('tests/deployError_test.sol', sources[0]['browser/tests/deployError_test.sol']) .clickLaunchIcon('fileExplorers') .openFile('browser/tests/deployError_test.sol') .clickLaunchIcon('solidityUnitTesting') @@ -131,7 +131,7 @@ module.exports = { 'Should fail when parameters are to method in test contract': function (browser: NightwatchBrowser) { browser.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]') - .addFile('methodFailure_test.sol', sources[0]['browser/tests/methodFailure_test.sol']) + .addFile('tests/methodFailure_test.sol', sources[0]['browser/tests/methodFailure_test.sol']) .clickLaunchIcon('fileExplorers') .openFile('browser/tests/methodFailure_test.sol') .clickLaunchIcon('solidityUnitTesting') @@ -145,8 +145,6 @@ module.exports = { 'Changing current path': function (browser: NightwatchBrowser) { browser - .clickLaunchIcon('fileExplorers') - .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"') .waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]') .addFile('myTests/simple_storage_test.sol', sources[0]['browser/tests/simple_storage_test.sol']) .clickLaunchIcon('solidityUnitTesting') diff --git a/apps/remix-ide-e2e/src/tests/terminal.test.ts b/apps/remix-ide-e2e/src/tests/terminal.test.ts index 3d8aa087c8..24cd600015 100644 --- a/apps/remix-ide-e2e/src/tests/terminal.test.ts +++ b/apps/remix-ide-e2e/src/tests/terminal.test.ts @@ -98,7 +98,6 @@ module.exports = { 'Call Remix File Resolver (internal URL) from a script': function (browser: NightwatchBrowser) { browser .click('*[data-id="terminalClearConsole"]') // clear the terminal - .click('li[data-id="treeViewLitreeViewItembrowser/resolveExternalUrlAndSave.js"') .addFile('resolveUrl.js', { content: resolveUrl }) .openFile('browser/resolveUrl.js') .pause(1000) @@ -110,7 +109,6 @@ module.exports = { 'Call Remix File Resolver (internal URL) from a script and specify a path': function (browser: NightwatchBrowser) { browser .click('*[data-id="terminalClearConsole"]') // clear the terminal - .click('li[data-id="treeViewLitreeViewItembrowser/resolveUrl.js"') .addFile('resolveExternalUrlAndSaveToaPath.js', { content: resolveExternalUrlAndSaveToaPath }) .openFile('browser/resolveExternalUrlAndSaveToaPath.js') .pause(1000) diff --git a/apps/remix-ide-e2e/src/tests/usingWebWorker.test.ts b/apps/remix-ide-e2e/src/tests/usingWebWorker.test.ts index d5dc8f52cd..d987357954 100644 --- a/apps/remix-ide-e2e/src/tests/usingWebWorker.test.ts +++ b/apps/remix-ide-e2e/src/tests/usingWebWorker.test.ts @@ -28,7 +28,7 @@ module.exports = { browser .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) .clickLaunchIcon('fileExplorers') - .addFile('browser/basic.sol', sources[0]['browser/basic.sol']) + .addFile('basic.sol', sources[0]['browser/basic.sol']) .clickLaunchIcon('solidity') .execute(function() { const elem = document.getElementById('nightlies') as HTMLInputElement diff --git a/apps/remix-ide-e2e/src/types/index.d.ts b/apps/remix-ide-e2e/src/types/index.d.ts index 3490e90ade..320cee78a4 100644 --- a/apps/remix-ide-e2e/src/types/index.d.ts +++ b/apps/remix-ide-e2e/src/types/index.d.ts @@ -10,7 +10,7 @@ declare module "nightwatch" { scrollInto(target: string): NightwatchBrowser, testContracts(fileName: string, contractCode: NightwatchContractContent, compiledContractNames: string[]): NightwatchBrowser, setEditorValue(value: string, callback?: () => void): NightwatchBrowser, - addFile(name: string, content: NightwatchContractContent, open?: boolean): NightwatchBrowser, + addFile(name: string, content: NightwatchContractContent): NightwatchBrowser, verifyContracts(compiledContractNames: string[], opts?: { wait: number, version?: string }): NightwatchBrowser, selectAccount(account?: string): NightwatchBrowser, clickFunction(fnFullName: string, expectedInput?: NightwatchClickFunctionExpectedInput): NightwatchBrowser, From a34d88c47cb010d7d5a1bbb78670117b94692dc5 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 15 Jan 2021 19:21:59 +0100 Subject: [PATCH 80/99] Set correct path for unit test --- apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts b/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts index d2f1061aef..83a1071633 100644 --- a/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts +++ b/apps/remix-ide-e2e/src/tests/solidityUnittests.test.ts @@ -102,7 +102,7 @@ module.exports = { 'Should fail on compilation': function (browser: NightwatchBrowser) { browser.waitForElementPresent('*[data-id="verticalIconsKindfileExplorers"]') - .addFile('compilationError_test.sol', sources[0]['browser/compilationError_test.sol']) + .addFile('tests/compilationError_test.sol', sources[0]['browser/compilationError_test.sol']) .clickLaunchIcon('fileExplorers') .openFile('browser/tests/compilationError_test.sol') .clickLaunchIcon('solidityUnitTesting') From 3e85e3c42522bf5b03d1ee3ec823aa604ed2a777 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 15 Jan 2021 19:34:16 +0100 Subject: [PATCH 81/99] Fix failing firefox command --- apps/remix-ide-e2e/src/commands/addFile.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/remix-ide-e2e/src/commands/addFile.ts b/apps/remix-ide-e2e/src/commands/addFile.ts index 918819640f..f88bc71df4 100644 --- a/apps/remix-ide-e2e/src/commands/addFile.ts +++ b/apps/remix-ide-e2e/src/commands/addFile.ts @@ -19,8 +19,8 @@ function addFile (browser: NightwatchBrowser, name: string, content: NightwatchC .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"]') // focus on root directory .click('.newFile') .pause(2000) - .keys(name) - .keys(browser.Keys.ENTER) + .sendKeys('[data-id="treeViewLitreeViewItembrowser/blank"]', name) + .sendKeys('[data-id="treeViewLitreeViewItembrowser/blank"]', browser.Keys.ENTER) .pause(2000) .waitForElementVisible(`li[data-id="treeViewLitreeViewItembrowser/${name}"]`) .click(`li[data-id="treeViewLitreeViewItembrowser/${name}"]`) From 5a723d86e297c87cd67d1d332382df01c82209bf Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 15 Jan 2021 20:09:31 +0100 Subject: [PATCH 82/99] Fix failing firefox command --- apps/remix-ide-e2e/src/commands/addFile.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/remix-ide-e2e/src/commands/addFile.ts b/apps/remix-ide-e2e/src/commands/addFile.ts index f88bc71df4..747b27cadb 100644 --- a/apps/remix-ide-e2e/src/commands/addFile.ts +++ b/apps/remix-ide-e2e/src/commands/addFile.ts @@ -18,9 +18,10 @@ function addFile (browser: NightwatchBrowser, name: string, content: NightwatchC .clickLaunchIcon('fileExplorers') .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"]') // focus on root directory .click('.newFile') - .pause(2000) - .sendKeys('[data-id="treeViewLitreeViewItembrowser/blank"]', name) - .sendKeys('[data-id="treeViewLitreeViewItembrowser/blank"]', browser.Keys.ENTER) + .waitForElementVisible('[data-id="treeViewLitreeViewItembrowser/blank"]') + .click('[data-id="treeViewLitreeViewItembrowser/blank"]') + .sendKeys('[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', name) + .sendKeys('[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', browser.Keys.ENTER) .pause(2000) .waitForElementVisible(`li[data-id="treeViewLitreeViewItembrowser/${name}"]`) .click(`li[data-id="treeViewLitreeViewItembrowser/${name}"]`) From a4a6c6185cfbeea7ad71966e9a7e0b34d10614c3 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 15 Jan 2021 23:29:43 +0100 Subject: [PATCH 83/99] Update addFile custom command --- apps/remix-ide-e2e/src/commands/addFile.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/remix-ide-e2e/src/commands/addFile.ts b/apps/remix-ide-e2e/src/commands/addFile.ts index 747b27cadb..96acbae867 100644 --- a/apps/remix-ide-e2e/src/commands/addFile.ts +++ b/apps/remix-ide-e2e/src/commands/addFile.ts @@ -18,8 +18,8 @@ function addFile (browser: NightwatchBrowser, name: string, content: NightwatchC .clickLaunchIcon('fileExplorers') .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"]') // focus on root directory .click('.newFile') - .waitForElementVisible('[data-id="treeViewLitreeViewItembrowser/blank"]') - .click('[data-id="treeViewLitreeViewItembrowser/blank"]') + .waitForElementVisible('[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items') + .click('[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items') .sendKeys('[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', name) .sendKeys('[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', browser.Keys.ENTER) .pause(2000) From b997b19f565d109005782b10f32a9520e221df1e Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 15 Jan 2021 23:38:11 +0100 Subject: [PATCH 84/99] Update addFile custom command --- apps/remix-ide-e2e/src/commands/addFile.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/remix-ide-e2e/src/commands/addFile.ts b/apps/remix-ide-e2e/src/commands/addFile.ts index 96acbae867..cc53774b94 100644 --- a/apps/remix-ide-e2e/src/commands/addFile.ts +++ b/apps/remix-ide-e2e/src/commands/addFile.ts @@ -18,10 +18,10 @@ function addFile (browser: NightwatchBrowser, name: string, content: NightwatchC .clickLaunchIcon('fileExplorers') .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"]') // focus on root directory .click('.newFile') - .waitForElementVisible('[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items') - .click('[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items') - .sendKeys('[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', name) - .sendKeys('[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', browser.Keys.ENTER) + .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/blank"]') + .click('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items') + .sendKeys('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', name) + .sendKeys('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', browser.Keys.ENTER) .pause(2000) .waitForElementVisible(`li[data-id="treeViewLitreeViewItembrowser/${name}"]`) .click(`li[data-id="treeViewLitreeViewItembrowser/${name}"]`) From ef325e4fe52e547d96626a640a5951411c85892f Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 15 Jan 2021 23:47:58 +0100 Subject: [PATCH 85/99] scroll and click addFile --- apps/remix-ide-e2e/src/commands/addFile.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/src/commands/addFile.ts b/apps/remix-ide-e2e/src/commands/addFile.ts index cc53774b94..c2e77291d9 100644 --- a/apps/remix-ide-e2e/src/commands/addFile.ts +++ b/apps/remix-ide-e2e/src/commands/addFile.ts @@ -19,7 +19,7 @@ function addFile (browser: NightwatchBrowser, name: string, content: NightwatchC .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"]') // focus on root directory .click('.newFile') .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/blank"]') - .click('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items') + .scrollAndClick('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items') .sendKeys('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', name) .sendKeys('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', browser.Keys.ENTER) .pause(2000) From 9c9aecf5fed0445f30020db327b41cb3b95d6415 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Fri, 15 Jan 2021 23:57:13 +0100 Subject: [PATCH 86/99] Remove unreachable element --- apps/remix-ide-e2e/src/commands/addFile.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/src/commands/addFile.ts b/apps/remix-ide-e2e/src/commands/addFile.ts index c2e77291d9..4eeca25002 100644 --- a/apps/remix-ide-e2e/src/commands/addFile.ts +++ b/apps/remix-ide-e2e/src/commands/addFile.ts @@ -19,7 +19,7 @@ function addFile (browser: NightwatchBrowser, name: string, content: NightwatchC .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"]') // focus on root directory .click('.newFile') .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/blank"]') - .scrollAndClick('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items') + // .scrollAndClick('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items') .sendKeys('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', name) .sendKeys('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', browser.Keys.ENTER) .pause(2000) From ff00618f214b5ecccd1757ac2b46ca75f2dc9152 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Sat, 16 Jan 2021 17:09:26 +0100 Subject: [PATCH 87/99] Fix failing firefox tests --- apps/remix-ide-e2e/src/commands/renamePath.ts | 2 +- apps/remix-ide-e2e/src/tests/fileExplorer.test.ts | 10 ++++++---- apps/remix-ide-e2e/src/tests/gist.test.ts | 5 +++-- apps/remix-ide-e2e/src/tests/terminal.test.ts | 1 + 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/apps/remix-ide-e2e/src/commands/renamePath.ts b/apps/remix-ide-e2e/src/commands/renamePath.ts index fb1fdfeb05..552f159587 100644 --- a/apps/remix-ide-e2e/src/commands/renamePath.ts +++ b/apps/remix-ide-e2e/src/commands/renamePath.ts @@ -42,7 +42,7 @@ function renamePath (browser: NightwatchBrowser, path: string, newFileName: stri }) }) .pause(1000) - .keys(browser.Keys.ENTER) + .click('li[data-id="treeViewLitreeViewItembrowser/README.txt"]') // focus on root directory .pause(2000) .waitForElementNotPresent('[data-path="' + path + '"]') .waitForElementPresent('[data-path="' + renamedPath + '"]') diff --git a/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts b/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts index b4255ab51e..b0bbb056d8 100644 --- a/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts +++ b/apps/remix-ide-e2e/src/tests/fileExplorer.test.ts @@ -22,8 +22,9 @@ module.exports = { .assert.containsText('h6[data-id="sidePanelSwapitTitle"]', 'FILE EXPLORERS') .click('*[data-id="fileExplorerNewFilecreateNewFile"]') .pause(1000) - .keys('5_New_contract.sol') - .keys(browser.Keys.ENTER) + .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/blank"]') + .sendKeys('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', '5_New_contract.sol') + .sendKeys('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', browser.Keys.ENTER) .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/5_New_contract.sol"]', 7000) }, @@ -50,8 +51,9 @@ module.exports = { .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/README.txt"]') .click('[data-id="fileExplorerNewFilecreateNewFolder"]') .pause(1000) - .keys('Browser_Tests') - .keys(browser.Keys.ENTER) + .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/blank"]') + .sendKeys('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', 'Browser_Tests') + .sendKeys('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', browser.Keys.ENTER) .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/Browser_Tests"]') }, diff --git a/apps/remix-ide-e2e/src/tests/gist.test.ts b/apps/remix-ide-e2e/src/tests/gist.test.ts index 2381f9c8d7..8f823954f4 100644 --- a/apps/remix-ide-e2e/src/tests/gist.test.ts +++ b/apps/remix-ide-e2e/src/tests/gist.test.ts @@ -29,8 +29,9 @@ module.exports = { .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) .click('[data-id="fileExplorerNewFilecreateNewFolder"]') .pause(1000) - .keys('Browser_Tests') - .keys(browser.Keys.ENTER) + .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/blank"]') + .sendKeys('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', 'Browser_Tests') + .sendKeys('*[data-id="treeViewLitreeViewItembrowser/blank"] .remixui_items', browser.Keys.ENTER) .waitForElementVisible('*[data-id="treeViewLitreeViewItembrowser/Browser_Tests"]') .addFile('File.sol', { content: '' }) .click('*[data-id="fileExplorerNewFilepublishToGist"]') diff --git a/apps/remix-ide-e2e/src/tests/terminal.test.ts b/apps/remix-ide-e2e/src/tests/terminal.test.ts index 24cd600015..88c21e0055 100644 --- a/apps/remix-ide-e2e/src/tests/terminal.test.ts +++ b/apps/remix-ide-e2e/src/tests/terminal.test.ts @@ -35,6 +35,7 @@ module.exports = { 'Should execute remix.help() command': function (browser: NightwatchBrowser) { browser .waitForElementVisible('*[data-id="terminalCli"]') + .clearEditableContent('*[data-id="terminalCliInput"]') .executeScript('remix.help()') .journalChildIncludes('remix.loadgist(id)') .journalChildIncludes('remix.loadurl(url)') From 298d58af6f66fc9718f7319071cf2eaf7d29d66e Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Sat, 16 Jan 2021 17:58:40 +0100 Subject: [PATCH 88/99] Fix gist test --- apps/remix-ide-e2e/src/tests/gist.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/src/tests/gist.test.ts b/apps/remix-ide-e2e/src/tests/gist.test.ts index 8f823954f4..4884904123 100644 --- a/apps/remix-ide-e2e/src/tests/gist.test.ts +++ b/apps/remix-ide-e2e/src/tests/gist.test.ts @@ -51,7 +51,7 @@ module.exports = { } else { const gistid = id[1] browser - .click('[data-id="browser-modal-footer-ok-react"]') + .click('[data-id="browser-modal-footer-cancel-react"]') .executeScript(`remix.loadgist('${gistid}')`) .perform((done) => { if (runtimeBrowser === 'chrome') { browser.openFile('browser/gists') } done() }) .waitForElementVisible(`[data-id="treeViewLitreeViewItembrowser/gists/${gistid}"]`) From b9251e5264898582d3eae605846e7d3796075724 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Sat, 16 Jan 2021 20:38:08 +0100 Subject: [PATCH 89/99] Fixed failing firefox tests --- apps/remix-ide-e2e/src/commands/clearEditableContent.ts | 2 +- apps/remix-ide-e2e/src/tests/terminal.test.ts | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/remix-ide-e2e/src/commands/clearEditableContent.ts b/apps/remix-ide-e2e/src/commands/clearEditableContent.ts index 8d15f50c96..ad433d3af1 100644 --- a/apps/remix-ide-e2e/src/commands/clearEditableContent.ts +++ b/apps/remix-ide-e2e/src/commands/clearEditableContent.ts @@ -22,7 +22,7 @@ function clearContent (browser: NightwatchBrowser, cssSelector: string, callback selection.removeAllRanges() selection.addRange(range) }, [cssSelector], function () { - browser.keys(browser.Keys.BACK_SPACE) + browser.sendKeys(cssSelector, browser.Keys.BACK_SPACE) .pause(5000) callback() }) diff --git a/apps/remix-ide-e2e/src/tests/terminal.test.ts b/apps/remix-ide-e2e/src/tests/terminal.test.ts index 88c21e0055..57edb3c1cd 100644 --- a/apps/remix-ide-e2e/src/tests/terminal.test.ts +++ b/apps/remix-ide-e2e/src/tests/terminal.test.ts @@ -10,7 +10,6 @@ module.exports = { 'Should execution a simple console command': function (browser: NightwatchBrowser) { browser - .pause(10000) .waitForElementVisible('*[data-id="terminalCli"]', 10000) .executeScript('console.log(1 + 1)') .journalLastChild('2') @@ -35,7 +34,6 @@ module.exports = { 'Should execute remix.help() command': function (browser: NightwatchBrowser) { browser .waitForElementVisible('*[data-id="terminalCli"]') - .clearEditableContent('*[data-id="terminalCliInput"]') .executeScript('remix.help()') .journalChildIncludes('remix.loadgist(id)') .journalChildIncludes('remix.loadurl(url)') From e4568dad9205f385b4e32d7a3383c586bfd650a4 Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Sat, 16 Jan 2021 20:40:25 +0100 Subject: [PATCH 90/99] Restore libs build --- .circleci/config.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index dc8b75889d..a936e1eec6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,10 +21,10 @@ jobs: steps: - checkout - # - run: npm install - # - run: npm run lint:libs - # - run: npm run build:libs - # - run: npm run test:libs + - run: npm install + - run: npm run lint:libs + - run: npm run build:libs + - run: npm run test:libs remix-ide-chrome: docker: From e001bfb40944eba1e7785f3f420c453112bb464a Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Mon, 18 Jan 2021 12:02:07 +0100 Subject: [PATCH 91/99] Uncomment valid events & Updated upload icon tooltip --- apps/remix-ide/src/app/panels/file-panel.js | 19 +++++++++---------- .../src/lib/file-explorer-menu.tsx | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js index a445a78761..9eb9a04c04 100644 --- a/apps/remix-ide/src/app/panels/file-panel.js +++ b/apps/remix-ide/src/app/panels/file-panel.js @@ -74,21 +74,20 @@ module.exports = class Filepanel extends ViewPlugin { this.gitHandle = new GitHandle() this.event = new EventManager() - // fileExplorer.ensureRoot() this._deps.fileProviders.localhost.event.register('connecting', (event) => { }) - // this._deps.fileProviders.localhost.event.register('connected', (event) => { - // fileSystemExplorer.show() - // }) + this._deps.fileProviders.localhost.event.register('connected', (event) => { + this.remixdExplorer.show() + }) - // this._deps.fileProviders.localhost.event.register('errored', (event) => { - // fileSystemExplorer.hide() - // }) + this._deps.fileProviders.localhost.event.register('errored', (event) => { + this.remixdExplorer.hide() + }) - // this._deps.fileProviders.localhost.event.register('closed', (event) => { - // fileSystemExplorer.hide() - // }) + this._deps.fileProviders.localhost.event.register('closed', (event) => { + this.remixdExplorer.hide() + }) this.renderComponent() } diff --git a/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx b/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx index 5f3376b057..c5b4e944fb 100644 --- a/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx +++ b/libs/remix-ui/file-explorer/src/lib/file-explorer-menu.tsx @@ -21,7 +21,7 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { }, { action: 'uploadFile', - title: 'Upload Local files to the Browser Storage Explorer', + title: 'Load a local file into Remix\'s browser folder', icon: 'fa fa-upload' }, { From acb9e5892a620ae613c433ecfbb91ac2ea7f2428 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 18 Jan 2021 15:52:31 +0100 Subject: [PATCH 92/99] Debugger Iframe plugin (#745) fix #588 --- apps/debugger/.babelrc | 4 + apps/debugger/.browserslistrc | 16 + apps/debugger/src/app/app.tsx | 17 + apps/debugger/src/app/debugger-api.ts | 157 ++++ apps/debugger/src/app/debugger.ts | 28 + apps/debugger/src/assets/.gitkeep | 0 .../src/environments/environment.prod.ts | 3 + apps/debugger/src/environments/environment.ts | 6 + apps/debugger/src/favicon.ico | Bin 0 -> 15086 bytes apps/debugger/src/index.html | 15 + apps/debugger/src/index.ts | 1 + apps/debugger/src/main.tsx | 9 + apps/debugger/src/polyfills.ts | 7 + apps/debugger/src/styles.css | 1 + apps/debugger/tsconfig.app.json | 9 + apps/debugger/tsconfig.json | 16 + apps/debugger/tsconfig.spec.json | 15 + apps/debugger/webpack.config.js | 17 + .../src/commands/debugTransaction.ts | 2 +- .../src/commands/goToVMTraceStep.ts | 1 + apps/remix-ide-e2e/src/tests/ballot.test.ts | 3 +- .../src/tests/ballot_0_4_11.test.ts | 2 + apps/remix-ide-e2e/src/tests/debugger.test.ts | 4 +- apps/remix-ide/src/app.js | 7 +- ...compiler-sourceVerifier-fetchAndCompile.js | 6 +- .../src/app/components/local-plugin.js | 15 + apps/remix-ide/src/app/editor/editor.js | 15 +- apps/remix-ide/src/app/tabs/debugger-tab.js | 91 +- .../src/lib/offsetToLineColumnConverter.js | 2 +- libs/remix-debug/src/debugger/debugger.ts | 6 +- libs/remix-ui/debugger-ui/src/index.ts | 2 + .../debugger-ui/src/lib/DebuggerAPI.ts | 64 -- .../debugger-ui/src/lib/debugger-ui.tsx | 53 +- .../debugger-ui/src/lib/idebugger-api.ts | 66 ++ nx.json | 3 + package-lock.json | 805 +++++++++++------- package.json | 6 +- tsconfig.json | 1 + tslint.json | 65 ++ workspace.json | 69 ++ 40 files changed, 1091 insertions(+), 518 deletions(-) create mode 100644 apps/debugger/.babelrc create mode 100644 apps/debugger/.browserslistrc create mode 100644 apps/debugger/src/app/app.tsx create mode 100644 apps/debugger/src/app/debugger-api.ts create mode 100644 apps/debugger/src/app/debugger.ts create mode 100644 apps/debugger/src/assets/.gitkeep create mode 100644 apps/debugger/src/environments/environment.prod.ts create mode 100644 apps/debugger/src/environments/environment.ts create mode 100644 apps/debugger/src/favicon.ico create mode 100644 apps/debugger/src/index.html create mode 100644 apps/debugger/src/index.ts create mode 100644 apps/debugger/src/main.tsx create mode 100644 apps/debugger/src/polyfills.ts create mode 100644 apps/debugger/src/styles.css create mode 100644 apps/debugger/tsconfig.app.json create mode 100644 apps/debugger/tsconfig.json create mode 100644 apps/debugger/tsconfig.spec.json create mode 100644 apps/debugger/webpack.config.js delete mode 100644 libs/remix-ui/debugger-ui/src/lib/DebuggerAPI.ts create mode 100644 libs/remix-ui/debugger-ui/src/lib/idebugger-api.ts create mode 100644 tslint.json diff --git a/apps/debugger/.babelrc b/apps/debugger/.babelrc new file mode 100644 index 0000000000..09d67939cc --- /dev/null +++ b/apps/debugger/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["@nrwl/react/babel"], + "plugins": [] +} diff --git a/apps/debugger/.browserslistrc b/apps/debugger/.browserslistrc new file mode 100644 index 0000000000..f1d12df4fa --- /dev/null +++ b/apps/debugger/.browserslistrc @@ -0,0 +1,16 @@ +# This file is used by: +# 1. autoprefixer to adjust CSS to support the below specified browsers +# 2. babel preset-env to adjust included polyfills +# +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries +# +# If you need to support different browsers in production, you may tweak the list below. + +last 1 Chrome version +last 1 Firefox version +last 2 Edge major versions +last 2 Safari major version +last 2 iOS major versions +Firefox ESR +not IE 9-11 # For IE 9-11 support, remove 'not'. \ No newline at end of file diff --git a/apps/debugger/src/app/app.tsx b/apps/debugger/src/app/app.tsx new file mode 100644 index 0000000000..5cee11a2d9 --- /dev/null +++ b/apps/debugger/src/app/app.tsx @@ -0,0 +1,17 @@ +import React, { useState, useEffect } from 'react'; + +import { DebuggerUI } from '@remix-ui/debugger-ui' // eslint-disable-line + +import { DebuggerClientApi } from './debugger' + +const remix = new DebuggerClientApi() + +export const App = () => { + return ( +
    + +
    + ); +}; + +export default App; diff --git a/apps/debugger/src/app/debugger-api.ts b/apps/debugger/src/app/debugger-api.ts new file mode 100644 index 0000000000..6d52279ccd --- /dev/null +++ b/apps/debugger/src/app/debugger-api.ts @@ -0,0 +1,157 @@ +import Web3 from 'web3' +import remixDebug, { TransactionDebugger as Debugger } from '@remix-project/remix-debug' +import { CompilationOutput, Sources } from '@remix-ui/debugger-ui' +import type { CompilationResult } from '@remix-project/remix-solidity-ts' + +export const DebuggerApiMixin = (Base) => class extends Base { + initDebuggerApi () { + this.debugHash = null + + const self = this + this.web3Provider = { + sendAsync(payload, callback) { + self.call('web3Provider', 'sendAsync', payload) + .then(result => callback(null, result)) + .catch(e => callback(e)) + } + } + this._web3 = new Web3(this.web3Provider) + + this.offsetToLineColumnConverter = { + async offsetToLineColumn (rawLocation, file, sources, asts) { + return await self.call('offsetToLineColumnConverter', 'offsetToLineColumn', rawLocation, file, sources, asts) + } + } + } + + // on() + // call() + // onDebugRequested() + // onRemoveHighlights() + + web3 () { + return this._web3 + } + + async discardHighlight () { + await this.call('editor', 'discardHighlight') + } + + async highlight (lineColumnPos, path) { + await this.call('editor', 'highlight', lineColumnPos, path) + } + + async getFile (path) { + return await this.call('fileManager', 'getFile', path) + } + + async setFile (path, content) { + await this.call('fileManager', 'setFile', path, content) + } + + onBreakpointCleared (listener) { + this.onBreakpointClearedListener = listener + } + + onBreakpointAdded (listener) { + this.onBreakpointAddedListener = listener + } + + onEditorContentChanged (listener) { + this.onEditorContentChangedListener = listener + } + + onDebugRequested (listener) { + this.onDebugRequestedListener = listener + } + + onRemoveHighlights (listener) { + this.onRemoveHighlightsListener = listener + } + + async fetchContractAndCompile (address, receipt) { + const target = (address && remixDebug.traceHelper.isContractCreation(address)) ? receipt.contractAddress : address + const targetAddress = target || receipt.contractAddress || receipt.to + const codeAtAddress = await this._web3.eth.getCode(targetAddress) + const output = await this.call('fetchAndCompile', 'resolve', targetAddress, codeAtAddress, 'browser/.debug') + return new CompilerAbstract(output.languageversion, output.data, output.source) + } + + async getDebugWeb3 () { + let web3 + let network + try { + network = await this.call('network', 'detectNetwork') + } catch (e) { + web3 = this.web3() + } + if (!web3) { + const webDebugNode = remixDebug.init.web3DebugNode(network.name) + web3 = !webDebugNode ? this.web3() : webDebugNode + } + remixDebug.init.extendWeb3(web3) + return web3 + } + + async getTrace (hash) { + if (!hash) return + const web3 = await this.getDebugWeb3() + const currentReceipt = await web3.eth.getTransactionReceipt(hash) + const debug = new Debugger({ + web3, + offsetToLineColumnConverter: this.offsetToLineColumnConverter, + compilationResult: async (address) => { + try { + return await this.fetchContractAndCompile(address, currentReceipt) + } catch (e) { + console.error(e) + } + return null + }, + debugWithGeneratedSources: false + }) + return await debug.debugger.traceManager.getTrace(hash) + } + + debug (hash) { + this.debugHash = hash + this.onDebugRequestedListener(hash) + } + + onActivation () { + this.on('editor', 'breakpointCleared', (fileName, row) => this.onBreakpointClearedListener(fileName, row)) + this.on('editor', 'breakpointAdded', (fileName, row) => this.onBreakpointAddedListener(fileName, row)) + this.on('editor', 'contentChanged', () => this.onEditorContentChangedListener()) + } + + onDeactivation () { + this.onRemoveHighlightsListener() + this.off('editor', 'breakpointCleared') + this.off('editor', 'breakpointAdded') + this.off('editor', 'contentChanged') + } +} + +export class CompilerAbstract implements CompilationOutput { // this is a subset of /remix-ide/src/app/compiler/compiler-abstract.js + languageversion + data + source + + constructor (languageversion: string, data: CompilationResult, source: { sources: Sources, target: string }) { + this.languageversion = languageversion + this.data = data + this.source = source // source code + } + + getSourceName (fileIndex) { + if (this.data && this.data.sources) { + return Object.keys(this.data.sources)[fileIndex] + } else if (Object.keys(this.source.sources).length === 1) { + // if we don't have ast, we return the only one filename present. + const sourcesArray = Object.keys(this.source.sources) + return sourcesArray[0] + } + return null + } +} + diff --git a/apps/debugger/src/app/debugger.ts b/apps/debugger/src/app/debugger.ts new file mode 100644 index 0000000000..4c14f6a3d2 --- /dev/null +++ b/apps/debugger/src/app/debugger.ts @@ -0,0 +1,28 @@ +import { PluginClient } from "@remixproject/plugin"; +import { createClient } from "@remixproject/plugin-webview"; +import { IDebuggerApi, RawLocation, Sources, Asts, LineColumnLocation, + onBreakpointClearedListener, onBreakpointAddedListener, onEditorContentChanged, TransactionReceipt } from '@remix-ui/debugger-ui' +import { DebuggerApiMixin, CompilerAbstract} from './debugger-api' + +export class DebuggerClientApi extends DebuggerApiMixin(PluginClient) { + constructor () { + super() + createClient(this as any) + this.initDebuggerApi() + } + + offsetToLineColumnConverter: IDebuggerApi['offsetToLineColumnConverter'] + debugHash: string + debugHashRequest: number + removeHighlights: boolean + onBreakpointCleared: (listener: onBreakpointClearedListener) => void + onBreakpointAdded: (listener: onBreakpointAddedListener) => void + onEditorContentChanged: (listener: onEditorContentChanged) => void + discardHighlight: () => Promise + highlight: (lineColumnPos: LineColumnLocation, path: string) => Promise + fetchContractAndCompile: (address: string, currentReceipt: TransactionReceipt) => Promise + getFile: (path: string) => Promise + setFile: (path: string, content: string) => Promise + getDebugWeb3: () => any // returns an instance of web3.js +} + diff --git a/apps/debugger/src/assets/.gitkeep b/apps/debugger/src/assets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/apps/debugger/src/environments/environment.prod.ts b/apps/debugger/src/environments/environment.prod.ts new file mode 100644 index 0000000000..3612073bc3 --- /dev/null +++ b/apps/debugger/src/environments/environment.prod.ts @@ -0,0 +1,3 @@ +export const environment = { + production: true +}; diff --git a/apps/debugger/src/environments/environment.ts b/apps/debugger/src/environments/environment.ts new file mode 100644 index 0000000000..d9370e924b --- /dev/null +++ b/apps/debugger/src/environments/environment.ts @@ -0,0 +1,6 @@ +// This file can be replaced during build by using the `fileReplacements` array. +// When building for production, this file is replaced with `environment.prod.ts`. + +export const environment = { + production: false +}; diff --git a/apps/debugger/src/favicon.ico b/apps/debugger/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..317ebcb2336e0833a22dddf0ab287849f26fda57 GIT binary patch literal 15086 zcmeI332;U^%p|z7g|#(P)qFEA@4f!_@qOK2 z_lJl}!lhL!VT_U|uN7%8B2iKH??xhDa;*`g{yjTFWHvXn;2s{4R7kH|pKGdy(7z!K zgftM+Ku7~24TLlh(!g)gz|foI94G^t2^IO$uvX$3(OR0<_5L2sB)lMAMy|+`xodJ{ z_Uh_1m)~h?a;2W{dmhM;u!YGo=)OdmId_B<%^V^{ovI@y`7^g1_V9G}*f# zNzAtvou}I!W1#{M^@ROc(BZ! z+F!!_aR&Px3_reO(EW+TwlW~tv*2zr?iP7(d~a~yA|@*a89IUke+c472NXM0wiX{- zl`UrZC^1XYyf%1u)-Y)jj9;MZ!SLfd2Hl?o|80Su%Z?To_=^g_Jt0oa#CT*tjx>BI z16wec&AOWNK<#i0Qd=1O$fymLRoUR*%;h@*@v7}wApDl^w*h}!sYq%kw+DKDY)@&A z@9$ULEB3qkR#85`lb8#WZw=@})#kQig9oqy^I$dj&k4jU&^2(M3q{n1AKeGUKPFbr z1^<)aH;VsG@J|B&l>UtU#Ejv3GIqERzYgL@UOAWtW<{p#zy`WyJgpCy8$c_e%wYJL zyGHRRx38)HyjU3y{-4z6)pzb>&Q1pR)B&u01F-|&Gx4EZWK$nkUkOI|(D4UHOXg_- zw{OBf!oWQUn)Pe(=f=nt=zkmdjpO^o8ZZ9o_|4tW1ni+Un9iCW47*-ut$KQOww!;u z`0q)$s6IZO!~9$e_P9X!hqLxu`fpcL|2f^I5d4*a@Dq28;@2271v_N+5HqYZ>x;&O z05*7JT)mUe&%S0@UD)@&8SmQrMtsDfZT;fkdA!r(S=}Oz>iP)w=W508=Rc#nNn7ym z1;42c|8($ALY8#a({%1#IXbWn9-Y|0eDY$_L&j{63?{?AH{);EzcqfydD$@-B`Y3<%IIj7S7rK_N}je^=dEk%JQ4c z!tBdTPE3Tse;oYF>cnrapWq*o)m47X1`~6@(!Y29#>-#8zm&LXrXa(3=7Z)ElaQqj z-#0JJy3Fi(C#Rx(`=VXtJ63E2_bZGCz+QRa{W0e2(m3sI?LOcUBx)~^YCqZ{XEPX)C>G>U4tfqeH8L(3|pQR*zbL1 zT9e~4Tb5p9_G}$y4t`i*4t_Mr9QYvL9C&Ah*}t`q*}S+VYh0M6GxTTSXI)hMpMpIq zD1ImYqJLzbj0}~EpE-aH#VCH_udYEW#`P2zYmi&xSPs_{n6tBj=MY|-XrA;SGA_>y zGtU$?HXm$gYj*!N)_nQ59%lQdXtQZS3*#PC-{iB_sm+ytD*7j`D*k(P&IH2GHT}Eh z5697eQECVIGQAUe#eU2I!yI&%0CP#>%6MWV z@zS!p@+Y1i1b^QuuEF*13CuB zu69dve5k7&Wgb+^s|UB08Dr3u`h@yM0NTj4h7MnHo-4@xmyr7(*4$rpPwsCDZ@2be zRz9V^GnV;;?^Lk%ynzq&K(Aix`mWmW`^152Hoy$CTYVehpD-S1-W^#k#{0^L`V6CN+E z!w+xte;2vu4AmVNEFUOBmrBL>6MK@!O2*N|2=d|Y;oN&A&qv=qKn73lDD zI(+oJAdgv>Yr}8(&@ZuAZE%XUXmX(U!N+Z_sjL<1vjy1R+1IeHt`79fnYdOL{$ci7 z%3f0A*;Zt@ED&Gjm|OFTYBDe%bbo*xXAQsFz+Q`fVBH!N2)kaxN8P$c>sp~QXnv>b zwq=W3&Mtmih7xkR$YA)1Yi?avHNR6C99!u6fh=cL|KQ&PwF!n@ud^n(HNIImHD!h87!i*t?G|p0o+eelJ?B@A64_9%SBhNaJ64EvKgD&%LjLCYnNfc; znj?%*p@*?dq#NqcQFmmX($wms@CSAr9#>hUR^=I+=0B)vvGX%T&#h$kmX*s=^M2E!@N9#m?LhMvz}YB+kd zG~mbP|D(;{s_#;hsKK9lbVK&Lo734x7SIFJ9V_}2$@q?zm^7?*XH94w5Qae{7zOMUF z^?%F%)c1Y)Q?Iy?I>knw*8gYW#ok|2gdS=YYZLiD=CW|Nj;n^x!=S#iJ#`~Ld79+xXpVmUK^B(xO_vO!btA9y7w3L3-0j-y4 z?M-V{%z;JI`bk7yFDcP}OcCd*{Q9S5$iGA7*E1@tfkyjAi!;wP^O71cZ^Ep)qrQ)N z#wqw0_HS;T7x3y|`P==i3hEwK%|>fZ)c&@kgKO1~5<5xBSk?iZV?KI6&i72H6S9A* z=U(*e)EqEs?Oc04)V-~K5AUmh|62H4*`UAtItO$O(q5?6jj+K^oD!04r=6#dsxp?~}{`?&sXn#q2 zGuY~7>O2=!u@@Kfu7q=W*4egu@qPMRM>(eyYyaIE<|j%d=iWNdGsx%c!902v#ngNg z@#U-O_4xN$s_9?(`{>{>7~-6FgWpBpqXb`Ydc3OFL#&I}Irse9F_8R@4zSS*Y*o*B zXL?6*Aw!AfkNCgcr#*yj&p3ZDe2y>v$>FUdKIy_2N~}6AbHc7gA3`6$g@1o|dE>vz z4pl(j9;kyMsjaw}lO?(?Xg%4k!5%^t#@5n=WVc&JRa+XT$~#@rldvN3S1rEpU$;XgxVny7mki3 z-Hh|jUCHrUXuLr!)`w>wgO0N%KTB-1di>cj(x3Bav`7v z3G7EIbU$z>`Nad7Rk_&OT-W{;qg)-GXV-aJT#(ozdmnA~Rq3GQ_3mby(>q6Ocb-RgTUhTN)))x>m&eD;$J5Bg zo&DhY36Yg=J=$Z>t}RJ>o|@hAcwWzN#r(WJ52^g$lh^!63@hh+dR$&_dEGu&^CR*< z!oFqSqO@>xZ*nC2oiOd0eS*F^IL~W-rsrO`J`ej{=ou_q^_(<$&-3f^J z&L^MSYWIe{&pYq&9eGaArA~*kA + + + + Debugger + + + + + + + +
    + + diff --git a/apps/debugger/src/index.ts b/apps/debugger/src/index.ts new file mode 100644 index 0000000000..b38e3a7942 --- /dev/null +++ b/apps/debugger/src/index.ts @@ -0,0 +1 @@ +export * from './app/debugger-api'; diff --git a/apps/debugger/src/main.tsx b/apps/debugger/src/main.tsx new file mode 100644 index 0000000000..bc1579ec0f --- /dev/null +++ b/apps/debugger/src/main.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; + +import App from './app/app'; + +ReactDOM.render( + , + document.getElementById('root') +); diff --git a/apps/debugger/src/polyfills.ts b/apps/debugger/src/polyfills.ts new file mode 100644 index 0000000000..2adf3d05b6 --- /dev/null +++ b/apps/debugger/src/polyfills.ts @@ -0,0 +1,7 @@ +/** + * Polyfill stable language features. These imports will be optimized by `@babel/preset-env`. + * + * See: https://github.com/zloirock/core-js#babel + */ +import 'core-js/stable'; +import 'regenerator-runtime/runtime'; diff --git a/apps/debugger/src/styles.css b/apps/debugger/src/styles.css new file mode 100644 index 0000000000..90d4ee0072 --- /dev/null +++ b/apps/debugger/src/styles.css @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/debugger/tsconfig.app.json b/apps/debugger/tsconfig.app.json new file mode 100644 index 0000000000..2151bb6497 --- /dev/null +++ b/apps/debugger/tsconfig.app.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node"] + }, + "exclude": ["**/*.spec.ts", "**/*.spec.tsx"], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/apps/debugger/tsconfig.json b/apps/debugger/tsconfig.json new file mode 100644 index 0000000000..7c6fcde8f2 --- /dev/null +++ b/apps/debugger/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "jsx": "react", + "allowJs": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "types": ["node", "jest"], + "resolveJsonModule": true + }, + "files": [ + "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", + "../../node_modules/@nrwl/react/typings/image.d.ts" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/apps/debugger/tsconfig.spec.json b/apps/debugger/tsconfig.spec.json new file mode 100644 index 0000000000..559410b96a --- /dev/null +++ b/apps/debugger/tsconfig.spec.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "**/*.spec.ts", + "**/*.spec.tsx", + "**/*.spec.js", + "**/*.spec.jsx", + "**/*.d.ts" + ] +} diff --git a/apps/debugger/webpack.config.js b/apps/debugger/webpack.config.js new file mode 100644 index 0000000000..bacc6e251e --- /dev/null +++ b/apps/debugger/webpack.config.js @@ -0,0 +1,17 @@ +const nxWebpack = require('@nrwl/react/plugins/webpack') + +module.exports = config => { + const nxWebpackConfig = nxWebpack(config) + + return { + ...nxWebpackConfig, + node: { + fs: 'empty', + tls: 'empty', + readline: 'empty', + net: 'empty', + module: 'empty', + child_process: 'empty' + } + } +} diff --git a/apps/remix-ide-e2e/src/commands/debugTransaction.ts b/apps/remix-ide-e2e/src/commands/debugTransaction.ts index 85b2b24238..d4d9100800 100644 --- a/apps/remix-ide-e2e/src/commands/debugTransaction.ts +++ b/apps/remix-ide-e2e/src/commands/debugTransaction.ts @@ -19,7 +19,7 @@ function checkStyle (browser: NightwatchBrowser, index: number, callback: VoidFu debugBtn && debugBtn.click() }, [index], function () { - callback() + browser.waitForElementVisible('*[data-id="buttonNavigatorJumpPreviousBreakpoint"]').perform(() => callback()) }) } diff --git a/apps/remix-ide-e2e/src/commands/goToVMTraceStep.ts b/apps/remix-ide-e2e/src/commands/goToVMTraceStep.ts index 7d01074158..c7eda61ebf 100644 --- a/apps/remix-ide-e2e/src/commands/goToVMTraceStep.ts +++ b/apps/remix-ide-e2e/src/commands/goToVMTraceStep.ts @@ -14,6 +14,7 @@ function goToVMtraceStep (browser: NightwatchBrowser, step: number, incr: number browser.execute(function () { return document.querySelector('#stepdetail').innerHTML }, [], function (result) { + console.log('goToVMtraceStep', result) if (typeof result.value === 'string' && ( result.value.indexOf('vm trace step:') !== -1 && result.value.indexOf(step.toString()) !== -1)) { done() } else if (incr > 1000) { diff --git a/apps/remix-ide-e2e/src/tests/ballot.test.ts b/apps/remix-ide-e2e/src/tests/ballot.test.ts index 692eb1bf4d..80528bf886 100644 --- a/apps/remix-ide-e2e/src/tests/ballot.test.ts +++ b/apps/remix-ide-e2e/src/tests/ballot.test.ts @@ -39,10 +39,11 @@ module.exports = { 'Debug Ballot / delegate': function (browser: NightwatchBrowser) { browser.pause(500) .click('*[data-id="txLoggerDebugButton0x41fab8ea5b1d9fba5e0a6545ca1a2d62fff518578802c033c2b9a031a01c31b3"]') - .pause(2000) + .waitForElementVisible('*[data-id="buttonNavigatorJumpPreviousBreakpoint"]') // .clickLaunchIcon('debugger') .click('*[data-id="buttonNavigatorJumpPreviousBreakpoint"]') .pause(2000) + .waitForElementVisible('#stepdetail') .goToVMTraceStep(79) .pause(1000) .checkVariableDebug('soliditystate', stateCheck) diff --git a/apps/remix-ide-e2e/src/tests/ballot_0_4_11.test.ts b/apps/remix-ide-e2e/src/tests/ballot_0_4_11.test.ts index 17f83c4778..ee71c13a58 100644 --- a/apps/remix-ide-e2e/src/tests/ballot_0_4_11.test.ts +++ b/apps/remix-ide-e2e/src/tests/ballot_0_4_11.test.ts @@ -50,8 +50,10 @@ module.exports = { browser.pause(500) .click('*[data-id="txLoggerDebugButton0x41fab8ea5b1d9fba5e0a6545ca1a2d62fff518578802c033c2b9a031a01c31b3"]') .pause(2000) + .waitForElementVisible('*[data-id="buttonNavigatorJumpPreviousBreakpoint"]') .click('*[data-id="buttonNavigatorJumpPreviousBreakpoint"]') .pause(2000) + .waitForElementVisible('#stepdetail') .goToVMTraceStep(20) .pause(1000) .checkVariableDebug('callstackpanel', ["0x692a70D2e424a56D2C6C27aA97D1a86395877b3A"]) diff --git a/apps/remix-ide-e2e/src/tests/debugger.test.ts b/apps/remix-ide-e2e/src/tests/debugger.test.ts index 317ac50270..9e3b84eea3 100644 --- a/apps/remix-ide-e2e/src/tests/debugger.test.ts +++ b/apps/remix-ide-e2e/src/tests/debugger.test.ts @@ -89,6 +89,7 @@ module.exports = { .createContract('"tokenName", "symbol"') .debugTransaction(2) .pause(2000) + .waitForElementVisible('#stepdetail') .goToVMTraceStep(10) .getEditorValue((content) => { browser.assert.ok(content.indexOf(`constructor (string memory name_, string memory symbol_) public { @@ -118,7 +119,8 @@ module.exports = { .clickInstance(2) .clickFunction('test1 - transact (not payable)', {types: 'bytes userData', values: '0x000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000015b38da6a701c568545dcfcb03fcb875f56beddc4'}) .debugTransaction(4) - .pause(2000) + .pause(2000) + .waitForElementVisible('#stepdetail') .goToVMTraceStep(261) .pause(1000) /* diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index fb1788e08c..042204cf07 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -50,7 +50,7 @@ const CompilersArtefacts = require('./app/compiler/compiler-artefacts') const CompileTab = require('./app/tabs/compile-tab') const SettingsTab = require('./app/tabs/settings-tab') const AnalysisTab = require('./app/tabs/analysis-tab') -const DebuggerTab = require('./app/tabs/debugger-tab') +const { DebuggerTab } = require('./app/tabs/debugger-tab') const TestTab = require('./app/tabs/test-tab') const FilePanel = require('./app/panels/file-panel') const Editor = require('./app/editor/editor') @@ -370,10 +370,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org registry.get('fileproviders/browser').api ) const analysis = new AnalysisTab(registry) - const debug = new DebuggerTab( - blockchain, - registry.get('editor').api, - registry.get('offsettolinecolumnconverter').api) + const debug = new DebuggerTab() const test = new TestTab( registry.get('filemanager').api, registry.get('offsettolinecolumnconverter').api, diff --git a/apps/remix-ide/src/app/compiler/compiler-sourceVerifier-fetchAndCompile.js b/apps/remix-ide/src/app/compiler/compiler-sourceVerifier-fetchAndCompile.js index d9fbdc5cce..4a513e2129 100644 --- a/apps/remix-ide/src/app/compiler/compiler-sourceVerifier-fetchAndCompile.js +++ b/apps/remix-ide/src/app/compiler/compiler-sourceVerifier-fetchAndCompile.js @@ -26,10 +26,11 @@ export default class FetchAndCompile extends Plugin { * Returns compilation data * * @param {string} contractAddress - Address of the contrac to resolve - * @param {string} compilersartefacts - Object containing a mapping of compilation results (byContractAddress and __last) + * @param {string} deployedBytecode - deployedBytecode of the contract + * @param {string} targetPath - Folder where to save the compilation arfefacts * @return {CompilerAbstract} - compilation data targeting the given @arg contractAddress */ - async resolve (contractAddress, targetPath, web3) { + async resolve (contractAddress, codeAtAddress, targetPath) { contractAddress = ethutil.toChecksumAddress(contractAddress) const compilersartefacts = globalRegistry.get('compilersartefacts').api @@ -52,7 +53,6 @@ export default class FetchAndCompile extends Plugin { if (!this.sourceVerifierNetWork.includes(network.name)) return localCompilation() // check if the contract if part of the local compilation result - const codeAtAddress = await web3.eth.getCode(contractAddress) const compilation = localCompilation() if (compilation) { let found = false diff --git a/apps/remix-ide/src/app/components/local-plugin.js b/apps/remix-ide/src/app/components/local-plugin.js index 1db3cae6e5..c93bb6775b 100644 --- a/apps/remix-ide/src/app/components/local-plugin.js +++ b/apps/remix-ide/src/app/components/local-plugin.js @@ -67,11 +67,20 @@ module.exports = class LocalPlugin { this.profile[key] = e.target.value } + updateMethods ({ target }) { + if (target.value) { + try { + this.profile.methods = target.value.split(',') + } catch (e) {} + } + } + /** The form to create a local plugin */ form () { const name = this.profile.name || '' const url = this.profile.url || '' const displayName = this.profile.displayName || '' + const methods = (this.profile.methods && this.profile.methods.join(',')) || '' const radioSelection = (key, label, message) => { return this.profile[key] === label ? yo`
    @@ -94,6 +103,12 @@ module.exports = class LocalPlugin {
    + +
    + + +
    +
    diff --git a/apps/remix-ide/src/app/editor/editor.js b/apps/remix-ide/src/app/editor/editor.js index ba5d0dad15..a632378af0 100644 --- a/apps/remix-ide/src/app/editor/editor.js +++ b/apps/remix-ide/src/app/editor/editor.js @@ -174,29 +174,34 @@ class Editor extends Plugin { const breakpoints = e.editor.session.getBreakpoints() for (const k in breakpoints) { if (k === row.toString()) { - this.event.trigger('breakpointCleared', [this.currentSession, row]) + this.triggerEvent('breakpointCleared', [this.currentSession, row]) e.editor.session.clearBreakpoint(row) e.stop() return } } this.setBreakpoint(row) - this.event.trigger('breakpointAdded', [this.currentSession, row]) + this.triggerEvent('breakpointAdded', [this.currentSession, row]) e.stop() }) // Do setup on initialisation here this.editor.on('changeSession', () => { this._onChange() - this.event.trigger('sessionSwitched', []) + this.triggerEvent('sessionSwitched', []) this.editor.getSession().on('change', () => { this._onChange() this.sourceHighlighters.discardAllHighlights() - this.event.trigger('contentChanged', []) + this.triggerEvent('contentChanged', []) }) }) } + triggerEvent (name, params) { + this.event.trigger(name, params) // internal stack + this.emit(name, ...params) // plugin stack + } + onActivation () { this.on('sidePanel', 'focusChanged', (name) => this.sourceHighlighters.hideHighlightsExcept(name)) this.on('sidePanel', 'pluginDisabled', (name) => this.sourceHighlighters.discardHighlight(name)) @@ -247,7 +252,7 @@ class Editor extends Plugin { window.clearTimeout(this.saveTimeout) } this.saveTimeout = window.setTimeout(() => { - this.event.trigger('requiringToSaveCurrentfile', []) + this.triggerEvent('requiringToSaveCurrentfile', []) }, 5000) } diff --git a/apps/remix-ide/src/app/tabs/debugger-tab.js b/apps/remix-ide/src/app/tabs/debugger-tab.js index b471ecb320..3b218fed58 100644 --- a/apps/remix-ide/src/app/tabs/debugger-tab.js +++ b/apps/remix-ide/src/app/tabs/debugger-tab.js @@ -1,7 +1,7 @@ import toaster from '../ui/tooltip' import { DebuggerUI } from '@remix-ui/debugger-ui' // eslint-disable-line +import { DebuggerApiMixin } from '@remixproject/debugger-plugin' import { ViewPlugin } from '@remixproject/engine-web' -import remixDebug, { TransactionDebugger as Debugger } from '@remix-project/remix-debug' import * as packageJson from '../../../../../package.json' import React from 'react' // eslint-disable-line import ReactDOM from 'react-dom' @@ -21,16 +21,11 @@ const profile = { version: packageJson.version } -class DebuggerTab extends ViewPlugin { - constructor (blockchain, editor, offsetToLineColumnConverter) { +export class DebuggerTab extends DebuggerApiMixin(ViewPlugin) { + constructor () { super(profile) this.el = null - this.editor = editor - this.offsetToLineColumnConverter = offsetToLineColumnConverter - this.blockchain = blockchain - this.debugHash = null - this.removeHighlights = false - this.debugHashRequest = 0 + this.initDebuggerApi() } render () { @@ -63,90 +58,12 @@ class DebuggerTab extends ViewPlugin { this.renderComponent() - // this.call('manager', 'activatePlugin', 'udapp') - return this.el } - async discardHighlight () { - await this.call('editor', 'discardHighlight') - } - - async highlight (lineColumnPos, path) { - await this.call('editor', 'highlight', lineColumnPos, path) - } - - async getFile (path) { - await this.call('fileManager', 'getFile', path) - } - - async setFile (path, content) { - await this.call('fileManager', 'setFile', path, content) - } - renderComponent () { ReactDOM.render( , this.el) } - - deactivate () { - this.removeHighlights = true - this.renderComponent() - super.deactivate() - } - - debug (hash) { - this.debugHash = hash - this.debugHashRequest++ // so we can trigger a debug using the same hash 2 times in a row. that's needs to be improved - this.renderComponent() - } - - getDebugWeb3 () { - return new Promise((resolve, reject) => { - this.blockchain.detectNetwork((error, network) => { - let web3 - if (error || !network) { - web3 = remixDebug.init.web3DebugNode(this.blockchain.web3()) - } else { - const webDebugNode = remixDebug.init.web3DebugNode(network.name) - web3 = !webDebugNode ? this.blockchain.web3() : webDebugNode - } - remixDebug.init.extendWeb3(web3) - resolve(web3) - }) - }) - } - - async getTrace (hash) { - if (!hash) return - const web3 = await this.getDebugWeb3() - const currentReceipt = await web3.eth.getTransactionReceipt(hash) - const debug = new Debugger({ - web3, - offsetToLineColumnConverter: this.offsetToLineColumnConverter, - compilationResult: async (address) => { - try { - return await this.fetchContractAndCompile(address, currentReceipt) - } catch (e) { - console.error(e) - } - return null - }, - debugWithGeneratedSources: false - }) - return await debug.debugger.traceManager.getTrace(hash) - } - - fetchContractAndCompile (address, receipt) { - const target = (address && remixDebug.traceHelper.isContractCreation(address)) ? receipt.contractAddress : address - const targetAddress = target || receipt.contractAddress || receipt.to - return this.call('fetchAndCompile', 'resolve', targetAddress, 'browser/.debug', this.blockchain.web3()) - } - - // debugger () { - // return this.debuggerUI - // } } - -module.exports = DebuggerTab diff --git a/apps/remix-ide/src/lib/offsetToLineColumnConverter.js b/apps/remix-ide/src/lib/offsetToLineColumnConverter.js index 07f0de0ec0..b2a2e37e32 100644 --- a/apps/remix-ide/src/lib/offsetToLineColumnConverter.js +++ b/apps/remix-ide/src/lib/offsetToLineColumnConverter.js @@ -5,7 +5,7 @@ import { sourceMappingDecoder } from '@remix-project/remix-debug' const profile = { name: 'offsetToLineColumnConverter', - methods: [], + methods: ['offsetToLineColumn'], events: [], version: packageJson.version } diff --git a/libs/remix-debug/src/debugger/debugger.ts b/libs/remix-debug/src/debugger/debugger.ts index 477f875ca2..53831e72f6 100644 --- a/libs/remix-debug/src/debugger/debugger.ts +++ b/libs/remix-debug/src/debugger/debugger.ts @@ -37,7 +37,7 @@ export class Debugger { locationToRowConverter: async (sourceLocation) => { const compilationResult = await this.compilationResult() if (!compilationResult) return { start: null, end: null } - return this.offsetToLineColumnConverter.offsetToLineColumn(sourceLocation, sourceLocation.file, compilationResult.source.sources, compilationResult.data.sources) + return await this.offsetToLineColumnConverter.offsetToLineColumn(sourceLocation, sourceLocation.file, compilationResult.source.sources, compilationResult.data.sources) } }) @@ -70,7 +70,7 @@ export class Debugger { const compilationResultForAddress = await this.compilationResult(address) if (!compilationResultForAddress) return - this.debugger.callTree.sourceLocationTracker.getValidSourceLocationFromVMTraceIndex(address, index, compilationResultForAddress.data.contracts).then((rawLocation) => { + this.debugger.callTree.sourceLocationTracker.getValidSourceLocationFromVMTraceIndex(address, index, compilationResultForAddress.data.contracts).then(async (rawLocation) => { if (compilationResultForAddress && compilationResultForAddress.data) { const generatedSources = this.debugger.callTree.sourceLocationTracker.getGeneratedSourcesFromAddress(address) const astSources = Object.assign({}, compilationResultForAddress.data.sources) @@ -81,7 +81,7 @@ export class Debugger { sources[genSource.name] = { content: genSource.contents } } } - var lineColumnPos = this.offsetToLineColumnConverter.offsetToLineColumn(rawLocation, rawLocation.file, sources, astSources) + var lineColumnPos = await this.offsetToLineColumnConverter.offsetToLineColumn(rawLocation, rawLocation.file, sources, astSources) this.event.trigger('newSourceLocation', [lineColumnPos, rawLocation, generatedSources, address]) } else { this.event.trigger('newSourceLocation', [null]) diff --git a/libs/remix-ui/debugger-ui/src/index.ts b/libs/remix-ui/debugger-ui/src/index.ts index 57f0619ee0..bc404baa76 100644 --- a/libs/remix-ui/debugger-ui/src/index.ts +++ b/libs/remix-ui/debugger-ui/src/index.ts @@ -1 +1,3 @@ export * from './lib/debugger-ui' +export * from './lib/idebugger-api' +export * from './lib/idebugger-api' diff --git a/libs/remix-ui/debugger-ui/src/lib/DebuggerAPI.ts b/libs/remix-ui/debugger-ui/src/lib/DebuggerAPI.ts deleted file mode 100644 index 9144490b03..0000000000 --- a/libs/remix-ui/debugger-ui/src/lib/DebuggerAPI.ts +++ /dev/null @@ -1,64 +0,0 @@ - -import type { CompilationResult, CompilationSource } from '@remix-project/remix-solidity-ts' - -export interface DebuggerUIProps { - debuggerAPI: DebuggerAPI -} - -interface EditorEvent { - event: { - register(eventName: 'breakpointCleared' | 'breakpointAdded' | 'contentChanged', - callback: (fileName: string, row: string | number) => void) - } -} - -interface LineColumnLocation { - start: { - line: number, column: number - }, - end: { - line: number, column: number - } -} - -interface RawLocation { - start: number, length: number -} - -interface Sources { - [fileName: string] : {content: string} -} - -interface CompilationOutput { - source: { sources: Sources, target: string } - data: CompilationResult - getSourceName: (id: number) => string -} - -interface Asts { - [fileName: string] : CompilationSource // ast -} - -interface TransactionReceipt { - blockHash: string - blockNumber: number - transactionHash: string - transactionIndex: number - from: string - to: string - contractAddress: string | null - } - -export interface DebuggerAPI { - offsetToLineColumnConverter: { offsetToLineColumn: (sourceLocation: RawLocation, file: number, contents: Sources, asts: Asts) => LineColumnLocation } - debugHash: string - debugHashRequest: string - removeHighlights: boolean - editor: EditorEvent - discardHighlight: () => void - highlight: (lineColumnPos: LineColumnLocation, path: string) => void - fetchContractAndCompile: (address: string, currentReceipt: TransactionReceipt) => CompilationOutput - getFile: (path: string) => string - setFile: (path: string, content: string) => void - getDebugWeb3: () => any // returns an instance of web3.js -} \ No newline at end of file diff --git a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx index 4f45e11f83..b8cd7b9bcf 100644 --- a/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx +++ b/libs/remix-ui/debugger-ui/src/lib/debugger-ui.tsx @@ -4,7 +4,7 @@ import StepManager from './step-manager/step-manager' import VmDebugger from './vm-debugger/vm-debugger' import VmDebuggerHead from './vm-debugger/vm-debugger-head' import { TransactionDebugger as Debugger } from '@remix-project/remix-debug' -import { DebuggerUIProps } from './DebuggerAPI' +import { DebuggerUIProps } from './idebugger-api' import { Toaster } from '@remix-ui/toaster' /* eslint-disable-next-line */ import './debugger-ui.css' @@ -25,39 +25,35 @@ export const DebuggerUI = (props: DebuggerUIProps) => { opt: { debugWithGeneratedSources: false }, - toastMessage: '' + toastMessage: '', + currentDebugTransaction: '' }) useEffect(() => { return unLoad() }, []) - useEffect(() => { - if (debuggerModule.debugHash) { - debug(debuggerModule.debugHash) - } - }, [debuggerModule.debugHashRequest]) + debuggerModule.onDebugRequested((hash) => { + if (hash) debug(hash) + }) - useEffect(() => { - if (debuggerModule.removeHighlights) deleteHighlights() - }, [debuggerModule.removeHighlights]) + debuggerModule.onRemoveHighlights(async () => { + await debuggerModule.discardHighlight() + }) useEffect(() => { const setEditor = () => { - const editor = debuggerModule.editor - - editor.event.register('breakpointCleared', (fileName, row) => { + + debuggerModule.onBreakpointCleared((fileName, row) => { if (state.debugger) state.debugger.breakPointManager.remove({fileName: fileName, row: row}) }) - editor.event.register('breakpointAdded', (fileName, row) => { - if (state.debugger) { - state.debugger.breakPointManager.add({fileName: fileName, row: row}) - } + debuggerModule.onBreakpointAdded((fileName, row) => { + if (state.debugger) state.debugger.breakPointManager.add({fileName: fileName, row: row}) }) - editor.event.register('contentChanged', () => { - unLoad() + debuggerModule.onEditorContentChanged(() => { + if (state.debugger) unLoad() }) } @@ -117,10 +113,6 @@ export const DebuggerUI = (props: DebuggerUIProps) => { unLoad() } - const isDebuggerActive = () => { - return state.isActive - } - const unLoad = () => { if (state.debugger) state.debugger.unload() setState(prevState => { @@ -138,13 +130,20 @@ export const DebuggerUI = (props: DebuggerUIProps) => { vmDebugger: false, vmDebuggerHead: false }, - debugging: false + debugging: false, + currentDebugTransaction: '' } }) } const startDebugging = async (blockNumber, txNumber, tx) => { if (state.debugger) unLoad() if (!txNumber) return + setState(prevState => { + return { + ...prevState, + currentDebugTransaction: txNumber + } + }) const web3 = await debuggerModule.getDebugWeb3() const currentReceipt = await web3.eth.getTransactionReceipt(txNumber) const debuggerInstance = new Debugger({ @@ -189,12 +188,6 @@ const debug = (txHash) => { startDebugging(null, txHash, null) } - - -const deleteHighlights = async () => { - await debuggerModule.discardHighlight() -} - const stepManager = { jumpTo: state.debugger && state.debugger.step_manager ? state.debugger.step_manager.jumpTo.bind(state.debugger.step_manager) : null, stepOverBack: state.debugger && state.debugger.step_manager ? state.debugger.step_manager.stepOverBack.bind(state.debugger.step_manager) : null, diff --git a/libs/remix-ui/debugger-ui/src/lib/idebugger-api.ts b/libs/remix-ui/debugger-ui/src/lib/idebugger-api.ts new file mode 100644 index 0000000000..418cd9ba4a --- /dev/null +++ b/libs/remix-ui/debugger-ui/src/lib/idebugger-api.ts @@ -0,0 +1,66 @@ + +import type { CompilationResult, CompilationSource } from '@remix-project/remix-solidity-ts' + +export interface DebuggerUIProps { + debuggerAPI: IDebuggerApi +} + +export interface LineColumnLocation { + start: { + line: number, column: number + }, + end: { + line: number, column: number + } +} + +export interface RawLocation { + start: number, length: number +} + +export interface Sources { + [fileName: string] : {content: string} +} + +export interface CompilationOutput { + source: { sources: Sources, target: string } + data: CompilationResult + getSourceName: (id: number) => string +} + +export interface Asts { + [fileName: string] : CompilationSource // ast +} + +export interface TransactionReceipt { + blockHash: string + blockNumber: number + transactionHash: string + transactionIndex: number + from: string + to: string + contractAddress: string | null + } + +export type onBreakpointClearedListener = (params: string, row: number) => void +export type onBreakpointAddedListener = (params: string, row: number) => void +export type onEditorContentChanged = () => void +export type onDebugRequested = (hash: string) => void + +export interface IDebuggerApi { + offsetToLineColumnConverter: { offsetToLineColumn: (sourceLocation: RawLocation, file: number, contents: Sources, asts: Asts) => Promise } + debugHash: string + debugHashRequest: number + removeHighlights: boolean + onRemoveHighlights: (listener: VoidFunction) => void + onDebugRequested: (listener: onDebugRequested) => void + onBreakpointCleared: (listener: onBreakpointClearedListener) => void + onBreakpointAdded: (listener: onBreakpointAddedListener) => void + onEditorContentChanged: (listener: onEditorContentChanged) => void + discardHighlight: () => Promise + highlight: (lineColumnPos: LineColumnLocation, path: string) => Promise + fetchContractAndCompile: (address: string, currentReceipt: TransactionReceipt) => Promise + getFile: (path: string) => Promise + setFile: (path: string, content: string) => Promise + getDebugWeb3: () => any // returns an instance of web3.js +} \ No newline at end of file diff --git a/nx.json b/nx.json index 4f324dd6cf..2d9caab10b 100644 --- a/nx.json +++ b/nx.json @@ -89,6 +89,9 @@ }, "remix-ui-file-explorer": { "tags": [] + }, + "debugger": { + "tags": [] } } } diff --git a/package-lock.json b/package-lock.json index 3597de461f..78811428ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2930,7 +2930,7 @@ "@evocateur/libnpmaccess": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@evocateur/libnpmaccess/-/libnpmaccess-3.1.2.tgz", - "integrity": "sha1-7Pf2zmsATp+UKwmNkiAL5KSxyEU=", + "integrity": "sha512-KSCAHwNWro0CF2ukxufCitT9K5LjL/KuMmNzSu8wuwN2rjyKHD8+cmOsiybK+W5hdnwc5M1SmRlVCaMHQo+3rg==", "dev": true, "requires": { "@evocateur/npm-registry-fetch": "^4.0.0", @@ -2943,13 +2943,13 @@ "aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha1-UlILiuW1aSFbNU78DKo/4eRaitw=", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", "dev": true }, "npm-package-arg": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha1-AhaMsKSaK3W/mIooaY3ntSnfXLc=", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", "dev": true, "requires": { "hosted-git-info": "^2.7.1", @@ -2961,7 +2961,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -2969,7 +2969,7 @@ "@evocateur/libnpmpublish": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@evocateur/libnpmpublish/-/libnpmpublish-1.2.2.tgz", - "integrity": "sha1-Vd8J0tyhNq+6nIjHWconIZjbnxo=", + "integrity": "sha512-MJrrk9ct1FeY9zRlyeoyMieBjGDG9ihyyD9/Ft6MMrTxql9NyoEx2hw9casTIP4CdqEVu+3nQ2nXxoJ8RCXyFg==", "dev": true, "requires": { "@evocateur/npm-registry-fetch": "^4.0.0", @@ -2986,13 +2986,13 @@ "aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha1-UlILiuW1aSFbNU78DKo/4eRaitw=", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", "dev": true }, "npm-package-arg": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha1-AhaMsKSaK3W/mIooaY3ntSnfXLc=", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", "dev": true, "requires": { "hosted-git-info": "^2.7.1", @@ -3004,7 +3004,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -3012,7 +3012,7 @@ "@evocateur/npm-registry-fetch": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@evocateur/npm-registry-fetch/-/npm-registry-fetch-4.0.0.tgz", - "integrity": "sha1-jEw4dm2NMtMgD8sKg/BktXNl7WY=", + "integrity": "sha512-k1WGfKRQyhJpIr+P17O5vLIo2ko1PFLKwoetatdduUSt/aQ4J2sJrJwwatdI5Z3SiYk/mRH9S3JpdmMFd/IK4g==", "dev": true, "requires": { "JSONStream": "^1.3.4", @@ -3027,7 +3027,7 @@ "agentkeepalive": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", - "integrity": "sha1-oROSTdP6JKC8O3gQjEUMKr7gD2c=", + "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", "dev": true, "requires": { "humanize-ms": "^1.2.1" @@ -3036,13 +3036,13 @@ "http-cache-semantics": { "version": "3.8.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", - "integrity": "sha1-ObDhat2bYFvwqe89nar0hDtMrNI=", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", "dev": true }, "https-proxy-agent": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha1-TuenN6vZJniik9mzShr00NCMeHs=", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, "requires": { "agent-base": "^4.3.0", @@ -3052,7 +3052,7 @@ "make-fetch-happen": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz", - "integrity": "sha1-qoOHEE8mh+3KAchofuRQE9AtGb0=", + "integrity": "sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==", "dev": true, "requires": { "agentkeepalive": "^3.4.1", @@ -3071,7 +3071,7 @@ "npm-package-arg": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha1-AhaMsKSaK3W/mIooaY3ntSnfXLc=", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", "dev": true, "requires": { "hosted-git-info": "^2.7.1", @@ -3083,7 +3083,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -3091,7 +3091,7 @@ "@evocateur/pacote": { "version": "9.6.5", "resolved": "https://registry.npmjs.org/@evocateur/pacote/-/pacote-9.6.5.tgz", - "integrity": "sha1-M94yuiELbxfCDrq01JfvxnVfSuU=", + "integrity": "sha512-EI552lf0aG2nOV8NnZpTxNo2PcXKPmDbF9K8eCBFQdIZwHNGN/mi815fxtmUMa2wTa1yndotICIDt/V0vpEx2w==", "dev": true, "requires": { "@evocateur/npm-registry-fetch": "^4.0.0", @@ -3128,7 +3128,7 @@ "agentkeepalive": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", - "integrity": "sha1-oROSTdP6JKC8O3gQjEUMKr7gD2c=", + "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", "dev": true, "requires": { "humanize-ms": "^1.2.1" @@ -3137,13 +3137,13 @@ "http-cache-semantics": { "version": "3.8.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", - "integrity": "sha1-ObDhat2bYFvwqe89nar0hDtMrNI=", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", "dev": true }, "https-proxy-agent": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha1-TuenN6vZJniik9mzShr00NCMeHs=", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, "requires": { "agent-base": "^4.3.0", @@ -3153,7 +3153,7 @@ "make-fetch-happen": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz", - "integrity": "sha1-qoOHEE8mh+3KAchofuRQE9AtGb0=", + "integrity": "sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==", "dev": true, "requires": { "agentkeepalive": "^3.4.1", @@ -3172,7 +3172,7 @@ "minipass": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha1-5xN2Ln0+Mv7YAxFc+T4EvKn8yaY=", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", "dev": true, "requires": { "safe-buffer": "^5.1.2", @@ -3182,7 +3182,7 @@ "npm-package-arg": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha1-AhaMsKSaK3W/mIooaY3ntSnfXLc=", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", "dev": true, "requires": { "hosted-git-info": "^2.7.1", @@ -3194,7 +3194,7 @@ "npm-packlist": { "version": "1.4.8", "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", - "integrity": "sha1-Vu5swTW5+YrT1Rwcldoiu7my7z4=", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", "dev": true, "requires": { "ignore-walk": "^3.0.1", @@ -3205,7 +3205,7 @@ "npm-pick-manifest": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz", - "integrity": "sha1-9Nnl/UviFT5fTl+be+jcQZqZq7c=", + "integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==", "dev": true, "requires": { "figgy-pudding": "^3.5.1", @@ -3216,7 +3216,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -3900,7 +3900,7 @@ "@lerna/add": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/@lerna/add/-/add-3.21.0.tgz", - "integrity": "sha1-JwB73nHMewopaas8LwrkFXi0V3s=", + "integrity": "sha512-vhUXXF6SpufBE1EkNEXwz1VLW03f177G9uMOFMQkp6OJ30/PWg4Ekifuz9/3YfgB2/GH8Tu4Lk3O51P2Hskg/A==", "dev": true, "requires": { "@evocateur/pacote": "^9.6.3", @@ -3918,7 +3918,7 @@ "npm-package-arg": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha1-AhaMsKSaK3W/mIooaY3ntSnfXLc=", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", "dev": true, "requires": { "hosted-git-info": "^2.7.1", @@ -3930,7 +3930,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -3940,7 +3940,7 @@ "@lerna/bootstrap": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/@lerna/bootstrap/-/bootstrap-3.21.0.tgz", - "integrity": "sha1-vNG2Ub5bCXCyDY+uBMhkVIEjrtY=", + "integrity": "sha512-mtNHlXpmvJn6JTu0KcuTTPl2jLsDNud0QacV/h++qsaKbhAaJr/FElNZ5s7MwZFUM3XaDmvWzHKaszeBMHIbBw==", "dev": true, "requires": { "@lerna/command": "3.21.0", @@ -3971,7 +3971,7 @@ "npm-package-arg": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha1-AhaMsKSaK3W/mIooaY3ntSnfXLc=", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", "dev": true, "requires": { "hosted-git-info": "^2.7.1", @@ -3983,7 +3983,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -3993,7 +3993,7 @@ "@lerna/changed": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/@lerna/changed/-/changed-3.21.0.tgz", - "integrity": "sha1-EI4V9nm/4HevUA9YJIxjTxBE6gs=", + "integrity": "sha512-hzqoyf8MSHVjZp0gfJ7G8jaz+++mgXYiNs9iViQGA8JlN/dnWLI5sWDptEH3/B30Izo+fdVz0S0s7ydVE3pWIw==", "dev": true, "requires": { "@lerna/collect-updates": "3.20.0", @@ -4005,7 +4005,7 @@ "@lerna/check-working-tree": { "version": "3.16.5", "resolved": "https://registry.npmjs.org/@lerna/check-working-tree/-/check-working-tree-3.16.5.tgz", - "integrity": "sha1-tPiuYbtFI1Yd+5+PjYdN1Gu0S6o=", + "integrity": "sha512-xWjVBcuhvB8+UmCSb5tKVLB5OuzSpw96WEhS2uz6hkWVa/Euh1A0/HJwn2cemyK47wUrCQXtczBUiqnq9yX5VQ==", "dev": true, "requires": { "@lerna/collect-uncommitted": "3.16.5", @@ -4016,7 +4016,7 @@ "@lerna/child-process": { "version": "3.16.5", "resolved": "https://registry.npmjs.org/@lerna/child-process/-/child-process-3.16.5.tgz", - "integrity": "sha1-OPo8GAZKpKwHVK2AEUd2p7NqabI=", + "integrity": "sha512-vdcI7mzei9ERRV4oO8Y1LHBZ3A5+ampRKg1wq5nutLsUA4mEBN6H7JqjWOMY9xZemv6+kATm2ofjJ3lW5TszQg==", "dev": true, "requires": { "chalk": "^2.3.1", @@ -4027,7 +4027,7 @@ "@lerna/clean": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/@lerna/clean/-/clean-3.21.0.tgz", - "integrity": "sha1-wLRrUwDMPa4s2jvsFLgDCC2jhW0=", + "integrity": "sha512-b/L9l+MDgE/7oGbrav6rG8RTQvRiZLO1zTcG17zgJAAuhlsPxJExMlh2DFwJEVi2les70vMhHfST3Ue1IMMjpg==", "dev": true, "requires": { "@lerna/command": "3.21.0", @@ -4043,7 +4043,7 @@ "@lerna/cli": { "version": "3.18.5", "resolved": "https://registry.npmjs.org/@lerna/cli/-/cli-3.18.5.tgz", - "integrity": "sha1-yQxGFUL801ttWwFaKQ+w2/tB0kI=", + "integrity": "sha512-erkbxkj9jfc89vVs/jBLY/fM0I80oLmJkFUV3Q3wk9J3miYhP14zgVEBsPZY68IZlEjT6T3Xlq2xO1AVaatHsA==", "dev": true, "requires": { "@lerna/global-options": "3.13.0", @@ -4055,13 +4055,13 @@ "ansi-regex": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, "cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha1-3u/P2y6AB4SqNPRvoI4GhRx7u8U=", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "dev": true, "requires": { "string-width": "^3.1.0", @@ -4072,7 +4072,7 @@ "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha1-SRafHXmTQwZG2mHsxa41XCHJe3M=", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { "locate-path": "^3.0.0" @@ -4081,13 +4081,13 @@ "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha1-T5RBKoLbMvNuOwuXQfipf+sDH34=", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, "locate-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha1-2+w7OrdZdYBxtY/ln8QYca8hQA4=", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { "p-locate": "^3.0.0", @@ -4097,7 +4097,7 @@ "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha1-PdM8ZHohT9//2DWTPrCG2g3CHbE=", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -4106,7 +4106,7 @@ "p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha1-Mi1poFwCZLJZl9n0DNiokasAZKQ=", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { "p-limit": "^2.0.0" @@ -4115,19 +4115,19 @@ "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha1-yyhoVA4xPWHeWPr741zpAE1VQOY=", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha1-0LMp7MfMD2Fkn2IhW+aa9UqomJs=", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha1-InZ74htirxCBV0MG9prFG2IgOWE=", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { "emoji-regex": "^7.0.1", @@ -4138,7 +4138,7 @@ "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha1-jJpTb+tq/JYr36WxBKUJHBrZwK4=", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { "ansi-regex": "^4.1.0" @@ -4147,7 +4147,7 @@ "wrap-ansi": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha1-H9H2cjXVttD+54EFYAG/tpTAOwk=", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "dev": true, "requires": { "ansi-styles": "^3.2.0", @@ -4158,7 +4158,7 @@ "yargs": { "version": "14.2.3", "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz", - "integrity": "sha1-Ghw+3O0a+yov6jNgS8bR2NaIpBQ=", + "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==", "dev": true, "requires": { "cliui": "^5.0.0", @@ -4177,7 +4177,7 @@ "yargs-parser": { "version": "15.0.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.1.tgz", - "integrity": "sha1-VHhq9AuCDcsvuAJbEbTWWddjI7M=", + "integrity": "sha512-0OAMV2mAZQrs3FkNpDQcBk1x5HXb8X4twADss4S0Iuk+2dGnLOE/fRHrsYm542GduMveyA77OF4wrNJuanRCWw==", "dev": true, "requires": { "camelcase": "^5.0.0", @@ -4189,7 +4189,7 @@ "@lerna/collect-uncommitted": { "version": "3.16.5", "resolved": "https://registry.npmjs.org/@lerna/collect-uncommitted/-/collect-uncommitted-3.16.5.tgz", - "integrity": "sha1-pJTWGqwxzceuxLvlLJZVAnQTLmM=", + "integrity": "sha512-ZgqnGwpDZiWyzIQVZtQaj9tRizsL4dUOhuOStWgTAw1EMe47cvAY2kL709DzxFhjr6JpJSjXV5rZEAeU3VE0Hg==", "dev": true, "requires": { "@lerna/child-process": "3.16.5", @@ -4201,7 +4201,7 @@ "@lerna/collect-updates": { "version": "3.20.0", "resolved": "https://registry.npmjs.org/@lerna/collect-updates/-/collect-updates-3.20.0.tgz", - "integrity": "sha1-YvnXa6IaJbfZ+/McAt6IdEpWS9E=", + "integrity": "sha512-qBTVT5g4fupVhBFuY4nI/3FSJtQVcDh7/gEPOpRxoXB/yCSnT38MFHXWl+y4einLciCjt/+0x6/4AG80fjay2Q==", "dev": true, "requires": { "@lerna/child-process": "3.16.5", @@ -4214,7 +4214,7 @@ "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha1-3lUoUaF1nfOo8gZTVEL17E3eq0Q=", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true } } @@ -4222,7 +4222,7 @@ "@lerna/command": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/@lerna/command/-/command-3.21.0.tgz", - "integrity": "sha1-miODdZ3HtwDaz6iiKy86bhkBIfc=", + "integrity": "sha512-T2bu6R8R3KkH5YoCKdutKv123iUgUbW8efVjdGCDnCMthAQzoentOJfDeodBwn0P2OqCl3ohsiNVtSn9h78fyQ==", "dev": true, "requires": { "@lerna/child-process": "3.16.5", @@ -4240,7 +4240,7 @@ "@lerna/conventional-commits": { "version": "3.22.0", "resolved": "https://registry.npmjs.org/@lerna/conventional-commits/-/conventional-commits-3.22.0.tgz", - "integrity": "sha1-J5j0iB7i70V72uAnq30L8K9vHgk=", + "integrity": "sha512-z4ZZk1e8Mhz7+IS8NxHr64wyklHctCJyWpJKEZZPJiLFJ8yKto/x38O80R10pIzC0rr8Sy/OsjSH4bl0TbbgqA==", "dev": true, "requires": { "@lerna/validation-error": "3.13.0", @@ -4270,7 +4270,7 @@ "npm-package-arg": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha1-AhaMsKSaK3W/mIooaY3ntSnfXLc=", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", "dev": true, "requires": { "hosted-git-info": "^2.7.1", @@ -4282,7 +4282,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -4290,7 +4290,7 @@ "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true } } @@ -4298,7 +4298,7 @@ "@lerna/create": { "version": "3.22.0", "resolved": "https://registry.npmjs.org/@lerna/create/-/create-3.22.0.tgz", - "integrity": "sha1-1rvQN8PcW0Jf5fbRuBcFfCePdhk=", + "integrity": "sha512-MdiQQzCcB4E9fBF1TyMOaAEz9lUjIHp1Ju9H7f3lXze5JK6Fl5NYkouAvsLgY6YSIhXMY8AHW2zzXeBDY4yWkw==", "dev": true, "requires": { "@evocateur/pacote": "^9.6.3", @@ -4324,13 +4324,13 @@ "@nodelib/fs.stat": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", - "integrity": "sha1-K1o6s/kYzKSKjHVMCBaOPwPrphs=", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", "dev": true }, "fast-glob": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", - "integrity": "sha1-aVOFfDr6R1//ku5gFdUtpwpM050=", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", "dev": true, "requires": { "@mrmlnc/readdir-enhanced": "^2.2.1", @@ -4376,7 +4376,7 @@ "globby": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", - "integrity": "sha1-/QKacGxwPSm90XD0tts6P3p8tj0=", + "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", "dev": true, "requires": { "@types/glob": "^7.1.1", @@ -4392,13 +4392,13 @@ "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw=", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, "npm-package-arg": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha1-AhaMsKSaK3W/mIooaY3ntSnfXLc=", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", "dev": true, "requires": { "hosted-git-info": "^2.7.1", @@ -4410,7 +4410,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -4418,13 +4418,13 @@ "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha1-3lUoUaF1nfOo8gZTVEL17E3eq0Q=", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true } } @@ -4432,7 +4432,7 @@ "@lerna/create-symlink": { "version": "3.16.2", "resolved": "https://registry.npmjs.org/@lerna/create-symlink/-/create-symlink-3.16.2.tgz", - "integrity": "sha1-QSy45Zpy9afZRj5ORyGtIHAUmWc=", + "integrity": "sha512-pzXIJp6av15P325sgiIRpsPXLFmkisLhMBCy4764d+7yjf2bzrJ4gkWVMhsv4AdF0NN3OyZ5jjzzTtLNqfR+Jw==", "dev": true, "requires": { "@zkochan/cmd-shim": "^3.1.0", @@ -4456,7 +4456,7 @@ "@lerna/describe-ref": { "version": "3.16.5", "resolved": "https://registry.npmjs.org/@lerna/describe-ref/-/describe-ref-3.16.5.tgz", - "integrity": "sha1-ozjCWq7YN9PccLinLER8XGY0asA=", + "integrity": "sha512-c01+4gUF0saOOtDBzbLMFOTJDHTKbDFNErEY6q6i9QaXuzy9LNN62z+Hw4acAAZuJQhrVWncVathcmkkjvSVGw==", "dev": true, "requires": { "@lerna/child-process": "3.16.5", @@ -4466,7 +4466,7 @@ "@lerna/diff": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/@lerna/diff/-/diff-3.21.0.tgz", - "integrity": "sha1-5t8Ni5kWFn/1pJ/LAqwGQkKApo0=", + "integrity": "sha512-5viTR33QV3S7O+bjruo1SaR40m7F2aUHJaDAC7fL9Ca6xji+aw1KFkpCtVlISS0G8vikUREGMJh+c/VMSc8Usw==", "dev": true, "requires": { "@lerna/child-process": "3.16.5", @@ -4478,7 +4478,7 @@ "@lerna/exec": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/@lerna/exec/-/exec-3.21.0.tgz", - "integrity": "sha1-F/B1M4k8uRihe0G8xWbcQ3AW2yY=", + "integrity": "sha512-iLvDBrIE6rpdd4GIKTY9mkXyhwsJ2RvQdB9ZU+/NhR3okXfqKc6py/24tV111jqpXTtZUW6HNydT4dMao2hi1Q==", "dev": true, "requires": { "@lerna/child-process": "3.16.5", @@ -4493,7 +4493,7 @@ "@lerna/filter-options": { "version": "3.20.0", "resolved": "https://registry.npmjs.org/@lerna/filter-options/-/filter-options-3.20.0.tgz", - "integrity": "sha1-Dw9dWkeDhW7s5CBHCMyQLLyK9Zs=", + "integrity": "sha512-bmcHtvxn7SIl/R9gpiNMVG7yjx7WyT0HSGw34YVZ9B+3xF/83N3r5Rgtjh4hheLZ+Q91Or0Jyu5O3Nr+AwZe2g==", "dev": true, "requires": { "@lerna/collect-updates": "3.20.0", @@ -4506,7 +4506,7 @@ "@lerna/filter-packages": { "version": "3.18.0", "resolved": "https://registry.npmjs.org/@lerna/filter-packages/-/filter-packages-3.18.0.tgz", - "integrity": "sha1-ano3bShSCNsDqClYz7gXLhebTnA=", + "integrity": "sha512-6/0pMM04bCHNATIOkouuYmPg6KH3VkPCIgTfQmdkPJTullERyEQfNUKikrefjxo1vHOoCACDpy65JYyKiAbdwQ==", "dev": true, "requires": { "@lerna/validation-error": "3.13.0", @@ -4517,7 +4517,7 @@ "@lerna/get-npm-exec-opts": { "version": "3.13.0", "resolved": "https://registry.npmjs.org/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-3.13.0.tgz", - "integrity": "sha1-0bVSywCIGZ/D5+Em+RTjmgjfnqU=", + "integrity": "sha512-Y0xWL0rg3boVyJk6An/vurKzubyJKtrxYv2sj4bB8Mc5zZ3tqtv0ccbOkmkXKqbzvNNF7VeUt1OJ3DRgtC/QZw==", "dev": true, "requires": { "npmlog": "^4.1.2" @@ -4526,7 +4526,7 @@ "@lerna/get-packed": { "version": "3.16.0", "resolved": "https://registry.npmjs.org/@lerna/get-packed/-/get-packed-3.16.0.tgz", - "integrity": "sha1-GzFrcG3O6Gx7qlXlCwh5WUR4Uv8=", + "integrity": "sha512-AjsFiaJzo1GCPnJUJZiTW6J1EihrPkc2y3nMu6m3uWFxoleklsSCyImumzVZJssxMi3CPpztj8LmADLedl9kXw==", "dev": true, "requires": { "fs-extra": "^8.1.0", @@ -4550,7 +4550,7 @@ "@lerna/github-client": { "version": "3.22.0", "resolved": "https://registry.npmjs.org/@lerna/github-client/-/github-client-3.22.0.tgz", - "integrity": "sha1-XYFqpPdnR+1zauZP+WK48Vw1TZU=", + "integrity": "sha512-O/GwPW+Gzr3Eb5bk+nTzTJ3uv+jh5jGho9BOqKlajXaOkMYGBELEAqV5+uARNGWZFvYAiF4PgqHb6aCUu7XdXg==", "dev": true, "requires": { "@lerna/child-process": "3.16.5", @@ -4563,7 +4563,7 @@ "@lerna/gitlab-client": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/@lerna/gitlab-client/-/gitlab-client-3.15.0.tgz", - "integrity": "sha1-kfTsjGl7WsV/fyW9UP5lnSSqlqY=", + "integrity": "sha512-OsBvRSejHXUBMgwWQqNoioB8sgzL/Pf1pOUhHKtkiMl6aAWjklaaq5HPMvTIsZPfS6DJ9L5OK2GGZuooP/5c8Q==", "dev": true, "requires": { "node-fetch": "^2.5.0", @@ -4574,13 +4574,13 @@ "@lerna/global-options": { "version": "3.13.0", "resolved": "https://registry.npmjs.org/@lerna/global-options/-/global-options-3.13.0.tgz", - "integrity": "sha1-IXZiKQ2watnPLEnY4xAO4o6uuuE=", + "integrity": "sha512-SlZvh1gVRRzYLVluz9fryY1nJpZ0FHDGB66U9tFfvnnxmueckRQxLopn3tXj3NU1kc3QANT2I5BsQkOqZ4TEFQ==", "dev": true }, "@lerna/has-npm-version": { "version": "3.16.5", "resolved": "https://registry.npmjs.org/@lerna/has-npm-version/-/has-npm-version-3.16.5.tgz", - "integrity": "sha1-q4OVbyEdiSPqav6bl5s4zHOxUyY=", + "integrity": "sha512-WL7LycR9bkftyqbYop5rEGJ9sRFIV55tSGmbN1HLrF9idwOCD7CLrT64t235t3t4O5gehDnwKI5h2U3oxTrF8Q==", "dev": true, "requires": { "@lerna/child-process": "3.16.5", @@ -4590,7 +4590,7 @@ "@lerna/import": { "version": "3.22.0", "resolved": "https://registry.npmjs.org/@lerna/import/-/import-3.22.0.tgz", - "integrity": "sha1-Gl8DlPOOI8T2QqEj5eFRfnDQaNI=", + "integrity": "sha512-uWOlexasM5XR6tXi4YehODtH9Y3OZrFht3mGUFFT3OIl2s+V85xIGFfqFGMTipMPAGb2oF1UBLL48kR43hRsOg==", "dev": true, "requires": { "@lerna/child-process": "3.16.5", @@ -4619,7 +4619,7 @@ "@lerna/info": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/@lerna/info/-/info-3.21.0.tgz", - "integrity": "sha1-dmlrZ2/bDzXUjIPGPB4yu143gU8=", + "integrity": "sha512-0XDqGYVBgWxUquFaIptW2bYSIu6jOs1BtkvRTWDDhw4zyEdp6q4eaMvqdSap1CG+7wM5jeLCi6z94wS0AuiuwA==", "dev": true, "requires": { "@lerna/command": "3.21.0", @@ -4630,7 +4630,7 @@ "@lerna/init": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/@lerna/init/-/init-3.21.0.tgz", - "integrity": "sha1-HoEJNNyL9OU4bAMQQYgdO0CWqlw=", + "integrity": "sha512-6CM0z+EFUkFfurwdJCR+LQQF6MqHbYDCBPyhu/d086LRf58GtYZYj49J8mKG9ktayp/TOIxL/pKKjgLD8QBPOg==", "dev": true, "requires": { "@lerna/child-process": "3.16.5", @@ -4656,7 +4656,7 @@ "@lerna/link": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/@lerna/link/-/link-3.21.0.tgz", - "integrity": "sha1-i+aP8MzuEEsXS1u9YGMCwvBunZs=", + "integrity": "sha512-tGu9GxrX7Ivs+Wl3w1+jrLi1nQ36kNI32dcOssij6bg0oZ2M2MDEFI9UF2gmoypTaN9uO5TSsjCFS7aR79HbdQ==", "dev": true, "requires": { "@lerna/command": "3.21.0", @@ -4669,7 +4669,7 @@ "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha1-3lUoUaF1nfOo8gZTVEL17E3eq0Q=", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true } } @@ -4677,7 +4677,7 @@ "@lerna/list": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/@lerna/list/-/list-3.21.0.tgz", - "integrity": "sha1-Qvdvr6Vt6hO2keyMqxODJpHWHaI=", + "integrity": "sha512-KehRjE83B1VaAbRRkRy6jLX1Cin8ltsrQ7FHf2bhwhRHK0S54YuA6LOoBnY/NtA8bHDX/Z+G5sMY78X30NS9tg==", "dev": true, "requires": { "@lerna/command": "3.21.0", @@ -4689,7 +4689,7 @@ "@lerna/listable": { "version": "3.18.5", "resolved": "https://registry.npmjs.org/@lerna/listable/-/listable-3.18.5.tgz", - "integrity": "sha1-6CeYQFte2PxRhDyO8eeg5Jc4iho=", + "integrity": "sha512-Sdr3pVyaEv5A7ZkGGYR7zN+tTl2iDcinryBPvtuv20VJrXBE8wYcOks1edBTcOWsPjCE/rMP4bo1pseyk3UTsg==", "dev": true, "requires": { "@lerna/query-graph": "3.18.5", @@ -4700,7 +4700,7 @@ "@lerna/log-packed": { "version": "3.16.0", "resolved": "https://registry.npmjs.org/@lerna/log-packed/-/log-packed-3.16.0.tgz", - "integrity": "sha1-+DmRBB7neySVY04URwtCJZ/SvBY=", + "integrity": "sha512-Fp+McSNBV/P2mnLUYTaSlG8GSmpXM7krKWcllqElGxvAqv6chk2K3c2k80MeVB4WvJ9tRjUUf+i7HUTiQ9/ckQ==", "dev": true, "requires": { "byte-size": "^5.0.1", @@ -4712,7 +4712,7 @@ "@lerna/npm-conf": { "version": "3.16.0", "resolved": "https://registry.npmjs.org/@lerna/npm-conf/-/npm-conf-3.16.0.tgz", - "integrity": "sha1-HBComuL2wu6WliVXc4aFMA03aCc=", + "integrity": "sha512-HbO3DUrTkCAn2iQ9+FF/eisDpWY5POQAOF1m7q//CZjdC2HSW3UYbKEGsSisFxSfaF9Z4jtrV+F/wX6qWs3CuA==", "dev": true, "requires": { "config-chain": "^1.1.11", @@ -4722,7 +4722,7 @@ "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true } } @@ -4730,7 +4730,7 @@ "@lerna/npm-dist-tag": { "version": "3.18.5", "resolved": "https://registry.npmjs.org/@lerna/npm-dist-tag/-/npm-dist-tag-3.18.5.tgz", - "integrity": "sha1-nvmrt8EEB3sx9vqyLMc7MU1UrFU=", + "integrity": "sha512-xw0HDoIG6HreVsJND9/dGls1c+lf6vhu7yJoo56Sz5bvncTloYGLUppIfDHQr4ZvmPCK8rsh0euCVh2giPxzKQ==", "dev": true, "requires": { "@evocateur/npm-registry-fetch": "^4.0.0", @@ -4743,7 +4743,7 @@ "npm-package-arg": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha1-AhaMsKSaK3W/mIooaY3ntSnfXLc=", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", "dev": true, "requires": { "hosted-git-info": "^2.7.1", @@ -4755,7 +4755,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -4763,7 +4763,7 @@ "@lerna/npm-install": { "version": "3.16.5", "resolved": "https://registry.npmjs.org/@lerna/npm-install/-/npm-install-3.16.5.tgz", - "integrity": "sha1-1r/cFvgShdpmUVrkeSTW4njWN9M=", + "integrity": "sha512-hfiKk8Eku6rB9uApqsalHHTHY+mOrrHeWEs+gtg7+meQZMTS3kzv4oVp5cBZigndQr3knTLjwthT/FX4KvseFg==", "dev": true, "requires": { "@lerna/child-process": "3.16.5", @@ -4789,7 +4789,7 @@ "npm-package-arg": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha1-AhaMsKSaK3W/mIooaY3ntSnfXLc=", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", "dev": true, "requires": { "hosted-git-info": "^2.7.1", @@ -4801,7 +4801,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -4809,7 +4809,7 @@ "@lerna/npm-publish": { "version": "3.18.5", "resolved": "https://registry.npmjs.org/@lerna/npm-publish/-/npm-publish-3.18.5.tgz", - "integrity": "sha1-JA5AOZWf2YFrScWwdCHhG1ywAK8=", + "integrity": "sha512-3etLT9+2L8JAx5F8uf7qp6iAtOLSMj+ZYWY6oUgozPi/uLqU0/gsMsEXh3F0+YVW33q0M61RpduBoAlOOZnaTg==", "dev": true, "requires": { "@evocateur/libnpmpublish": "^1.2.2", @@ -4837,7 +4837,7 @@ "npm-package-arg": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha1-AhaMsKSaK3W/mIooaY3ntSnfXLc=", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", "dev": true, "requires": { "hosted-git-info": "^2.7.1", @@ -4849,13 +4849,13 @@ "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -4863,7 +4863,7 @@ "@lerna/npm-run-script": { "version": "3.16.5", "resolved": "https://registry.npmjs.org/@lerna/npm-run-script/-/npm-run-script-3.16.5.tgz", - "integrity": "sha1-nC7IJFOibAtG7cC7fBWBbIIfXBU=", + "integrity": "sha512-1asRi+LjmVn3pMjEdpqKJZFT/3ZNpb+VVeJMwrJaV/3DivdNg7XlPK9LTrORuKU4PSvhdEZvJmSlxCKyDpiXsQ==", "dev": true, "requires": { "@lerna/child-process": "3.16.5", @@ -4874,7 +4874,7 @@ "@lerna/otplease": { "version": "3.18.5", "resolved": "https://registry.npmjs.org/@lerna/otplease/-/otplease-3.18.5.tgz", - "integrity": "sha1-t3uOdgtAq62fdljZiPPqd9T9AjE=", + "integrity": "sha512-S+SldXAbcXTEDhzdxYLU0ZBKuYyURP/ND2/dK6IpKgLxQYh/z4ScljPDMyKymmEvgiEJmBsPZAAPfmNPEzxjog==", "dev": true, "requires": { "@lerna/prompt": "3.18.5", @@ -4884,7 +4884,7 @@ "@lerna/output": { "version": "3.13.0", "resolved": "https://registry.npmjs.org/@lerna/output/-/output-3.13.0.tgz", - "integrity": "sha1-Pe18yQiyephyIopjDZUK7a56SYk=", + "integrity": "sha512-7ZnQ9nvUDu/WD+bNsypmPG5MwZBwu86iRoiW6C1WBuXXDxM5cnIAC1m2WxHeFnjyMrYlRXM9PzOQ9VDD+C15Rg==", "dev": true, "requires": { "npmlog": "^4.1.2" @@ -4893,7 +4893,7 @@ "@lerna/pack-directory": { "version": "3.16.4", "resolved": "https://registry.npmjs.org/@lerna/pack-directory/-/pack-directory-3.16.4.tgz", - "integrity": "sha1-Pq5fkb31rP4DhFEO1T+t3EwHRpM=", + "integrity": "sha512-uxSF0HZeGyKaaVHz5FroDY9A5NDDiCibrbYR6+khmrhZtY0Bgn6hWq8Gswl9iIlymA+VzCbshWIMX4o2O8C8ng==", "dev": true, "requires": { "@lerna/get-packed": "3.16.0", @@ -4909,7 +4909,7 @@ "npm-packlist": { "version": "1.4.8", "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", - "integrity": "sha1-Vu5swTW5+YrT1Rwcldoiu7my7z4=", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", "dev": true, "requires": { "ignore-walk": "^3.0.1", @@ -4922,7 +4922,7 @@ "@lerna/package": { "version": "3.16.0", "resolved": "https://registry.npmjs.org/@lerna/package/-/package-3.16.0.tgz", - "integrity": "sha1-fgpG5Gl+2LipwU1Zx/iQ4NOLoTw=", + "integrity": "sha512-2lHBWpaxcBoiNVbtyLtPUuTYEaB/Z+eEqRS9duxpZs6D+mTTZMNy6/5vpEVSCBmzvdYpyqhqaYjjSLvjjr5Riw==", "dev": true, "requires": { "load-json-file": "^5.3.0", @@ -4933,7 +4933,7 @@ "load-json-file": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", - "integrity": "sha1-TTweAfocA+p4pgrHr5MsnOU0A/M=", + "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", "dev": true, "requires": { "graceful-fs": "^4.1.15", @@ -4946,7 +4946,7 @@ "npm-package-arg": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha1-AhaMsKSaK3W/mIooaY3ntSnfXLc=", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", "dev": true, "requires": { "hosted-git-info": "^2.7.1", @@ -4958,19 +4958,19 @@ "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, "type-fest": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", - "integrity": "sha1-Y9ANIE4FlHT+Xht8ARESu9HcKeE=", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", "dev": true } } @@ -4978,7 +4978,7 @@ "@lerna/package-graph": { "version": "3.18.5", "resolved": "https://registry.npmjs.org/@lerna/package-graph/-/package-graph-3.18.5.tgz", - "integrity": "sha1-x0Di6jV40FnlUWM+lQaQgxuUH2s=", + "integrity": "sha512-8QDrR9T+dBegjeLr+n9WZTVxUYUhIUjUgZ0gvNxUBN8S1WB9r6H5Yk56/MVaB64tA3oGAN9IIxX6w0WvTfFudA==", "dev": true, "requires": { "@lerna/prerelease-id-from-version": "3.16.0", @@ -4991,7 +4991,7 @@ "npm-package-arg": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha1-AhaMsKSaK3W/mIooaY3ntSnfXLc=", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", "dev": true, "requires": { "hosted-git-info": "^2.7.1", @@ -5003,7 +5003,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -5013,7 +5013,7 @@ "@lerna/prerelease-id-from-version": { "version": "3.16.0", "resolved": "https://registry.npmjs.org/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-3.16.0.tgz", - "integrity": "sha1-skv6eJ9eG6q5FNewi6rpt719g6E=", + "integrity": "sha512-qZyeUyrE59uOK8rKdGn7jQz+9uOpAaF/3hbslJVFL1NqF9ELDTqjCPXivuejMX/lN4OgD6BugTO4cR7UTq/sZA==", "dev": true, "requires": { "semver": "^6.2.0" @@ -5022,7 +5022,7 @@ "@lerna/profiler": { "version": "3.20.0", "resolved": "https://registry.npmjs.org/@lerna/profiler/-/profiler-3.20.0.tgz", - "integrity": "sha1-D23CNvTqj56l81jGcDMFpPMq0FE=", + "integrity": "sha512-bh8hKxAlm6yu8WEOvbLENm42i2v9SsR4WbrCWSbsmOElx3foRnMlYk7NkGECa+U5c3K4C6GeBbwgqs54PP7Ljg==", "dev": true, "requires": { "figgy-pudding": "^3.5.1", @@ -5047,7 +5047,7 @@ "@lerna/project": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/@lerna/project/-/project-3.21.0.tgz", - "integrity": "sha1-XXhNLRDFYaAPIDILzbBAmXwQUC0=", + "integrity": "sha512-xT1mrpET2BF11CY32uypV2GPtPVm6Hgtha7D81GQP9iAitk9EccrdNjYGt5UBYASl4CIDXBRxwmTTVGfrCx82A==", "dev": true, "requires": { "@lerna/package": "3.16.0", @@ -5067,13 +5067,13 @@ "@nodelib/fs.stat": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz", - "integrity": "sha1-K1o6s/kYzKSKjHVMCBaOPwPrphs=", + "integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==", "dev": true }, "cosmiconfig": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha1-BA9yaAnFked6F8CjYmykW08Wixo=", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", "dev": true, "requires": { "import-fresh": "^2.0.0", @@ -5085,7 +5085,7 @@ "dot-prop": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha1-HxngwuGqDjJ5fEl5nyg3rGr2nFc=", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", "dev": true, "requires": { "is-obj": "^1.0.0" @@ -5094,7 +5094,7 @@ "fast-glob": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz", - "integrity": "sha1-aVOFfDr6R1//ku5gFdUtpwpM050=", + "integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==", "dev": true, "requires": { "@mrmlnc/readdir-enhanced": "^2.2.1", @@ -5131,7 +5131,7 @@ "globby": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz", - "integrity": "sha1-/QKacGxwPSm90XD0tts6P3p8tj0=", + "integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==", "dev": true, "requires": { "@types/glob": "^7.1.1", @@ -5147,7 +5147,7 @@ "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw=", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, "import-fresh": { @@ -5177,7 +5177,7 @@ "load-json-file": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", - "integrity": "sha1-TTweAfocA+p4pgrHr5MsnOU0A/M=", + "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", "dev": true, "requires": { "graceful-fs": "^4.1.15", @@ -5190,25 +5190,25 @@ "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true }, "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY=", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha1-3lUoUaF1nfOo8gZTVEL17E3eq0Q=", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true }, "type-fest": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", - "integrity": "sha1-Y9ANIE4FlHT+Xht8ARESu9HcKeE=", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", "dev": true } } @@ -5216,7 +5216,7 @@ "@lerna/prompt": { "version": "3.18.5", "resolved": "https://registry.npmjs.org/@lerna/prompt/-/prompt-3.18.5.tgz", - "integrity": "sha1-YozVRfIliH0GBJGrld+JnPxSGKE=", + "integrity": "sha512-rkKj4nm1twSbBEb69+Em/2jAERK8htUuV8/xSjN0NPC+6UjzAwY52/x9n5cfmpa9lyKf/uItp7chCI7eDmNTKQ==", "dev": true, "requires": { "inquirer": "^6.2.0", @@ -5226,7 +5226,7 @@ "@lerna/publish": { "version": "3.22.1", "resolved": "https://registry.npmjs.org/@lerna/publish/-/publish-3.22.1.tgz", - "integrity": "sha1-tPfOP7oemvsovkofPYgiImm6lRk=", + "integrity": "sha512-PG9CM9HUYDreb1FbJwFg90TCBQooGjj+n/pb3gw/eH5mEDq0p8wKdLFe0qkiqUkm/Ub5C8DbVFertIo0Vd0zcw==", "dev": true, "requires": { "@evocateur/libnpmaccess": "^3.1.2", @@ -5275,7 +5275,7 @@ "npm-package-arg": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha1-AhaMsKSaK3W/mIooaY3ntSnfXLc=", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", "dev": true, "requires": { "hosted-git-info": "^2.7.1", @@ -5287,7 +5287,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -5297,7 +5297,7 @@ "@lerna/pulse-till-done": { "version": "3.13.0", "resolved": "https://registry.npmjs.org/@lerna/pulse-till-done/-/pulse-till-done-3.13.0.tgz", - "integrity": "sha1-yOnOW6+vENkwpn1+0My12Vj+ARA=", + "integrity": "sha512-1SOHpy7ZNTPulzIbargrgaJX387csN7cF1cLOGZiJQA6VqnS5eWs2CIrG8i8wmaUavj2QlQ5oEbRMVVXSsGrzA==", "dev": true, "requires": { "npmlog": "^4.1.2" @@ -5306,7 +5306,7 @@ "@lerna/query-graph": { "version": "3.18.5", "resolved": "https://registry.npmjs.org/@lerna/query-graph/-/query-graph-3.18.5.tgz", - "integrity": "sha1-30gwu1FVJzADvzXo3aHDLQknvYY=", + "integrity": "sha512-50Lf4uuMpMWvJ306be3oQDHrWV42nai9gbIVByPBYJuVW8dT8O8pA3EzitNYBUdLL9/qEVbrR0ry1HD7EXwtRA==", "dev": true, "requires": { "@lerna/package-graph": "3.18.5", @@ -5316,7 +5316,7 @@ "@lerna/resolve-symlink": { "version": "3.16.0", "resolved": "https://registry.npmjs.org/@lerna/resolve-symlink/-/resolve-symlink-3.16.0.tgz", - "integrity": "sha1-N/xwlfq9vPMXwm63Tg0L3o79I4Y=", + "integrity": "sha512-Ibj5e7njVHNJ/NOqT4HlEgPFPtPLWsO7iu59AM5bJDcAJcR96mLZ7KGVIsS2tvaO7akMEJvt2P+ErwCdloG3jQ==", "dev": true, "requires": { "fs-extra": "^8.1.0", @@ -5340,7 +5340,7 @@ "@lerna/rimraf-dir": { "version": "3.16.5", "resolved": "https://registry.npmjs.org/@lerna/rimraf-dir/-/rimraf-dir-3.16.5.tgz", - "integrity": "sha1-BDFqtf/SkJZXqvOI6lAsuMLyCgk=", + "integrity": "sha512-bQlKmO0pXUsXoF8lOLknhyQjOZsCc0bosQDoX4lujBXSWxHVTg1VxURtWf2lUjz/ACsJVDfvHZbDm8kyBk5okA==", "dev": true, "requires": { "@lerna/child-process": "3.16.5", @@ -5352,7 +5352,7 @@ "@lerna/run": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/@lerna/run/-/run-3.21.0.tgz", - "integrity": "sha1-KjXshJeeTW5CR0/hSNMuXeHKyJE=", + "integrity": "sha512-fJF68rT3veh+hkToFsBmUJ9MHc9yGXA7LSDvhziAojzOb0AI/jBDp6cEcDQyJ7dbnplba2Lj02IH61QUf9oW0Q==", "dev": true, "requires": { "@lerna/command": "3.21.0", @@ -5369,7 +5369,7 @@ "@lerna/run-lifecycle": { "version": "3.16.2", "resolved": "https://registry.npmjs.org/@lerna/run-lifecycle/-/run-lifecycle-3.16.2.tgz", - "integrity": "sha1-Z7KI+OqWTbnqT7H7x3FdW7sLzgA=", + "integrity": "sha512-RqFoznE8rDpyyF0rOJy3+KjZCeTkO8y/OB9orPauR7G2xQ7PTdCpgo7EO6ZNdz3Al+k1BydClZz/j78gNCmL2A==", "dev": true, "requires": { "@lerna/npm-conf": "3.16.0", @@ -5381,7 +5381,7 @@ "@lerna/run-topologically": { "version": "3.18.5", "resolved": "https://registry.npmjs.org/@lerna/run-topologically/-/run-topologically-3.18.5.tgz", - "integrity": "sha1-PNY52iDpZ9dnLLiNsPdWuS8v38M=", + "integrity": "sha512-6N1I+6wf4hLOnPW+XDZqwufyIQ6gqoPfHZFkfWlvTQ+Ue7CuF8qIVQ1Eddw5HKQMkxqN10thKOFfq/9NQZ4NUg==", "dev": true, "requires": { "@lerna/query-graph": "3.18.5", @@ -5392,13 +5392,13 @@ "eventemitter3": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", - "integrity": "sha1-LT1I+cNGaY/Og6hdfWZOmFNd9uc=", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==", "dev": true }, "p-queue": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-4.0.0.tgz", - "integrity": "sha1-7Q7uh5iSftbywvX1t3/bIGGl00Y=", + "integrity": "sha512-3cRXXn3/O0o3+eVmUroJPSj/esxoEFIm0ZOno/T+NzG/VZgPOqQ8WKmlNqubSEpZmCIngEy34unkHGg83ZIBmg==", "dev": true, "requires": { "eventemitter3": "^3.1.0" @@ -5409,7 +5409,7 @@ "@lerna/symlink-binary": { "version": "3.17.0", "resolved": "https://registry.npmjs.org/@lerna/symlink-binary/-/symlink-binary-3.17.0.tgz", - "integrity": "sha1-j4AxswmGOBSIPT8AmHf4Ljiu9Fo=", + "integrity": "sha512-RLpy9UY6+3nT5J+5jkM5MZyMmjNHxZIZvXLV+Q3MXrf7Eaa1hNqyynyj4RO95fxbS+EZc4XVSk25DGFQbcRNSQ==", "dev": true, "requires": { "@lerna/create-symlink": "3.16.2", @@ -5434,7 +5434,7 @@ "@lerna/symlink-dependencies": { "version": "3.17.0", "resolved": "https://registry.npmjs.org/@lerna/symlink-dependencies/-/symlink-dependencies-3.17.0.tgz", - "integrity": "sha1-SNY2DphYZaDlbNi1GzCKUmMIeEo=", + "integrity": "sha512-KmjU5YT1bpt6coOmdFueTJ7DFJL4H1w5eF8yAQ2zsGNTtZ+i5SGFBWpb9AQaw168dydc3s4eu0W0Sirda+F59Q==", "dev": true, "requires": { "@lerna/create-symlink": "3.16.2", @@ -5462,13 +5462,13 @@ "@lerna/timer": { "version": "3.13.0", "resolved": "https://registry.npmjs.org/@lerna/timer/-/timer-3.13.0.tgz", - "integrity": "sha1-vNCQRVHbFuCDZNbBjl4hYPyHB4E=", + "integrity": "sha512-RHWrDl8U4XNPqY5MQHkToWS9jHPnkLZEt5VD+uunCKTfzlxGnRCr3/zVr8VGy/uENMYpVP3wJa4RKGY6M0vkRw==", "dev": true }, "@lerna/validation-error": { "version": "3.13.0", "resolved": "https://registry.npmjs.org/@lerna/validation-error/-/validation-error-3.13.0.tgz", - "integrity": "sha1-yGuPB8WrlTn3db2KVJdukm83WcM=", + "integrity": "sha512-SiJP75nwB8GhgwLKQfdkSnDufAaCbkZWJqEDlKOUPUvVOplRGnfL+BPQZH5nvq2BYSRXsksXWZ4UHVnQZI/HYA==", "dev": true, "requires": { "npmlog": "^4.1.2" @@ -5477,7 +5477,7 @@ "@lerna/version": { "version": "3.22.1", "resolved": "https://registry.npmjs.org/@lerna/version/-/version-3.22.1.tgz", - "integrity": "sha1-mAWpJHpH7mLWuBvZ+l+3KLJLWeI=", + "integrity": "sha512-PSGt/K1hVqreAFoi3zjD0VEDupQ2WZVlVIwesrE5GbrL2BjXowjCsTDPqblahDUPy0hp6h7E2kG855yLTp62+g==", "dev": true, "requires": { "@lerna/check-working-tree": "3.16.5", @@ -5511,7 +5511,7 @@ "load-json-file": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-5.3.0.tgz", - "integrity": "sha1-TTweAfocA+p4pgrHr5MsnOU0A/M=", + "integrity": "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw==", "dev": true, "requires": { "graceful-fs": "^4.1.15", @@ -5524,19 +5524,19 @@ "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha1-3lUoUaF1nfOo8gZTVEL17E3eq0Q=", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true }, "type-fest": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.3.1.tgz", - "integrity": "sha1-Y9ANIE4FlHT+Xht8ARESu9HcKeE=", + "integrity": "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ==", "dev": true } } @@ -5544,7 +5544,7 @@ "@lerna/write-log-file": { "version": "3.13.0", "resolved": "https://registry.npmjs.org/@lerna/write-log-file/-/write-log-file-3.13.0.tgz", - "integrity": "sha1-t42eTPwTSai+ZNkTJMTIGZ6CKiY=", + "integrity": "sha512-RibeMnDPvlL8bFYW5C8cs4mbI3AHfQef73tnJCQ/SgrXZHehmHnsyWUiE7qDQCAo+B1RfTapvSyFF69iPj326A==", "dev": true, "requires": { "npmlog": "^4.1.2", @@ -5554,7 +5554,7 @@ "write-file-atomic": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha1-H9Lprh3z51uNjDZ0Q8aS1MqB9IE=", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", "dev": true, "requires": { "graceful-fs": "^4.1.11", @@ -5567,7 +5567,7 @@ "@mrmlnc/readdir-enhanced": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", - "integrity": "sha1-UkryQNGjYFJ7cwR17PoTRKpUDd4=", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", "dev": true, "requires": { "call-me-maybe": "^1.0.1", @@ -6748,7 +6748,7 @@ "@octokit/auth-token": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.4.2.tgz", - "integrity": "sha1-ENCul5sQD6a3L6Do5j4n5tDb/4o=", + "integrity": "sha512-jE/lE/IKIz2v1+/P0u4fJqv0kYwXOTujKemJMFr6FeopsxlIK3+wKDCJGnysg81XID5TgZQbIfuJ5J0lnTiuyQ==", "dev": true, "requires": { "@octokit/types": "^5.0.0" @@ -6757,7 +6757,7 @@ "@octokit/endpoint": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.5.tgz", - "integrity": "sha1-Q6at7oE8X/0vcZ4gz9FKH+58GTo=", + "integrity": "sha512-70K5u6zd45ItOny6aHQAsea8HHQjlQq85yqOMe+Aj8dkhN2qSJ9T+Q3YjUjEYfPRBcuUWNgMn62DQnP/4LAIiQ==", "dev": true, "requires": { "@octokit/types": "^5.0.0", @@ -6768,13 +6768,13 @@ "is-plain-object": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-4.1.1.tgz", - "integrity": "sha1-GhTWRSy9UHkO3H/aoK7VpAo167U=", + "integrity": "sha512-5Aw8LLVsDlZsETVMhoMXzqsXwQqr/0vlnBYzIXJbYo2F4yYlhLHs+Ez7Bod7IIQKWkJbJfxrWD7pA1Dw1TKrwA==", "dev": true }, "universal-user-agent": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha1-M4H4UDslHA2c0hvB3pOeyd9UgO4=", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", "dev": true } } @@ -6782,13 +6782,13 @@ "@octokit/plugin-enterprise-rest": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz", - "integrity": "sha1-4HiWc5YY2rjafUB3xlgAN3X5VDc=", + "integrity": "sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw==", "dev": true }, "@octokit/plugin-paginate-rest": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz", - "integrity": "sha1-AEFwrPjCvlNauiZyeGfWkve0iPw=", + "integrity": "sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q==", "dev": true, "requires": { "@octokit/types": "^2.0.1" @@ -6797,7 +6797,7 @@ "@octokit/types": { "version": "2.16.2", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", - "integrity": "sha1-TF+No8b+zz2hgRrvZ4/aA+2sNdI=", + "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", "dev": true, "requires": { "@types/node": ">= 8" @@ -6808,13 +6808,13 @@ "@octokit/plugin-request-log": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz", - "integrity": "sha1-7vh6QxMA9hSMOaf3X4z+shiyVH4=", + "integrity": "sha512-ywoxP68aOT3zHCLgWZgwUJatiENeHE7xJzYjfz8WI0goynp96wETBF+d95b8g/uL4QmS6owPVlaxiz3wyMAzcw==", "dev": true }, "@octokit/plugin-rest-endpoint-methods": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz", - "integrity": "sha1-Mojs9UgfaMSU3QYC/BVAeln69h4=", + "integrity": "sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ==", "dev": true, "requires": { "@octokit/types": "^2.0.1", @@ -6824,7 +6824,7 @@ "@octokit/types": { "version": "2.16.2", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", - "integrity": "sha1-TF+No8b+zz2hgRrvZ4/aA+2sNdI=", + "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", "dev": true, "requires": { "@types/node": ">= 8" @@ -6835,7 +6835,7 @@ "@octokit/request": { "version": "5.4.7", "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.4.7.tgz", - "integrity": "sha1-/XA+4JLgRjzrpJ/3o+YctM+KD94=", + "integrity": "sha512-FN22xUDP0i0uF38YMbOfx6TotpcENP5W8yJM1e/LieGXn6IoRxDMnBf7tx5RKSW4xuUZ/1P04NFZy5iY3Rax1A==", "dev": true, "requires": { "@octokit/endpoint": "^6.0.1", @@ -6851,7 +6851,7 @@ "@octokit/request-error": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.2.tgz", - "integrity": "sha1-Dna4P12P3aHbmQJ+pfYXwua6ntA=", + "integrity": "sha512-2BrmnvVSV1MXQvEkrb9zwzP0wXFNbPJij922kYBTLIlIafukrGOb+ABBT2+c6wZiuyWDH1K1zmjGQ0toN/wMWw==", "dev": true, "requires": { "@octokit/types": "^5.0.1", @@ -6862,13 +6862,13 @@ "is-plain-object": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-4.1.1.tgz", - "integrity": "sha1-GhTWRSy9UHkO3H/aoK7VpAo167U=", + "integrity": "sha512-5Aw8LLVsDlZsETVMhoMXzqsXwQqr/0vlnBYzIXJbYo2F4yYlhLHs+Ez7Bod7IIQKWkJbJfxrWD7pA1Dw1TKrwA==", "dev": true }, "universal-user-agent": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz", - "integrity": "sha1-M4H4UDslHA2c0hvB3pOeyd9UgO4=", + "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==", "dev": true } } @@ -6876,7 +6876,7 @@ "@octokit/request-error": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-1.2.1.tgz", - "integrity": "sha1-7eBxTHc/MjR1dsJWSdwBOuazGAE=", + "integrity": "sha512-+6yDyk1EES6WK+l3viRDElw96MvwfJxCt45GvmjDUKWjYIb3PJZQkq3i46TwGwoPD4h8NmTrENmtyA1FwbmhRA==", "dev": true, "requires": { "@octokit/types": "^2.0.0", @@ -6887,7 +6887,7 @@ "@octokit/types": { "version": "2.16.2", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-2.16.2.tgz", - "integrity": "sha1-TF+No8b+zz2hgRrvZ4/aA+2sNdI=", + "integrity": "sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q==", "dev": true, "requires": { "@types/node": ">= 8" @@ -6898,7 +6898,7 @@ "@octokit/rest": { "version": "16.43.2", "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-16.43.2.tgz", - "integrity": "sha1-xTQm8eHRBE3ulnAj4yecUJk92Rs=", + "integrity": "sha512-ngDBevLbBTFfrHZeiS7SAMAZ6ssuVmXuya+F/7RaVvlysgGa1JKJkKWY+jV6TCJYcW0OALfJ7nTIGXcBXzycfQ==", "dev": true, "requires": { "@octokit/auth-token": "^2.4.0", @@ -6922,7 +6922,7 @@ "@octokit/types": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@octokit/types/-/types-5.2.0.tgz", - "integrity": "sha1-0HXcI78pP1QHOSULaHniwb4vwgw=", + "integrity": "sha512-XjOk9y4m8xTLIKPe1NFxNWBdzA2/z3PFFA/bwf4EoH6oS8hM0Y46mEa4Cb+KCyj/tFDznJFahzQ0Aj3o1FYq4A==", "dev": true, "requires": { "@types/node": ">= 8" @@ -6936,7 +6936,7 @@ "@remixproject/engine": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@remixproject/engine/-/engine-0.3.3.tgz", - "integrity": "sha512-0orGJhxHAFMUMokfDVq04yy0cvFknyrk9PcqvJw3KqChhusgkLw/J/KqJszywD9BmIjLgdc3n8vRtCmHICR3mA==", + "integrity": "sha1-jEde0zAFQBj8C0s49f1FqbK9gIY=", "requires": { "@remixproject/plugin-api": "0.3.3", "@remixproject/plugin-utils": "0.3.3" @@ -6945,7 +6945,7 @@ "@remixproject/engine-web": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@remixproject/engine-web/-/engine-web-0.3.3.tgz", - "integrity": "sha512-GF+WHrZyT8OS9ApmAv6ujUfX/lfxbpfTYbYC0To/EznusrBYfm0tmem1xvmI4PJ5C1NOxz9j862S4I4AxWGOng==", + "integrity": "sha1-ZQZD7museqljZNPHpuOwG7dgiZU=", "requires": { "@remixproject/engine": "0.3.3", "@remixproject/plugin-api": "0.3.3", @@ -6955,7 +6955,7 @@ "@remixproject/plugin": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@remixproject/plugin/-/plugin-0.3.3.tgz", - "integrity": "sha512-gSZdgBjb4y2N2+5kMfbJYjO2zH8b1pFd3xdY4ViL5vtt8l4lup+iOVidrGTv1lPPl7Snk+E8NQhRk8Snr6//mg==", + "integrity": "sha1-yy+ifasg+IQ5CDJ2jmXRaRc8sAE=", "requires": { "@remixproject/plugin-api": "0.3.3", "@remixproject/plugin-utils": "0.3.3", @@ -6965,7 +6965,7 @@ "events": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", - "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==" + "integrity": "sha1-k7h8GPjvzUICpGGuxN/AVWtjk3k=" } } }, @@ -6995,7 +6995,7 @@ "@remixproject/plugin-webview": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@remixproject/plugin-webview/-/plugin-webview-0.3.3.tgz", - "integrity": "sha512-2/O2hUgcTFFmuKYnHl65FW7n591lF1PLAmFUSzoUOezs0iAg8+IP1ydejVXFLWhZByLkiQezHu/kezA5g4cwaQ==", + "integrity": "sha1-3x7RgdkD1ya0JTjfWsIp8cpQOqI=", "requires": { "@remixproject/plugin": "0.3.3", "@remixproject/plugin-api": "0.3.3", @@ -7005,7 +7005,7 @@ "@remixproject/plugin-ws": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@remixproject/plugin-ws/-/plugin-ws-0.3.3.tgz", - "integrity": "sha512-QHWv5sjzUIb+rsLyAcOV67tShx8fniJvxYglqURaBc9LXdz0j5QfwnDIGwJwvnkJqAsk3MnXizaIXMU7CvKuzw==", + "integrity": "sha1-qxGVX9ut7uRG0FE+8gOnbyodNr8=", "requires": { "@remixproject/plugin": "0.3.3", "@remixproject/plugin-api": "0.3.3", @@ -7085,12 +7085,12 @@ "@restart/context": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@restart/context/-/context-2.1.4.tgz", - "integrity": "sha1-qZ2HwpmjTCi9hbtInLB7/SMUnAI=" + "integrity": "sha512-INJYZQJP7g+IoDUh/475NlGiTeMfwTXUEr3tmRneckHIxNolGOW9CTq83S8cxq0CgJwwcMzMJFchxvlwe7Rk8Q==" }, "@restart/hooks": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.3.25.tgz", - "integrity": "sha1-EQBBOa0ccNL1llqJOdy1rrlqplI=", + "integrity": "sha512-m2v3N5pxTsIiSH74/sb1yW8D9RxkJidGW+5Mfwn/lHb2QzhZNlaU1su7abSyT9EGf0xS/0waLjrf7/XxQHUk7w==", "requires": { "lodash": "^4.17.15", "lodash-es": "^4.17.15" @@ -7330,12 +7330,150 @@ "defer-to-connect": "^1.0.1" } }, + "@testing-library/dom": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.29.1.tgz", + "integrity": "sha512-6BU7vAjKuMspCy9QQEtbWgmkuXi/yOSZo3ANdvZmNQW8N/WQGjO9cvlcA5EFJaPtp2hL1RAaPGpCXxumijUxCg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^4.2.0", + "aria-query": "^4.2.2", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.4", + "lz-string": "^1.4.4", + "pretty-format": "^26.6.2" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", + "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@jest/types": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + } + }, + "@types/istanbul-reports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", + "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "pretty-format": { + "version": "26.6.2", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "dev": true, + "requires": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + } + }, + "react-is": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", + "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@testing-library/react": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-10.4.1.tgz", + "integrity": "sha512-QX31fRDGLnOdBYoQ95VEOYgRahaPfsI+toOaYhlvuGNFQrcagZv/KLWCIctRGB0h1PTsQt3JpLBbbLGM63yy5Q==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.3", + "@testing-library/dom": "^7.17.1" + } + }, "@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true }, + "@types/aria-query": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.0.tgz", + "integrity": "sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A==", + "dev": true + }, "@types/axios": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@types/axios/-/axios-0.14.0.tgz", @@ -7470,7 +7608,7 @@ "@types/invariant": { "version": "2.2.34", "resolved": "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.34.tgz", - "integrity": "sha1-BeT3n0ZcIAeIQ3TUeVRS+ZVyC74=" + "integrity": "sha512-lYUtmJ9BqUN688fGY1U1HZoWT1/Jrmgigx2loq4ZcJpICECm/Om3V314BxdzypO0u5PORKGMM6x0OXaljV1YFg==" }, "@types/istanbul-lib-coverage": { "version": "2.0.3", @@ -7639,7 +7777,7 @@ "@types/react-transition-group": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz", - "integrity": "sha1-iCg520Zd8TIOR1Pm6fcMp+m01G0=", + "integrity": "sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w==", "requires": { "@types/react": "*" } @@ -8168,7 +8306,7 @@ "@zkochan/cmd-shim": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@zkochan/cmd-shim/-/cmd-shim-3.1.0.tgz", - "integrity": "sha1-KrjtgfW7VFKoXyV1jrm4aBmC/S4=", + "integrity": "sha512-o8l0+x7C7sMZU3v9GuJIAU10qQLtwR1dtRQIOmlNMtyaqhmpXOzx1HWiYoWfmmf9HHZoAkXpc9TM9PQYF9d4Jg==", "dev": true, "requires": { "is-windows": "^1.0.0", @@ -8675,7 +8813,7 @@ "array-differ": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-2.1.0.tgz", - "integrity": "sha1-S5wcPxS5BnVwgpJXaeirkE9IAbE=", + "integrity": "sha512-KbUpJgx909ZscOc/7CLATBFam7P1Z1QRQInvgT0UztM9Q72aGKCunKASAl7WNW0tnPmPyEMeMhdsfWhfmW037w==", "dev": true }, "array-each": { @@ -9230,7 +9368,7 @@ "babel-jest": { "version": "25.1.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-25.1.0.tgz", - "integrity": "sha1-IGCTrDgKS3jEQEoFsydzkSePgPs=", + "integrity": "sha512-tz0VxUhhOE2y+g8R2oFrO/2VtVjA1lkJeavlhExuRBg3LdNJY9gwQ+Vcvqt9+cqy71MCTJhewvTB7Qtnnr9SWg==", "dev": true, "requires": { "@jest/transform": "^25.1.0", @@ -9255,7 +9393,7 @@ "chalk": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha1-P3PCv1JlkfV0zEksUeJFY0n4ROQ=", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -9265,7 +9403,7 @@ "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { "color-name": "~1.1.4" @@ -9274,25 +9412,25 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha1-ZTm+hwwWWtvVJAIg2+Nh8bxNRjQ=", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { "has-flag": "^4.0.0" @@ -9414,6 +9552,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, + "optional": true, "requires": { "is-extendable": "^0.1.0" } @@ -9469,6 +9608,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, + "optional": true, "requires": { "kind-of": "^3.0.2" } @@ -9485,6 +9625,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, + "optional": true, "requires": { "is-buffer": "^1.1.5" } @@ -9521,7 +9662,8 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "optional": true }, "string_decoder": { "version": "1.1.1", @@ -10387,7 +10529,7 @@ "before-after-hook": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.1.0.tgz", - "integrity": "sha1-tsA0h/ROJCAN0wyl5qGXnF0vtjU=", + "integrity": "sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A==", "dev": true }, "big.js": { @@ -11751,7 +11893,7 @@ "byte-size": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-5.0.1.tgz", - "integrity": "sha1-S2UQOaXs2Wdn5xo9ftOA5IvtQZE=", + "integrity": "sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw==", "dev": true }, "bytes": { @@ -11896,7 +12038,7 @@ "camelcase-keys": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha1-XnVda6UaoiPsfT1S8ld4IQ+dw8A=", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", "dev": true, "requires": { "camelcase": "^5.3.1", @@ -12250,7 +12392,7 @@ "classnames": { "version": "2.2.6", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.6.tgz", - "integrity": "sha1-Q5Nb/90pHzJtrQogUwmzjQD2UM4=" + "integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==" }, "clean-css": { "version": "4.2.1", @@ -12651,7 +12793,7 @@ "command-exists": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.9.tgz", - "integrity": "sha1-xQclrzgIyKsCYP1gsB+/oluVT2k=", + "integrity": "sha512-LTQ/SGc+s0Xc0Fu5WaKnR0YiygZkm9eKFvyS+fRsU7/ZWFF8ykFM6Pc9aCVf1+xasOOZpO3BAVgVrKvsqKHV7w==", "dev": true }, "commander": { @@ -12674,7 +12816,7 @@ "compare-func": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-1.3.4.tgz", - "integrity": "sha1-awfExeg0ERm69EV4CFvaD0qCNRY=", + "integrity": "sha512-sq2sWtrqKPkEXAC8tEJA1+BqAH9GbFkGBtUOqrUX57VSfwp8xyktctk+uLoRy5eccTdxzDcVIztlYDpKs3Jv1Q==", "dev": true, "requires": { "array-ify": "^1.0.0", @@ -12935,7 +13077,7 @@ "conventional-changelog-angular": { "version": "5.0.10", "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.10.tgz", - "integrity": "sha1-XPewDdMVtqalWCI8gNXvJN2zQgU=", + "integrity": "sha512-k7RPPRs0vp8+BtPsM9uDxRl6KcgqtCJmzRD1wRtgqmhQ96g8ifBGo9O/TZBG23jqlXS/rg8BKRDELxfnQQGiaA==", "dev": true, "requires": { "compare-func": "^1.3.1", @@ -12945,7 +13087,7 @@ "conventional-changelog-core": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-3.2.3.tgz", - "integrity": "sha1-sxQQhW9DHIRwhqfctNLKGEp9iPs=", + "integrity": "sha512-LMMX1JlxPIq/Ez5aYAYS5CpuwbOk6QFp8O4HLAcZxe3vxoCtABkhfjetk8IYdRB9CDQGwJFLR3Dr55Za6XKgUQ==", "dev": true, "requires": { "conventional-changelog-writer": "^4.0.6", @@ -12987,7 +13129,7 @@ "through2": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha1-mfiJMc/HYex2eLQdXXM2tbage/Q=", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", "dev": true, "requires": { "inherits": "^2.0.4", @@ -12999,13 +13141,13 @@ "conventional-changelog-preset-loader": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz", - "integrity": "sha1-FKhVq7/9WQJ/1gJYHx802YYupEw=", + "integrity": "sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==", "dev": true }, "conventional-changelog-writer": { "version": "4.0.16", "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.16.tgz", - "integrity": "sha1-yhDyaRqOptPC63S9Nbz0CqBS3aU=", + "integrity": "sha512-jmU1sDJDZpm/dkuFxBeRXvyNcJQeKhGtVcFFkwTphUAzyYWcwz2j36Wcv+Mv2hU3tpvLMkysOPXJTLO55AUrYQ==", "dev": true, "requires": { "compare-func": "^1.3.1", @@ -13023,7 +13165,7 @@ "through2": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha1-mfiJMc/HYex2eLQdXXM2tbage/Q=", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", "dev": true, "requires": { "inherits": "^2.0.4", @@ -13035,7 +13177,7 @@ "conventional-commits-filter": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.6.tgz", - "integrity": "sha1-CTXhJAxcp2mDKa/+4bakbTMyTEw=", + "integrity": "sha512-4g+sw8+KA50/Qwzfr0hL5k5NWxqtrOVw4DDk3/h6L85a9Gz0/Eqp3oP+CWCNfesBvZZZEFHF7OTEbRe+yYSyKw==", "dev": true, "requires": { "lodash.ismatch": "^4.4.0", @@ -13045,7 +13187,7 @@ "conventional-commits-parser": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.1.0.tgz", - "integrity": "sha1-EBQGc9Xn71VyYzeRRWxdA7aei+Q=", + "integrity": "sha512-RSo5S0WIwXZiRxUGTPuYFbqvrR4vpJ1BDdTlthFgvHt5kEdnd1+pdvwWphWn57/oIl4V72NMmOocFqqJ8mFFhA==", "dev": true, "requires": { "JSONStream": "^1.0.4", @@ -13060,7 +13202,7 @@ "through2": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha1-mfiJMc/HYex2eLQdXXM2tbage/Q=", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", "dev": true, "requires": { "inherits": "^2.0.4", @@ -13072,7 +13214,7 @@ "conventional-recommended-bump": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/conventional-recommended-bump/-/conventional-recommended-bump-5.0.1.tgz", - "integrity": "sha1-WvY5A5R7bgied3Z2ActZLKuxBro=", + "integrity": "sha512-RVdt0elRcCxL90IrNP0fYCpq1uGt2MALko0eyeQ+zQuDVWtMGAy9ng6yYn3kax42lCj9+XBxQ8ZN6S9bdKxDhQ==", "dev": true, "requires": { "concat-stream": "^2.0.0", @@ -13105,7 +13247,7 @@ "concat-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", - "integrity": "sha1-QUz1r3kKSMYKub5FJ9VtXkETPLE=", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -13129,7 +13271,7 @@ "meow": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz", - "integrity": "sha1-1IWY9vSxRy81v2MXqVlFrONH+XU=", + "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==", "dev": true, "requires": { "camelcase-keys": "^4.0.0", @@ -13146,7 +13288,7 @@ "minimist-options": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", - "integrity": "sha1-+6TIGRM54T7PTWG+sD8HAQPz2VQ=", + "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", "dev": true, "requires": { "arrify": "^1.0.1", @@ -14110,7 +14252,7 @@ "dateformat": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", - "integrity": "sha1-puN0maTZqc+F71hyBE1ikByYia4=", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", "dev": true }, "deasync": { @@ -14686,7 +14828,7 @@ "deprecation": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", - "integrity": "sha1-Y2jL20Cr8zc7UlrIfkomDDpwCRk=", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==", "dev": true }, "deps-sort": { @@ -14836,10 +14978,24 @@ } } }, + "document-register-element": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/document-register-element/-/document-register-element-1.13.1.tgz", + "integrity": "sha512-92ZyLDKg9j4rOll//NNXj25f+8rAzOkYsGJonhugKwXfeqH7bzs8Ucpvey0WzZ2ZzKdrvW9RnUw3UyOZ/uhBFw==", + "requires": { + "lightercollective": "^0.1.0" + } + }, + "dom-accessibility-api": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz", + "integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==", + "dev": true + }, "dom-helpers": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz", - "integrity": "sha1-V/0FTF+PNMUqPu/9t+fpPNNX2Vs=", + "integrity": "sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==", "requires": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" @@ -16857,7 +17013,7 @@ "express-ws": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/express-ws/-/express-ws-4.0.0.tgz", - "integrity": "sha512-KEyUw8AwRET2iFjFsI1EJQrJ/fHeGiJtgpYgEWG3yDv4l/To/m3a2GaYfeGyB3lsWdvbesjF5XCMx+SVBgAAYw==", + "integrity": "sha1-2r2NyXRRZBiQKkH+bjDtlJtNNsQ=", "requires": { "ws": "^5.2.0" }, @@ -16865,7 +17021,7 @@ "ws": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "integrity": "sha1-3/7xSGa46NyRM1glFNG++vlumA8=", "requires": { "async-limiter": "~1.0.0" } @@ -18619,7 +18775,7 @@ "genfun": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", - "integrity": "sha1-ndlxCgaQClxKW/V6yl2k5S/nZTc=", + "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==", "dev": true }, "gensync": { @@ -18836,7 +18992,7 @@ "get-port": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/get-port/-/get-port-4.2.0.tgz", - "integrity": "sha1-43Nosehjt2KcQ8WjI2Jflc8ksRk=", + "integrity": "sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw==", "dev": true }, "get-stdin": { @@ -18963,7 +19119,7 @@ "git-raw-commits": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.0.tgz", - "integrity": "sha1-2Srd90RAwUvMXIPszj+3+KeRGLU=", + "integrity": "sha512-w4jFEJFgKXMQJ0H0ikBk2S+4KP2VEjhCvLCNqbNRQC8BgGWgLKNCO7a9K9LI+TVT7Gfoloje502sEnctibffgg==", "dev": true, "requires": { "dargs": "^4.0.1", @@ -19005,7 +19161,7 @@ "meow": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz", - "integrity": "sha1-1IWY9vSxRy81v2MXqVlFrONH+XU=", + "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==", "dev": true, "requires": { "camelcase-keys": "^4.0.0", @@ -19022,7 +19178,7 @@ "minimist-options": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", - "integrity": "sha1-+6TIGRM54T7PTWG+sD8HAQPz2VQ=", + "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", "dev": true, "requires": { "arrify": "^1.0.1", @@ -19101,7 +19257,7 @@ "git-semver-tags": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-2.0.3.tgz", - "integrity": "sha1-SJiKcYrPWTgA+ZYiqVKnfEBb+jQ=", + "integrity": "sha512-tj4FD4ww2RX2ae//jSrXZzrocla9db5h0V7ikPl1P/WwoZar9epdUhwR7XHXSgc+ZkNq72BEEerqQuicoEQfzA==", "dev": true, "requires": { "meow": "^4.0.0", @@ -19140,7 +19296,7 @@ "meow": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz", - "integrity": "sha1-1IWY9vSxRy81v2MXqVlFrONH+XU=", + "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==", "dev": true, "requires": { "camelcase-keys": "^4.0.0", @@ -19157,7 +19313,7 @@ "minimist-options": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz", - "integrity": "sha1-+6TIGRM54T7PTWG+sD8HAQPz2VQ=", + "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==", "dev": true, "requires": { "arrify": "^1.0.1", @@ -19218,7 +19374,7 @@ "git-up": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/git-up/-/git-up-4.0.1.tgz", - "integrity": "sha1-yy7whmU2QOch0gQv4xBIV9iQB8A=", + "integrity": "sha512-LFTZZrBlrCrGCG07/dm1aCjjpL1z9L3+5aEeI9SBhAqSc+kiA9Or1bgZhQFNppJX6h/f5McrvJt1mQXTFm6Qrw==", "dev": true, "requires": { "is-ssh": "^1.3.0", @@ -19228,7 +19384,7 @@ "git-url-parse": { "version": "11.1.2", "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.1.2.tgz", - "integrity": "sha1-r/Gol8NsyTaZJwWHvqPby7uV3mc=", + "integrity": "sha512-gZeLVGY8QVKMIkckncX+iCq2/L8PlwncvDFKiWkBn9EtCfYDbliRTTp6qzyQ1VMdITUfq7293zDzfpjdiGASSQ==", "dev": true, "requires": { "git-up": "^4.0.0" @@ -20034,7 +20190,7 @@ "handlebars": { "version": "4.7.6", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", - "integrity": "sha1-1MBcG6+Q6ZRfd6pop6IZqkp9904=", + "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", "dev": true, "requires": { "minimist": "^1.2.5", @@ -20047,13 +20203,13 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true }, "uglify-js": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.0.tgz", - "integrity": "sha1-OXp+bjHOggv9HLVbgE7hQMWHqec=", + "integrity": "sha512-Esj5HG5WAyrLIdYU74Z3JdG2PxdIusvj6IWHMtlyESxc7kcDz7zYlYjpnSokn1UbpV0d/QX9fan7gkCNd/9BQA==", "dev": true, "optional": true }, @@ -20084,7 +20240,7 @@ "hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha1-HG7aXBaFxjlCdm15u0Cudzzs2IM=", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", "dev": true }, "harmony-reflect": { @@ -20725,7 +20881,7 @@ "init-package-json": { "version": "1.10.3", "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-1.10.3.tgz", - "integrity": "sha1-Rf/i9hCoyhNPK9HbVjeyNQcPbL4=", + "integrity": "sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw==", "dev": true, "requires": { "glob": "^7.1.1", @@ -20741,7 +20897,7 @@ "npm-package-arg": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", - "integrity": "sha1-AhaMsKSaK3W/mIooaY3ntSnfXLc=", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", "dev": true, "requires": { "hosted-git-info": "^2.7.1", @@ -20753,7 +20909,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -21561,7 +21717,7 @@ "is-ssh": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.1.tgz", - "integrity": "sha1-80moyt0k5lKYA3pSLPdSDy6BoPM=", + "integrity": "sha512-0eRIASHZt1E68/ixClI8bp2YK2wmBPVWEismTs6M+M099jKgrzl/3E976zIbImSIob48N2/XGe9y7ZiYdImSlg==", "dev": true, "requires": { "protocols": "^1.1.0" @@ -24236,7 +24392,7 @@ "lerna": { "version": "3.22.1", "resolved": "https://registry.npmjs.org/lerna/-/lerna-3.22.1.tgz", - "integrity": "sha1-ggJ6w9qcYn/YvwLM/v+AapjmW2I=", + "integrity": "sha512-vk1lfVRFm+UuEFA7wkLKeSF7Iz13W+N/vFd48aW2yuS7Kv0RbNm2/qcDPV863056LMfkRlsEe+QYOw3palj5Lg==", "dev": true, "requires": { "@lerna/add": "3.21.0", @@ -24609,6 +24765,11 @@ "resolve": "^1.1.7" } }, + "lightercollective": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lightercollective/-/lightercollective-0.1.0.tgz", + "integrity": "sha512-J9tg5uraYoQKaWbmrzDDexbG6hHnMcWS1qLYgJSWE+mpA3U5OCSeMUhb+K55otgZJ34oFdR0ECvdIb3xuO5JOQ==" + }, "lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", @@ -24833,7 +24994,7 @@ "lodash-es": { "version": "4.17.15", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz", - "integrity": "sha1-Ib2Wg5NUQS8j16EDQOXqxu5FXXg=" + "integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==" }, "lodash._arraycopy": { "version": "3.0.0", @@ -25004,7 +25165,7 @@ "lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", - "integrity": "sha1-+XYZXPPzR9DV9SSDVp/oAxzM6Ks=", + "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==", "dev": true, "requires": { "lodash._reinterpolate": "^3.0.0", @@ -25014,7 +25175,7 @@ "lodash.templatesettings": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz", - "integrity": "sha1-5IExDwSdPPbUfpEq0JMTsVTw+zM=", + "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==", "dev": true, "requires": { "lodash._reinterpolate": "^3.0.0" @@ -25198,10 +25359,16 @@ "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", "integrity": "sha1-81ypHEk/e3PaDgdJUwTxezH4fuU=" }, + "lz-string": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", + "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=", + "dev": true + }, "macos-release": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.4.1.tgz", - "integrity": "sha1-ZAM9Dsal5jdRVadLGh66jlCYIKw=", + "integrity": "sha512-H/QHeBIN1fIGJX517pvK8IEK53yQOW7YcEI55oYtgjDdoCQQz7eJS94qt5kNrscReEyuD/JcdFCm2XBEcGOITg==", "dev": true }, "magic-string": { @@ -25461,7 +25628,7 @@ "map-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz", - "integrity": "sha1-uRIhtUJzS58UJWwBMsiXxdclb9U=", + "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==", "dev": true }, "map-visit": { @@ -25679,7 +25846,7 @@ "meow": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/meow/-/meow-7.0.1.tgz", - "integrity": "sha1-HtSgpQs4RLRRNpxINi6wUV8Ewdw=", + "integrity": "sha512-tBKIQqVrAHqwit0vfuFPY3LlzJYkEOFyKa3bPgxzNl6q/RtN8KQ+ALYEASYuFayzSAsjlhXj/JZ10rH85Q6TUw==", "dev": true, "requires": { "@types/minimist": "^1.2.0", @@ -25700,19 +25867,19 @@ "arrify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha1-yWVekzHgq81YjSp8rX6ZVvZnAfo=", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", "dev": true }, "camelcase": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.0.0.tgz", - "integrity": "sha1-Uln3ww414njxvcKk2RIws3ytmB4=", + "integrity": "sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w==", "dev": true }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha1-l6/n1s3AvFkoWEt8jXsW6KmqXRk=", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "requires": { "locate-path": "^5.0.0", @@ -25722,7 +25889,7 @@ "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha1-Gvujlq/WdqbUJQTQpno6frn2KqA=", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "requires": { "p-locate": "^4.1.0" @@ -25731,7 +25898,7 @@ "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha1-PdM8ZHohT9//2DWTPrCG2g3CHbE=", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -25740,7 +25907,7 @@ "p-locate": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha1-o0KLtwiLOmApL2aRkni3wpetTwc=", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "requires": { "p-limit": "^2.2.0" @@ -25749,13 +25916,13 @@ "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha1-yyhoVA4xPWHeWPr741zpAE1VQOY=", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, "parse-json": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.1.tgz", - "integrity": "sha1-fP41wczWQbzjmBRn5sLs5hs7OHg=", + "integrity": "sha512-ztoZ4/DYeXQq4E21v169sC8qWINGpcosGv9XhTDvg9/hWvx/zrFkc9BiWxR58OJLHGk28j5BL0SDLeV2WmFZlQ==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -25767,13 +25934,13 @@ "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha1-UTvb4tO5XXdi6METfvoZXGxhtbM=", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha1-e/KVQ4yloz5WzTDgU7NO5yUMk8w=", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "dev": true, "requires": { "@types/normalize-package-data": "^2.4.0", @@ -25785,7 +25952,7 @@ "type-fest": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha1-jSojcNPfiG61yQraHFv2GIrPg4s=", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", "dev": true } } @@ -25793,7 +25960,7 @@ "read-pkg-up": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha1-86YTV1hFlzOuK5VjgFbhhU5+9Qc=", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "dev": true, "requires": { "find-up": "^4.1.0", @@ -25804,7 +25971,7 @@ "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha1-CeJJ696FHTseSNJ8EFREZn8XuD0=", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true } } @@ -25812,13 +25979,13 @@ "type-fest": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha1-AXLLW86AsL1ULqNI21DH4hg02TQ=", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", "dev": true }, "yargs-parser": { "version": "18.1.3", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha1-vmjEl1xrKr9GkjawyHA2L6sJp7A=", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, "requires": { "camelcase": "^5.0.0", @@ -25828,7 +25995,7 @@ "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha1-48mzFWnhBoEd8kL3FXJaH0xJQyA=", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true } } @@ -26195,7 +26362,7 @@ "min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha1-pj9oFnOzBXH76LwlaGrnRu76mGk=", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true }, "mini-css-extract-plugin": { @@ -26255,7 +26422,7 @@ "minimist-options": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha1-wGVXE8U6ii69d/+iR9NCxA8BBhk=", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", "dev": true, "requires": { "arrify": "^1.0.1", @@ -26768,7 +26935,7 @@ "modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", - "integrity": "sha1-s5OfpgVUZHTj4+PGPWS9Q7TuYCI=", + "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==", "dev": true }, "module-deps": { @@ -27000,7 +27167,7 @@ "multimatch": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-3.0.0.tgz", - "integrity": "sha1-DiU0zGvCONmrZ+G5zV/Nhabb9ws=", + "integrity": "sha512-22foS/gqQfANZ3o+W7ST2x25ueHDVNWl/b9OlGcLpy/iKxjCpvcNCM51YCenUi7Mt/jAjjqv8JwZRs8YP5sRjA==", "dev": true, "requires": { "array-differ": "^2.0.3", @@ -27036,7 +27203,7 @@ "mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha1-lQCAV6Vsr63CvGPd5/n/aVWUjjI=", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", "dev": true, "requires": { "any-promise": "^1.0.0", @@ -27255,7 +27422,8 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true + "dev": true, + "optional": true }, "cliui": { "version": "5.0.0", @@ -27299,6 +27467,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, + "optional": true, "requires": { "locate-path": "^3.0.0" } @@ -27341,6 +27510,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, + "optional": true, "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -27410,6 +27580,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "optional": true, "requires": { "p-try": "^2.0.0" } @@ -27419,6 +27590,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, + "optional": true, "requires": { "p-limit": "^2.0.0" } @@ -27427,7 +27599,8 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true + "dev": true, + "optional": true }, "require-main-filename": { "version": "2.0.0", @@ -27441,6 +27614,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, + "optional": true, "requires": { "emoji-regex": "^7.0.1", "is-fullwidth-code-point": "^2.0.0", @@ -27452,6 +27626,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, + "optional": true, "requires": { "ansi-regex": "^4.1.0" } @@ -27533,6 +27708,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, + "optional": true, "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -27586,17 +27762,12 @@ "node-fetch": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", -<<<<<<< .merge_file_V6jDWX "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" -======= - "integrity": "sha1-5jNFY4bUqlWGP2dqerDaqP3ssP0=", - "dev": true ->>>>>>> .merge_file_8k1pIl }, "node-fetch-npm": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.4.tgz", - "integrity": "sha1-ZQfQ4XqewL477FFpWKSXzsVL9aQ=", + "integrity": "sha512-iOuIQDWDyjhv9qSDrj9aq/klt6F9z1p2otB3AV7v3zBDcL/x+OfGsvGQZZCcMZbUf4Ujw1xGNQkjvGnVT22cKg==", "dev": true, "requires": { "encoding": "^0.1.11", @@ -30477,7 +30648,7 @@ "npm-lifecycle": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-3.1.5.tgz", - "integrity": "sha1-mILTZCuMgsgVeCoS5qG/7tACYwk=", + "integrity": "sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g==", "dev": true, "requires": { "byline": "^5.0.0", @@ -30493,7 +30664,7 @@ "node-gyp": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.1.tgz", - "integrity": "sha1-65Ffe2Mck30oLjOu1Ey3oCX2Kj4=", + "integrity": "sha512-WH0WKGi+a4i4DUt2mHnvocex/xPLp9pYt5R6M2JdFB7pJ7Z34hveZ4nDTGTiLXCkitA9T8HFZjhinBCiVHYcWw==", "dev": true, "requires": { "env-paths": "^2.2.0", @@ -30512,7 +30683,7 @@ "nopt": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha1-o3XK2dAv2SEnjZVMIlTVqlfhXkg=", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", "dev": true, "requires": { "abbrev": "1", @@ -30522,13 +30693,13 @@ "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha1-SrzYUq0y3Xuqv+m0DgCjbbXzkuY=", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -32617,7 +32788,7 @@ "octokit-pagination-methods": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz", - "integrity": "sha1-z0cu3J1VEFX573P25CtNu0yAvqQ=", + "integrity": "sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ==", "dev": true }, "on-finished": { @@ -33440,7 +33611,7 @@ "os-name": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz", - "integrity": "sha1-3sGdlmKW4c1i1wGlpm7h3ernCAE=", + "integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==", "dev": true, "requires": { "macos-release": "^2.2.0", @@ -34014,7 +34185,7 @@ "parse-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.1.tgz", - "integrity": "sha1-DsdpcElJd4yzuO2l6ZTDIHOhrf8=", + "integrity": "sha512-d7yhga0Oc+PwNXDvQ0Jv1BuWkLVPXcAoQ/WREgd6vNNoKYaW52KI+RdOFjI63wjkmps9yUE8VS4veP+AgpQ/hA==", "dev": true, "requires": { "is-ssh": "^1.3.0", @@ -34024,7 +34195,7 @@ "parse-url": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-5.0.1.tgz", - "integrity": "sha1-mcQIT8Eb4UFB76QbPRF6lvy5Un8=", + "integrity": "sha512-flNUPP27r3vJpROi0/R3/2efgKkyXqnXwyP1KQ2U0SfFRgdizOdWfvrrvJg1LuOoxs7GQhmxJlq23IpQ/BkByg==", "dev": true, "requires": { "is-ssh": "^1.3.0", @@ -34036,7 +34207,7 @@ "normalize-url": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", - "integrity": "sha1-suHE3E98bVd0PfczpPWXjRhlBVk=", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", "dev": true } } @@ -35240,7 +35411,7 @@ "prop-types-extra": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", - "integrity": "sha1-WMO3TL+7ldMEYll1qi8ISDKaAQs=", + "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", "requires": { "react-is": "^16.3.2", "warning": "^4.0.0" @@ -35261,13 +35432,13 @@ "protocols": { "version": "1.4.7", "resolved": "https://registry.npmjs.org/protocols/-/protocols-1.4.7.tgz", - "integrity": "sha1-lfeIpPDpebKR/+/PVjatET0DfTI=", + "integrity": "sha512-Fx65lf9/YDn3hUX08XUc0J8rSux36rEsyiv21ZGUC1mOyeM3lTRpZLcrm8aAolzS4itwVfm7TAPyxC2E5zd6xg==", "dev": true }, "protoduck": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", - "integrity": "sha1-A8NlnKGAB7aaUP2Cp+vMUWJhFR8=", + "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", "dev": true, "requires": { "genfun": "^5.0.0" @@ -35454,7 +35625,7 @@ "quick-lru": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha1-W4h48ROlgheEjGSCAmxz4bpXcn8=", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", "dev": true }, "raf-schd": { @@ -35562,7 +35733,7 @@ "react": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz", - "integrity": "sha1-LoGIIvGpdDEiwGPWQQ2FweOv5I4=", + "integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -35627,7 +35798,7 @@ "react-dom": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz", - "integrity": "sha1-wb03MxoEhsB47lTEdAcgmTsuDn8=", + "integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", @@ -35643,7 +35814,7 @@ "react-lifecycles-compat": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha1-TxonOv38jzSIqMUWv9p4+HI1I2I=" + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, "react-overlays": { "version": "4.1.0", @@ -35685,7 +35856,7 @@ "react-transition-group": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", - "integrity": "sha1-Y4aPkyWjjqXulTXYKDJ/hXczRck=", + "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", "requires": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", @@ -35722,7 +35893,7 @@ "read-cmd-shim": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.5.tgz", - "integrity": "sha1-h+Q+ulAJi6WjLQzrWDq45DuWHBY=", + "integrity": "sha512-v5yCqQ/7okKoZZkBQUAfTsQ3sVJtXdNfbPnI5cceppoxEVLYA3k+VtV2omkeo8MS94JCy4fSiUwlRBAwCVRPUA==", "dev": true, "requires": { "graceful-fs": "^4.1.2" @@ -35778,7 +35949,7 @@ "read-package-json": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.1.tgz", - "integrity": "sha1-FqpmxZ59Ta1iiPF53ZKV/Vm7mPE=", + "integrity": "sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A==", "dev": true, "requires": { "glob": "^7.1.1", @@ -35801,7 +35972,7 @@ "read-package-tree": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", - "integrity": "sha1-oyy2TH8x64pvMe8G+c7fdAaP5jY=", + "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", "dev": true, "requires": { "read-package-json": "^2.0.0", @@ -35950,7 +36121,7 @@ "redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha1-5Ve3mYMWu1PJ8fVvpiY1LGljBZ8=", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", "dev": true, "requires": { "indent-string": "^4.0.0", @@ -36121,7 +36292,7 @@ "events": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz", - "integrity": "sha1-k7h8GPjvzUICpGGuxN/AVWtjk3k=", + "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==", "dev": true } } @@ -37014,7 +37185,7 @@ "scheduler": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", - "integrity": "sha1-Tz4u0sGn1laB9MhU+oxaHMtA8ZY=", + "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", "requires": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" @@ -37776,7 +37947,7 @@ "solc": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/solc/-/solc-0.7.4.tgz", - "integrity": "sha1-nF7YGuBpLj5hTkfNW1ALD5SFuY0=", + "integrity": "sha512-IVLqAfUkJqgTS0JIgFPeC50ehUeBXu2eE+iU+rqb6UeOyf6w/BB/EsNcTSTpjtUti8BTG/sCd2qVhrWVYy7p0g==", "dev": true, "requires": { "command-exists": "^1.2.8", @@ -37793,7 +37964,7 @@ "commander": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/commander/-/commander-3.0.2.tgz", - "integrity": "sha1-aDfD+2d62ZM9HPukLdFNURfWs54=", + "integrity": "sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==", "dev": true }, "fs-extra": { @@ -37812,7 +37983,7 @@ "js-sha3": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", - "integrity": "sha1-ubel2nOvrX3t0PjEY5VMveaBiEA=", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", "dev": true }, "jsonfile": { @@ -37827,7 +37998,7 @@ "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true } } @@ -38008,7 +38179,7 @@ "split": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha1-YFvZvjA6pZ+zX5Ip++oN3snqB9k=", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", "dev": true, "requires": { "through": "2" @@ -38025,7 +38196,7 @@ "split2": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", - "integrity": "sha1-GGsldbz4PoW30YRldWI47k7kJJM=", + "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==", "dev": true, "requires": { "through2": "^2.0.2" @@ -38919,7 +39090,7 @@ "strip-indent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha1-wy4c7pQLazQyx3G8LFS8znPNMAE=", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "dev": true, "requires": { "min-indent": "^1.0.0" @@ -38934,7 +39105,7 @@ "strong-log-transformer": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", - "integrity": "sha1-D17XjTJeBCGsb5D38Q5pHWrjrhA=", + "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", "dev": true, "requires": { "duplexer": "^0.1.1", @@ -39527,7 +39698,7 @@ "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha1-ecEDO4BRW9bSTsmTPoYMp17ifww=", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { "pify": "^3.0.0" @@ -39645,7 +39816,7 @@ "text-extensions": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", - "integrity": "sha1-GFPkX+45yUXOb2w2stZZtaq8KiY=", + "integrity": "sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==", "dev": true }, "text-hex": { @@ -39662,7 +39833,7 @@ "thenify": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha1-iTLmhqQGYDigFt2eLKRq3Zg4qV8=", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", "dev": true, "requires": { "any-promise": "^1.0.0" @@ -39995,7 +40166,7 @@ "trim-newlines": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz", - "integrity": "sha1-eXJjBKaomKqDc0JymNVMLuixyzA=", + "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==", "dev": true }, "trim-off-newlines": { @@ -40382,7 +40553,7 @@ "uncontrollable": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.1.1.tgz", - "integrity": "sha1-9n/tPvk2NxJlcYCXRjI6nbgV1VY=", + "integrity": "sha512-EcPYhot3uWTS3w00R32R2+vS8Vr53tttrvMj/yA1uYRhf8hbTG2GyugGqWDY0qIskxn0uTTojVd6wPYW9ZEf8Q==", "requires": { "@babel/runtime": "^7.6.3", "@types/react": "^16.9.11", @@ -40565,7 +40736,7 @@ "universal-user-agent": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-4.0.1.tgz", - "integrity": "sha1-/Y1st3OmeacJ6WfvgoijH8wD5Vc=", + "integrity": "sha512-LnST3ebHwVL2aNe4mejI9IQh2HfZ1RLo8Io2HugSif8ekzD1TlWpHpColOB/eh8JHMLkGH3Akqf040I+4ylNxg==", "dev": true, "requires": { "os-name": "^3.1.0" @@ -41156,7 +41327,7 @@ "warning": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha1-Fungd+uKhtavfWSqHgX9hbRnjKM=", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", "requires": { "loose-envify": "^1.0.0" } @@ -41514,6 +41685,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, + "optional": true, "requires": { "is-extendable": "^0.1.0" } @@ -41569,6 +41741,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, + "optional": true, "requires": { "kind-of": "^3.0.2" } @@ -41585,6 +41758,7 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, + "optional": true, "requires": { "is-buffer": "^1.1.5" } @@ -41621,7 +41795,8 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "optional": true }, "string_decoder": { "version": "1.1.1", @@ -42805,7 +42980,7 @@ "windows-release": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.3.1.tgz", - "integrity": "sha1-y06AOF+FUPcJcnKHv3EDXiCcSs4=", + "integrity": "sha512-Pngk/RDCaI/DkuHPlGTdIkDiTAnAkyMjoQMZqRsxydNl1qGXNIoZrB7RK8g53F2tEgQBMqQJHQdYZuQEEAu54A==", "dev": true, "requires": { "execa": "^1.0.0" @@ -43003,7 +43178,7 @@ "write-json-file": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-3.2.0.tgz", - "integrity": "sha1-Zbvcns2KFFjhWVJ3DMut/P9f5io=", + "integrity": "sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ==", "dev": true, "requires": { "detect-indent": "^5.0.0", @@ -43017,7 +43192,7 @@ "pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha1-SyzSXFDVmHNcUCkiJP2MbfQeMjE=", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true }, "sort-keys": { @@ -43032,7 +43207,7 @@ "write-file-atomic": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha1-H9Lprh3z51uNjDZ0Q8aS1MqB9IE=", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", "dev": true, "requires": { "graceful-fs": "^4.1.11", @@ -43045,7 +43220,7 @@ "write-pkg": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/write-pkg/-/write-pkg-3.2.0.tgz", - "integrity": "sha1-DheP6Xgg04mokovHlTXb5ows/yE=", + "integrity": "sha512-tX2ifZ0YqEFOF1wjRW2Pk93NLsj02+n1UP5RvO6rCs0K6R2g1padvf006cY74PQJKMGS2r42NK7FD0dG6Y6paw==", "dev": true, "requires": { "sort-keys": "^2.0.0", @@ -43055,7 +43230,7 @@ "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha1-ecEDO4BRW9bSTsmTPoYMp17ifww=", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "dev": true, "requires": { "pify": "^3.0.0" @@ -43073,7 +43248,7 @@ "write-file-atomic": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha1-H9Lprh3z51uNjDZ0Q8aS1MqB9IE=", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", "dev": true, "requires": { "graceful-fs": "^4.1.11", diff --git a/package.json b/package.json index e207d2c802..b4a1b72fb6 100644 --- a/package.json +++ b/package.json @@ -159,7 +159,8 @@ "signale": "^1.4.0", "time-stamp": "^2.2.0", "winston": "^3.3.3", - "ws": "^7.3.0" + "ws": "^7.3.0", + "document-register-element": "1.13.1" }, "devDependencies": { "@babel/core": "^7.4.5", @@ -283,6 +284,7 @@ "worker-loader": "^2.0.0", "yo-yo": "github:ioedeveloper/yo-yo", "yo-yoify": "^3.7.3", - "@types/jest": "25.1.4" + "@types/jest": "25.1.4", + "@testing-library/react": "10.4.1" } } diff --git a/tsconfig.json b/tsconfig.json index f267d32ab8..5a873c9f97 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,6 +26,7 @@ "@remix-project/remix-url-resolver": [ "dist/libs/remix-url-resolver/index.js" ], + "@remixproject/debugger-plugin": ["apps/debugger/src/index.ts"], "@remix-project/remixd": ["dist/libs/remixd/index.js"], "@remix-ui/tree-view": ["libs/remix-ui/tree-view/src/index.ts"], "@remix-ui/debugger-ui": ["libs/remix-ui/debugger-ui/src/index.ts"], diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000000..d948508f0e --- /dev/null +++ b/tslint.json @@ -0,0 +1,65 @@ +{ + "rulesDirectory": ["node_modules/@nrwl/workspace/src/tslint"], + "linterOptions": { + "exclude": ["**/*"] + }, + "rules": { + "arrow-return-shorthand": true, + "callable-types": true, + "class-name": true, + "deprecation": { + "severity": "warn" + }, + "forin": true, + "import-blacklist": [true, "rxjs/Rx"], + "interface-over-type-literal": true, + "member-access": false, + "member-ordering": [ + true, + { + "order": [ + "static-field", + "instance-field", + "static-method", + "instance-method" + ] + } + ], + "no-arg": true, + "no-bitwise": true, + "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], + "no-construct": true, + "no-debugger": true, + "no-duplicate-super": true, + "no-empty": false, + "no-empty-interface": true, + "no-eval": true, + "no-inferrable-types": [true, "ignore-params"], + "no-misused-new": true, + "no-non-null-assertion": true, + "no-shadowed-variable": true, + "no-string-literal": false, + "no-string-throw": true, + "no-switch-case-fall-through": true, + "no-unnecessary-initializer": true, + "no-unused-expression": true, + "no-var-keyword": true, + "object-literal-sort-keys": false, + "prefer-const": true, + "radix": true, + "triple-equals": [true, "allow-null-check"], + "unified-signatures": true, + "variable-name": false, + + "nx-enforce-module-boundaries": [ + true, + { + "enforceBuildableLibDependency": true, + "allow": [], + "depConstraints": [ + { "sourceTag": "*", "onlyDependOnLibsWithTags": ["*"] } + ] + } + ] + } +} diff --git a/workspace.json b/workspace.json index 4fb9bbd36c..f65a571d09 100644 --- a/workspace.json +++ b/workspace.json @@ -636,6 +636,75 @@ } } } + }, + "debugger": { + "root": "apps/debugger", + "sourceRoot": "apps/debugger/src", + "projectType": "application", + "schematics": {}, + "architect": { + "build": { + "builder": "@nrwl/web:build", + "options": { + "outputPath": "dist/apps/debugger", + "index": "apps/debugger/src/index.html", + "main": "apps/debugger/src/main.tsx", + "polyfills": "apps/debugger/src/polyfills.ts", + "tsConfig": "apps/debugger/tsconfig.app.json", + "assets": [ + "apps/debugger/src/assets", + "apps/debugger/src/index.html", + "apps/debugger/src/favicon.ico" + ], + "styles": [], + "scripts": [], + "webpackConfig": "apps/debugger/webpack.config.js", + "maxWorkers": 2 + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "apps/debugger/src/environments/environment.ts", + "with": "apps/debugger/src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "extractLicenses": true, + "vendorChunk": false, + "budgets": [ + { + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "5mb" + } + ] + } + } + }, + "serve": { + "builder": "@nrwl/web:dev-server", + "options": { + "buildTarget": "debugger:build" + }, + "configurations": { + "production": { + "buildTarget": "debugger:build:production" + } + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": ["apps/debugger/tsconfig.app.json"], + "exclude": ["**/node_modules/**", "!apps/debugger/**/*"] + } + } + } } }, "cli": { From 67783eab109ee21a97f5155efdd842f65ae222d3 Mon Sep 17 00:00:00 2001 From: LianaHus Date: Wed, 6 Jan 2021 11:34:54 +0100 Subject: [PATCH 93/99] added context to menuicons --- apps/remix-ide/src/app/components/vertical-icons.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/apps/remix-ide/src/app/components/vertical-icons.js b/apps/remix-ide/src/app/components/vertical-icons.js index 855050926a..7ff9009ac4 100644 --- a/apps/remix-ide/src/app/components/vertical-icons.js +++ b/apps/remix-ide/src/app/components/vertical-icons.js @@ -4,9 +4,10 @@ var yo = require('yo-yo') var csjs = require('csjs-inject') var helper = require('../../lib/helper') const globalRegistry = require('../../global/registry') +const contextMenu = require('../ui/contextMenu') const { Plugin } = require('@remixproject/engine') - const EventEmitter = require('events') +let VERTICALMENU_HANDLE const profile = { name: 'menuicons', @@ -72,6 +73,7 @@ export class VerticalIcons extends Plugin { onclick="${() => { this.toggle(name) }}" plugin="${name}" title="${title}" + oncontextmenu="${(e) => this.itemContextMenu(e, name)}" data-id="verticalIconsKind${name}"> ${name}
    ` @@ -221,6 +223,15 @@ export class VerticalIcons extends Plugin { } } + itemContextMenu (e, name) { + console.log(name) + VERTICALMENU_HANDLE && VERTICALMENU_HANDLE.hide(null, true) + const actions = {} + actions['Deactivate'] = () => { this.call('manager', 'deactivatePlugin', name) } + VERTICALMENU_HANDLE = contextMenu(e, actions) + e.preventDefault() + } + render () { const home = yo`
    Date: Tue, 12 Jan 2021 12:29:30 +0100 Subject: [PATCH 94/99] added documentation and deactivate to context menu of vertical icons bar --- .../src/app/components/vertical-icons.js | 25 +++++++++++++------ apps/remix-ide/src/app/ui/contextMenu.js | 14 +++++++++-- apps/remix-ide/src/remixAppManager.js | 8 +++--- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/apps/remix-ide/src/app/components/vertical-icons.js b/apps/remix-ide/src/app/components/vertical-icons.js index 7ff9009ac4..35b9f0ac17 100644 --- a/apps/remix-ide/src/app/components/vertical-icons.js +++ b/apps/remix-ide/src/app/components/vertical-icons.js @@ -64,7 +64,7 @@ export class VerticalIcons extends Plugin { * Add an icon to the map * @param {ModuleProfile} profile The profile of the module */ - addIcon ({ kind, name, icon, displayName, tooltip }) { + addIcon ({ kind, name, icon, displayName, tooltip, documentation }) { let title = (tooltip || displayName || name) title = title.replace(/^\w/, c => c.toUpperCase()) this.icons[name] = yo` @@ -73,7 +73,7 @@ export class VerticalIcons extends Plugin { onclick="${() => { this.toggle(name) }}" plugin="${name}" title="${title}" - oncontextmenu="${(e) => this.itemContextMenu(e, name)}" + oncontextmenu="${(e) => this.itemContextMenu(e, name, documentation)}" data-id="verticalIconsKind${name}"> ${name}
    ` @@ -223,13 +223,24 @@ export class VerticalIcons extends Plugin { } } - itemContextMenu (e, name) { - console.log(name) - VERTICALMENU_HANDLE && VERTICALMENU_HANDLE.hide(null, true) + async itemContextMenu (e, name, documentation) { const actions = {} - actions['Deactivate'] = () => { this.call('manager', 'deactivatePlugin', name) } - VERTICALMENU_HANDLE = contextMenu(e, actions) + if (await this.appManager.canDeactivatePlugin(profile, { name })) { + actions.Deactivate = () => { + // this.call('manager', 'deactivatePlugin', name) + this.appManager.deactivatePlugin(name) + } + } + const links = {} + if (documentation) { + links.Documentation = documentation + } + if (Object.keys(actions).length || Object.keys(links).length) { + VERTICALMENU_HANDLE && VERTICALMENU_HANDLE.hide(null, true) + VERTICALMENU_HANDLE = contextMenu(e, actions, links) + } e.preventDefault() + e.stopPropagation() } render () { diff --git a/apps/remix-ide/src/app/ui/contextMenu.js b/apps/remix-ide/src/app/ui/contextMenu.js index f97720c6cd..148261ee5b 100644 --- a/apps/remix-ide/src/app/ui/contextMenu.js +++ b/apps/remix-ide/src/app/ui/contextMenu.js @@ -30,7 +30,7 @@ var css = csjs` } ` -module.exports = (event, items) => { +module.exports = (event, items, linkItems) => { event.preventDefault() function hide (event, force) { @@ -45,7 +45,17 @@ module.exports = (event, items) => { current.onclick = () => { hide(null, true); items[item]() } return current }) - const container = yo`` + + const menuForLinks = Object.keys(linkItems).map((item, index) => { + const current = yo`
  • ` + current.onclick = () => { hide(null, true) } + return current + }) + const container = yo` + + ` container.style.left = event.pageX + 'px' container.style.top = event.pageY + 'px' diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index 93af43107f..f985f793ce 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -6,12 +6,12 @@ import QueryParams from './lib/query-params' import { PermissionHandler } from './app/ui/persmission-handler' const requiredModules = [ // services + layout views + system views - 'manager', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', 'fileManager', 'contentImport', 'web3Provider', 'scriptRunner', 'fetchAndCompile', - 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons', 'fileExplorers', - 'terminal', 'settings', 'pluginManager', 'tabs'] + 'manager', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme', + 'fileManager', 'contentImport', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons', + 'fileExplorers', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp'] export function isNative (name) { - const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd'] + const nativePlugins = ['vyper', 'workshops', 'debugger', 'remixd', 'menuicons'] return nativePlugins.includes(name) || requiredModules.includes(name) } From 17e490f923d901e0bf8079d25c48231ec92d8b51 Mon Sep 17 00:00:00 2001 From: LianaHus Date: Tue, 12 Jan 2021 14:32:20 +0100 Subject: [PATCH 95/99] checked if liks are given --- apps/remix-ide/src/app/ui/contextMenu.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/apps/remix-ide/src/app/ui/contextMenu.js b/apps/remix-ide/src/app/ui/contextMenu.js index 148261ee5b..334c720e1f 100644 --- a/apps/remix-ide/src/app/ui/contextMenu.js +++ b/apps/remix-ide/src/app/ui/contextMenu.js @@ -46,11 +46,15 @@ module.exports = (event, items, linkItems) => { return current }) - const menuForLinks = Object.keys(linkItems).map((item, index) => { - const current = yo`` - current.onclick = () => { hide(null, true) } - return current - }) + let menuForLinks = yo`` + if (linkItems) { + menuForLinks = Object.keys(linkItems).map((item, index) => { + const current = yo`` + current.onclick = () => { hide(null, true) } + return current + }) + } + const container = yo`