pull/5370/head
filip mertens 11 months ago
parent 8e5552fd5f
commit 2591c16f54
  1. 20
      apps/remix-ide/src/app/panels/file-panel.js
  2. 7
      apps/remix-ide/webpack.config.js
  3. 1
      apps/remixdesktop/package.json
  4. 3
      apps/remixdesktop/src/utils/config.ts
  5. 110
      apps/remixdesktop/yarn.lock
  6. 2
      libs/remix-ui/app/src/index.ts
  7. 6
      libs/remix-ui/app/src/lib/remix-app/context/context.tsx
  8. 6
      libs/remix-ui/app/src/lib/remix-app/context/provider.tsx
  9. 143
      libs/remix-ui/app/src/lib/remix-app/remix-app.tsx
  10. 6
      libs/remix-ui/home-tab/src/lib/components/homeTabGetStarted.tsx
  11. 6
      libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx
  12. 26
      libs/remix-ui/panel/src/lib/main/main-panel.tsx
  13. 4
      libs/remix-ui/plugin-manager/src/lib/components/InactivePluginCard.tsx
  14. 6
      libs/remix-ui/search/src/lib/components/Search.tsx
  15. 7
      libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx
  16. 7
      libs/remix-ui/solidity-compiler/src/lib/components/compiler-dropdown.tsx
  17. 6
      libs/remix-ui/solidity-unit-testing/src/lib/solidity-unit-testing.tsx
  18. 2
      libs/remix-ui/tree-view/src/lib/remix-ui-tree-view.tsx
  19. 1
      libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx
  20. 4
      libs/remix-ui/vertical-icons-panel/src/lib/remix-ui-vertical-icons-panel.tsx
  21. 2
      libs/remix-ui/workspace/src/lib/actions/events.ts
  22. 6
      libs/remix-ui/workspace/src/lib/components/electron-menu.tsx
  23. 17
      libs/remix-ui/workspace/src/lib/components/file-blok.tsx
  24. 6
      libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx
  25. 15
      libs/remix-ui/workspace/src/lib/components/file-explorer-new.tsx
  26. 233
      libs/remix-ui/workspace/src/lib/components/file-explorer.tsx
  27. 210
      libs/remix-ui/workspace/src/lib/components/file-recursive-tree.tsx
  28. 5
      libs/remix-ui/workspace/src/lib/components/workspace-hamburger-item.tsx
  29. 20
      libs/remix-ui/workspace/src/lib/reducers/workspace.ts
  30. 22
      libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx

@ -5,6 +5,7 @@ import React from 'react' // eslint-disable-line
import { FileSystemProvider } from '@remix-ui/workspace' // eslint-disable-line
import {Registry} from '@remix-project/remix-lib'
import { RemixdHandle } from '../plugins/remixd-handle'
import {PluginViewWrapper} from '@remix-ui/helper'
const { HardhatHandle } = require('../files/hardhat-handle.js')
const { FoundryHandle } = require('../files/foundry-handle.js')
const { TruffleHandle } = require('../files/truffle-handle.js')
@ -77,13 +78,30 @@ module.exports = class Filepanel extends ViewPlugin {
this.expandPath = []
}
setDispatch(dispatch) {
this.dispatch = dispatch
this.renderComponent()
}
render() {
return (
<div id="fileExplorerView">
<FileSystemProvider plugin={this} />
<PluginViewWrapper plugin={this} />
</div>
)
}
updateComponent(state) {
console.log('updateComponent', state)
return (
<FileSystemProvider plugin={state.plugin} />
)
}
renderComponent() {
this.dispatch({
plugin: this,
})
}
/**
* @param item { id: string, name: string, type?: string[], path?: string[], extension?: string[], pattern?: string[] }

@ -77,6 +77,13 @@ module.exports = composePlugins(withNx(), withReact(), (config) => {
solc: 'solc'
}
// set alias
config.resolve.alias = {
...config.resolve.alias,
'react-dom$': 'react-dom/profiling',
}
// add public path
if(process.env.NX_DESKTOP_FROM_DIST){
config.output.publicPath = './'

@ -36,6 +36,7 @@
"cross-env": "^7.0.3",
"electron": "^25.0.1",
"electron-builder": "^23.6.0",
"electron-devtools-installer": "^3.2.0",
"typescript": "^5.1.3",
"yarn": "^1.22.21"
},

@ -15,6 +15,7 @@ export const createDefaultConfigLocations = async() => {
fs.mkdirSync(cacheDir + '/compilers')
}
if (!fs.existsSync(cacheDir + '/remixdesktop.json')) {
console.log('create config file')
fs.writeFileSync(cacheDir + '/remixdesktop.json', JSON.stringify({}))
}
} catch (e) {
@ -26,6 +27,7 @@ export const writeConfig = async (data: any) => {
await createDefaultConfigLocations()
const cache = readConfig()
try {
console.log('write config file', data)
fs.writeFileSync(cacheDir + '/remixdesktop.json', JSON.stringify({ ...cache, ...data }))
} catch (e) {
console.error('Can\'t write config file', e)
@ -39,6 +41,7 @@ export const readConfig = async () => {
// read the cache file
const cache = fs.readFileSync(cacheDir + '/remixdesktop.json')
const data = JSON.parse(cache.toString())
console.log('read config file', data)
return data
} catch (e) {
console.error('Can\'t read config file', e)

@ -1719,6 +1719,11 @@ core-util-is@1.0.2:
resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz"
integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==
core-util-is@~1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
cors@^2.8.1:
version "2.8.5"
resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
@ -2002,6 +2007,16 @@ electron-builder@^23.6.0:
simple-update-notifier "^1.0.7"
yargs "^17.5.1"
electron-devtools-installer@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/electron-devtools-installer/-/electron-devtools-installer-3.2.0.tgz#acc48d24eb7033fe5af284a19667e73b78d406d0"
integrity sha512-t3UczsYugm4OAbqvdImMCImIMVdFzJAHgbwHpkl5jmfu1izVgUcP/mnrPqJIpEeCK1uZGpt+yHgWEN+9EwoYhQ==
dependencies:
rimraf "^3.0.2"
semver "^7.2.1"
tslib "^2.1.0"
unzip-crx-3 "^0.2.0"
electron-osx-sign@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/electron-osx-sign/-/electron-osx-sign-0.6.0.tgz#9b69c191d471d9458ef5b1e4fdd52baa059f1bb8"
@ -3030,6 +3045,11 @@ ignore@^5.1.4:
resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz"
integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==
immediate@~3.0.5:
version "3.0.6"
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz"
@ -3048,7 +3068,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4:
inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@ -3249,6 +3269,11 @@ isarray@^2.0.5:
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723"
integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==
isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==
isbinaryfile@^3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80"
@ -3380,6 +3405,16 @@ jsprim@^1.2.2:
json-schema "0.4.0"
verror "1.10.0"
jszip@^3.1.0:
version "3.10.1"
resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2"
integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==
dependencies:
lie "~3.3.0"
pako "~1.0.2"
readable-stream "~2.3.6"
setimmediate "^1.0.5"
keccak@^3.0.0:
version "3.0.4"
resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.4.tgz#edc09b89e633c0549da444432ecf062ffadee86d"
@ -3401,6 +3436,13 @@ lazy-val@^1.0.4, lazy-val@^1.0.5:
resolved "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz"
integrity sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==
lie@~3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a"
integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==
dependencies:
immediate "~3.0.5"
lodash@^4.17.15:
version "4.17.21"
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
@ -3683,7 +3725,7 @@ mkdirp@*:
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50"
integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==
mkdirp@^0.5.5:
mkdirp@^0.5.1, mkdirp@^0.5.5:
version "0.5.6"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
@ -3960,7 +4002,7 @@ p-map@^4.0.0:
dependencies:
aggregate-error "^3.0.0"
pako@^1.0.10:
pako@^1.0.10, pako@~1.0.2:
version "1.0.11"
resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz"
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
@ -4046,6 +4088,11 @@ plist@^3.0.4:
base64-js "^1.5.1"
xmlbuilder "^15.1.1"
process-nextick-args@~2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
process@^0.11.10:
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
@ -4190,6 +4237,19 @@ readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
readable-stream@~2.3.6:
version "2.3.8"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b"
integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.3"
isarray "~1.0.0"
process-nextick-args "~2.0.0"
safe-buffer "~5.1.1"
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readdirp@~3.6.0:
version "3.6.0"
resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz"
@ -4316,7 +4376,7 @@ safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, s
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
safe-buffer@~5.1.0:
safe-buffer@~5.1.0, safe-buffer@~5.1.1:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
@ -4371,6 +4431,13 @@ semver@^6.2.0:
resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
semver@^7.2.1, semver@^7.3.7, semver@^7.5.4:
version "7.5.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
dependencies:
lru-cache "^6.0.0"
semver@^7.3.2, semver@^7.3.5:
version "7.5.3"
resolved "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz"
@ -4378,13 +4445,6 @@ semver@^7.3.2, semver@^7.3.5:
dependencies:
lru-cache "^6.0.0"
semver@^7.3.7, semver@^7.5.4:
version "7.5.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
dependencies:
lru-cache "^6.0.0"
semver@~7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
@ -4678,6 +4738,13 @@ string_decoder@^1.1.1:
dependencies:
safe-buffer "~5.2.0"
string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
dependencies:
safe-buffer "~5.1.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
@ -4830,6 +4897,11 @@ tslib@2.0.1:
resolved "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz"
integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==
tslib@^2.1.0:
version "2.6.2"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
tunnel-agent@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
@ -4960,6 +5032,15 @@ unpipe@1.0.0, unpipe@~1.0.0:
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
unzip-crx-3@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/unzip-crx-3/-/unzip-crx-3-0.2.0.tgz#d5324147b104a8aed9ae8639c95521f6f7cda292"
integrity sha512-0+JiUq/z7faJ6oifVB5nSwt589v1KCduqIJupNVDoWSXZtWDmjDGO3RAEOvwJ07w90aoXoP4enKsR7ecMrJtWQ==
dependencies:
jszip "^3.1.0"
mkdirp "^0.5.1"
yaku "^0.16.6"
uri-js@^4.2.2:
version "4.4.1"
resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz"
@ -4997,7 +5078,7 @@ utf8@3.0.0:
resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1"
integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==
util-deprecate@^1.0.1:
util-deprecate@^1.0.1, util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
@ -5446,6 +5527,11 @@ yaeti@^0.0.6:
resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577"
integrity sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==
yaku@^0.16.6:
version "0.16.7"
resolved "https://registry.yarnpkg.com/yaku/-/yaku-0.16.7.tgz#1d195c78aa9b5bf8479c895b9504fd4f0847984e"
integrity sha512-Syu3IB3rZvKvYk7yTiyl1bo/jiEFaaStrgv1V2TIJTqYPStSMQVO8EQjg/z+DRzLq/4LIIharNT3iH1hylEIRw==
yallist@^3.0.0, yallist@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"

@ -1,5 +1,5 @@
export { default as RemixApp } from './lib/remix-app/remix-app'
export { dispatchModalContext, dispatchModalInterface, AppContext, appProviderContextType, appPlatformTypes } from './lib/remix-app/context/context'
export { dispatchModalContext, dispatchModalInterface, AppContext, appProviderContextType, appPlatformTypes, platformContext, onLineContext } from './lib/remix-app/context/context'
export { ModalProvider, useDialogDispatchers } from './lib/remix-app/context/provider'
export { AppModal } from './lib/remix-app/interface/index'
export { AlertModal } from './lib/remix-app/interface/index'

@ -8,9 +8,6 @@ export type appProviderContextType = {
showEnter: boolean,
appManager: any
modal: any
layout: any
platform: appPlatformTypes
online: boolean
}
export enum appPlatformTypes {
@ -18,8 +15,9 @@ export enum appPlatformTypes {
desktop = 'desktop'
}
export const AppContext = React.createContext<appProviderContextType>(null)
export const onLineContext = React.createContext<boolean>(null)
export const platformContext = React.createContext<appPlatformTypes>(null)
export interface dispatchModalInterface {
modal: (data: AppModal) => void

@ -4,7 +4,7 @@ import {AlertModal, AppModal} from '../interface'
import {modalReducer} from '../reducer/modals'
import {ModalInitialState} from '../state/modals'
import {ModalTypes} from '../types'
import {AppContext, dispatchModalContext, modalContext} from './context'
import {AppContext, dispatchModalContext, modalContext, platformContext, onLineContext} from './context'
export const ModalProvider = ({children = [], reducer = modalReducer, initialState = ModalInitialState} = {}) => {
const [{modals, toasters, focusModal, focusToaster}, dispatch] = useReducer(reducer, initialState)
@ -83,7 +83,9 @@ export const ModalProvider = ({children = [], reducer = modalReducer, initialSta
export const AppProvider = ({children = [], value = {}} = null) => {
return (
<AppContext.Provider value={value}>
<ModalProvider>{children}</ModalProvider>
<ModalProvider>
{children}
</ModalProvider>
</AppContext.Provider>
)
}

@ -1,17 +1,17 @@
import React, {useEffect, useRef, useState} from 'react'
import React, { useEffect, useRef, useState } from 'react'
import './style/remix-app.css'
import {RemixUIMainPanel} from '@remix-ui/panel'
import { RemixUIMainPanel } from '@remix-ui/panel'
import MatomoDialog from './components/modals/matomo'
import EnterDialog from './components/modals/enter'
import OriginWarning from './components/modals/origin-warning'
import DragBar from './components/dragbar/dragbar'
import {AppProvider} from './context/provider'
import { AppProvider } from './context/provider'
import AppDialogs from './components/modals/dialogs'
import DialogViewPlugin from './components/modals/dialogViewPlugin'
import { AppContext, appProviderContextType } from './context/context'
import { AppContext, appProviderContextType, onLineContext, platformContext } from './context/context'
import { FormattedMessage, IntlProvider } from 'react-intl'
import {CustomTooltip} from '@remix-ui/helper'
import {UsageTypes} from './types'
import { CustomTooltip } from '@remix-ui/helper'
import { UsageTypes } from './types'
declare global {
interface Window {
@ -30,7 +30,7 @@ const RemixApp = (props: IRemixAppUi) => {
const [maximiseTrigger, setMaximiseTrigger] = useState<number>(0)
const [resetTrigger, setResetTrigger] = useState<number>(0)
const [online, setOnline] = useState<boolean>(true)
const [locale, setLocale] = useState<{code: string; messages: any}>({
const [locale, setLocale] = useState<{ code: string; messages: any }>({
code: 'en',
messages: {}
})
@ -60,7 +60,7 @@ const RemixApp = (props: IRemixAppUi) => {
if (!hadUsageTypeAsked && props.app.matomoCurrentSetting) {
setShowEnterDialog(true)
}
}
}
}, [])
function setListeners() {
@ -106,9 +106,6 @@ const RemixApp = (props: IRemixAppUi) => {
appManager: props.app.appManager,
showEnter: props.app.showEnter,
modal: props.app.notification,
layout: props.app.layout,
platform: props.app.platform,
online: online
}
const handleUserChosenType = async (type) => {
@ -119,31 +116,31 @@ const RemixApp = (props: IRemixAppUi) => {
// Use the type to setup the UI accordingly
switch (type) {
case UsageTypes.Beginner: {
await props.app.appManager.call('manager', 'activatePlugin', 'LearnEth')
// const wName = 'Playground'
// const workspaces = await props.app.appManager.call('filePanel', 'getWorkspaces')
// if (!workspaces.find((workspace) => workspace.name === wName)) {
// await props.app.appManager.call('filePanel', 'createWorkspace', wName, 'playground')
// }
// await props.app.appManager.call('filePanel', 'switchToWorkspace', { name: wName, isLocalHost: false })
_paq.push(['trackEvent', 'enterDialog', 'usageType', 'beginner'])
break
}
case UsageTypes.Advance: {
_paq.push(['trackEvent', 'enterDialog', 'usageType', 'tutor'])
break
}
case UsageTypes.Prototyper: {
_paq.push(['trackEvent', 'enterDialog', 'usageType', 'prototyper'])
break
}
case UsageTypes.Production: {
_paq.push(['trackEvent', 'enterDialog', 'usageType', 'production'])
break
}
default: throw new Error()
case UsageTypes.Beginner: {
await props.app.appManager.call('manager', 'activatePlugin', 'LearnEth')
// const wName = 'Playground'
// const workspaces = await props.app.appManager.call('filePanel', 'getWorkspaces')
// if (!workspaces.find((workspace) => workspace.name === wName)) {
// await props.app.appManager.call('filePanel', 'createWorkspace', wName, 'playground')
// }
// await props.app.appManager.call('filePanel', 'switchToWorkspace', { name: wName, isLocalHost: false })
_paq.push(['trackEvent', 'enterDialog', 'usageType', 'beginner'])
break
}
case UsageTypes.Advance: {
_paq.push(['trackEvent', 'enterDialog', 'usageType', 'tutor'])
break
}
case UsageTypes.Prototyper: {
_paq.push(['trackEvent', 'enterDialog', 'usageType', 'prototyper'])
break
}
case UsageTypes.Production: {
_paq.push(['trackEvent', 'enterDialog', 'usageType', 'production'])
break
}
default: throw new Error()
}
}
@ -151,41 +148,45 @@ const RemixApp = (props: IRemixAppUi) => {
return (
//@ts-ignore
<IntlProvider locale={locale.code} messages={locale.messages}>
<AppProvider value={value}>
<OriginWarning></OriginWarning>
<MatomoDialog hide={!appReady} okFn={() => setShowEnterDialog(true)}></MatomoDialog>
{showEnterDialog && <EnterDialog handleUserChoice={(type) => handleUserChosenType(type)}></EnterDialog>}
<div className={`remixIDE ${appReady ? '' : 'd-none'}`} data-id="remixIDE">
<div id="icon-panel" data-id="remixIdeIconPanel" className="custom_icon_panel iconpanel bg-light">
{props.app.menuicons.render()}
</div>
<div
ref={sidePanelRef}
id="side-panel"
data-id="remixIdeSidePanel"
className={`sidepanel border-right border-left ${hideSidePanel ? 'd-none' : ''}`}
>
{props.app.sidePanel.render()}
</div>
<DragBar
resetTrigger={resetTrigger}
maximiseTrigger={maximiseTrigger}
minWidth={285}
refObject={sidePanelRef}
hidden={hideSidePanel}
setHideStatus={setHideSidePanel}
></DragBar>
<div id="main-panel" data-id="remixIdeMainPanel" className="mainpanel d-flex">
<RemixUIMainPanel Context={AppContext}></RemixUIMainPanel>
<CustomTooltip placement="bottom" tooltipId="overlay-tooltip-all-tabs" tooltipText={<FormattedMessage id="remixApp.scrollToSeeAllTabs" />}>
<div className="remix-ui-tabs_end remix-bg-opacity position-absolute position-fixed"></div>
</CustomTooltip>
</div>
</div>
<div>{props.app.hiddenPanel.render()}</div>
<AppDialogs></AppDialogs>
<DialogViewPlugin></DialogViewPlugin>
</AppProvider>
<platformContext.Provider value={props.app.platform}>
<onLineContext.Provider value={online}>
<AppProvider value={value}>
<OriginWarning></OriginWarning>
<MatomoDialog hide={!appReady} okFn={() => setShowEnterDialog(true)}></MatomoDialog>
{showEnterDialog && <EnterDialog handleUserChoice={(type) => handleUserChosenType(type)}></EnterDialog>}
<div className={`remixIDE ${appReady ? '' : 'd-none'}`} data-id="remixIDE">
<div id="icon-panel" data-id="remixIdeIconPanel" className="custom_icon_panel iconpanel bg-light">
{props.app.menuicons.render()}
</div>
<div
ref={sidePanelRef}
id="side-panel"
data-id="remixIdeSidePanel"
className={`sidepanel border-right border-left ${hideSidePanel ? 'd-none' : ''}`}
>
{props.app.sidePanel.render()}
</div>
<DragBar
resetTrigger={resetTrigger}
maximiseTrigger={maximiseTrigger}
minWidth={285}
refObject={sidePanelRef}
hidden={hideSidePanel}
setHideStatus={setHideSidePanel}
></DragBar>
<div id="main-panel" data-id="remixIdeMainPanel" className="mainpanel d-flex">
<RemixUIMainPanel layout={props.app.layout}></RemixUIMainPanel>
<CustomTooltip placement="bottom" tooltipId="overlay-tooltip-all-tabs" tooltipText={<FormattedMessage id="remixApp.scrollToSeeAllTabs" />}>
<div className="remix-ui-tabs_end remix-bg-opacity position-absolute position-fixed"></div>
</CustomTooltip>
</div>
</div>
<div>{props.app.hiddenPanel.render()}</div>
<AppDialogs></AppDialogs>
<DialogViewPlugin></DialogViewPlugin>
</AppProvider>
</onLineContext.Provider>
</platformContext.Provider>
</IntlProvider>
)
}

@ -7,7 +7,9 @@ import Carousel from 'react-multi-carousel'
import WorkspaceTemplate from './workspaceTemplate'
import 'react-multi-carousel/lib/styles.css'
import CustomNavButtons from './customNavButtons'
import { AppContext, appPlatformTypes } from '@remix-ui/app'
import { appPlatformTypes, platformContext } from '@remix-ui/app'
declare global {
interface Window {
_paq: any
@ -19,7 +21,7 @@ interface HomeTabGetStartedProps {
}
function HomeTabGetStarted({plugin}: HomeTabGetStartedProps) {
const {platform} = useContext(AppContext)
const platform = useContext(platformContext)
const themeFilter = useContext(ThemeContext)
const carouselRef = useRef<any>({})
const carouselRefDiv = useRef(null)

@ -9,10 +9,12 @@ import HomeTabScamAlert from './components/homeTabScamAlert'
import HomeTabGetStarted from './components/homeTabGetStarted'
import HomeTabFeatured from './components/homeTabFeatured'
import HomeTabFeaturedPlugins from './components/homeTabFeaturedPlugins'
import { AppContext, appPlatformTypes } from '@remix-ui/app'
import { appPlatformTypes, platformContext } from '@remix-ui/app'
import { HomeTabFileElectron } from './components/homeTabFileElectron'
import { LanguageOptions } from './components/homeTablangOptions'
declare global {
interface Window {
_paq: any
@ -24,7 +26,7 @@ export interface RemixUiHomeTabProps {
}
export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => {
const {platform} = useContext(AppContext)
const platform = useContext(platformContext)
const {plugin} = props
const [state, setState] = useState<{

@ -3,17 +3,19 @@ import React, {useContext, useEffect, useRef, useState} from 'react' // eslint-d
import DragBar from '../dragbar/dragbar'
import RemixUIPanelPlugin from '../plugins/panel-plugin'
import {PluginRecord} from '../types'
import { AppContext, appPlatformTypes } from '@remix-ui/app'
import { appPlatformTypes, platformContext } from '@remix-ui/app'
import './main-panel.css'
export type RemixUIMainPanelProps = {
Context: React.Context<any>
layout: any
}
const RemixUIMainPanel = (props: RemixUIMainPanelProps) => {
const {platform} = useContext(AppContext)
const appContext = useContext(props.Context)
const platform = useContext(platformContext)
const {layout} = props
const [plugins, setPlugins] = useState<PluginRecord[]>([])
const editorRef = useRef<HTMLDivElement>(null)
const mainPanelRef = useRef<HTMLDivElement>(null)
@ -23,9 +25,9 @@ const RemixUIMainPanel = (props: RemixUIMainPanelProps) => {
const refs = [tabsRef, editorRef, mainPanelRef, terminalRef]
const renderPanels = () => {
if (appContext) {
if (layout.panels) {
const pluginPanels: PluginRecord[] = []
Object.values(appContext.layout.panels).map((panel: any) => {
Object.values(layout.panels).map((panel: any) => {
pluginPanels.push({
profile: panel.plugin.profile,
active: panel.active,
@ -40,23 +42,23 @@ const RemixUIMainPanel = (props: RemixUIMainPanelProps) => {
useEffect(() => {
renderPanels()
appContext.layout.event.on('change', () => {
layout.event.on('change', () => {
renderPanels()
})
return () => {
appContext.layout.event.off('change')
layout.event.off('change')
}
}, [])
const showTerminal = (hide: boolean) => {
appContext.layout.panels.terminal.minimized = hide
appContext.layout.event.emit('change', appContext.layout.panels)
appContext.layout.emit('change', appContext.layout.panels)
layout.panels.terminal.minimized = hide
layout.event.emit('change', layout.panels)
layout.emit('change', layout.panels)
}
const resize = (height: number) => {
appContext.layout.emit('resize', height)
layout.emit('resize', height)
}
return (

@ -4,7 +4,7 @@ import React, { useContext, useEffect, useState } from 'react'
import {FormattedMessage, useIntl} from 'react-intl'
import '../remix-ui-plugin-manager.css'
import {CustomTooltip} from '@remix-ui/helper'
import { AppContext } from '@remix-ui/app'
import { AppContext, onLineContext } from '@remix-ui/app'
interface PluginCardProps {
profile: any
buttonText: string
@ -12,7 +12,7 @@ interface PluginCardProps {
}
function InactivePluginCard({profile, buttonText, activatePlugin}: PluginCardProps) {
const {online} = useContext(AppContext)
const online = useContext(onLineContext)
const [canBeActivated, setCanBeActivated] = useState(false)
const intl = useIntl()
useEffect(() => {

@ -6,11 +6,13 @@ import {Include} from './Include'
import {Exclude} from './Exclude'
import {FindContainer} from './FindContainer'
import {Undo} from './Undo'
import { AppContext } from '@remix-ui/app'
import { appPlatformTypes, platformContext } from '@remix-ui/app'
export const SearchTab = (props) => {
const plugin = props.plugin
const {platform} = useContext(AppContext)
const platform = useContext(platformContext)
return (
<>

@ -10,11 +10,13 @@ import {resetEditorMode, listenToEvents} from './actions/compiler'
import {getValidLanguage} from '@remix-project/remix-solidity'
import {CopyToClipboard} from '@remix-ui/clipboard'
import {configFileContent} from './compilerConfiguration'
import { AppContext, appPlatformTypes } from '@remix-ui/app'
import { appPlatformTypes, platformContext, onLineContext } from '@remix-ui/app'
import './css/style.css'
import { CompilerDropdown } from './components/compiler-dropdown'
const defaultPath = 'compiler_config.json'
declare global {
@ -26,7 +28,8 @@ declare global {
const _paq = (window._paq = window._paq || []) //eslint-disable-line
export const CompilerContainer = (props: CompilerContainerProps) => {
const {platform, online} = useContext(AppContext)
const online = useContext(onLineContext)
const platform = useContext(platformContext)
const {
api,
compileTabLogic,

@ -1,4 +1,6 @@
import { AppContext, appPlatformTypes } from '@remix-ui/app';
import { appPlatformTypes, platformContext, onLineContext } from '@remix-ui/app';
;
import React, { useEffect, useState, useRef, useReducer, useContext } from 'react' // eslint-disable-line
import { Dropdown } from 'react-bootstrap';
import { CompilerMenu, CompilerMenuToggle } from './compiler-menu';
@ -20,7 +22,8 @@ interface compilerDropdownProps {
}
export const CompilerDropdown = (props: compilerDropdownProps) => {
const {platform, online} = useContext(AppContext)
const online = useContext(onLineContext)
const platform = useContext(platformContext)
const { customVersions, selectedVersion, defaultVersion, allversions, handleLoadVersion, _shouldBeAdded, onlyDownloaded } = props
return (
<Dropdown id="versionSelector" data-id="versionSelector">

@ -9,7 +9,9 @@ import { Toaster } from '@remix-ui/toaster' // eslint-disable-line
import { format } from 'util'
import './css/style.css'
import { CustomTooltip } from '@remix-ui/helper'
import { AppContext, appPlatformTypes } from '@remix-ui/app'
import { appPlatformTypes, platformContext } from '@remix-ui/app'
const _paq = ((window as any)._paq = (window as any)._paq || []) // eslint-disable-line @typescript-eslint/no-explicit-any
@ -44,7 +46,7 @@ interface FinalResult {
export const SolidityUnitTesting = (props: Record<string, any>) => {
// eslint-disable-line @typescript-eslint/no-explicit-any
const {platform} = useContext(AppContext)
const platform = useContext(platformContext)
const { helper, testTab, initialPath } = props
const { testTabLogic } = testTab

@ -1,4 +1,4 @@
import React from 'react' // eslint-disable-line
import React, { useEffect } from 'react' // eslint-disable-line
import {TreeViewProps} from '../types'
import './remix-ui-tree-view.css'

@ -17,7 +17,6 @@ export const TreeViewItem = (props: TreeViewItemProps) => {
key={`treeViewDiv${id}`}
data-id={`treeViewDiv${id}`}
className={`d-flex flex-row align-items-center ${labelClass}`}
onClick={() => !controlBehaviour && setIsExpanded(!isExpanded)}
>
{children && showIcon ? (
<div className={isExpanded ? `pl-2 ${iconY}` : `pl-2 ${iconX} caret caret_tv`} style={{visibility: children ? 'visible' : 'hidden'}}></div>

@ -6,7 +6,7 @@ import Home from './components/Home'
import { verticalScrollReducer } from './reducers/verticalScrollReducer'
import { Chevron } from './components/Chevron'
import { IconRecord } from './types'
import { AppContext } from '@remix-ui/app'
import { onLineContext } from '@remix-ui/app'
import { CustomTooltip } from '@remix-ui/helper'
export interface RemixUiVerticalIconsPanelProps {
verticalIconsPlugin: Plugin
@ -24,7 +24,7 @@ const RemixUiVerticalIconsPanel = ({ verticalIconsPlugin, icons }: RemixUiVertic
const iconPanelRef = useRef<any>()
const [activateScroll, dispatchScrollAction] = useReducer(verticalScrollReducer, initialState)
const [theme, setTheme] = useState<string>('dark')
const { online } = useContext(AppContext)
const online = useContext(onLineContext)
const evaluateScrollability = () => {
dispatchScrollAction({

@ -68,7 +68,7 @@ export const listenOnPluginEvents = (filePanelPlugin) => {
let currentCheck = ''
for (const value of paths) {
currentCheck = currentCheck + '/' + value
await folderAdded(currentCheck)
//await folderAdded(currentCheck)
}
})
}

@ -1,12 +1,14 @@
import React, { MouseEventHandler, useContext, useEffect, useState } from "react"
import { FileSystemContext } from "../contexts"
import { AppContext, appPlatformTypes } from '@remix-ui/app'
import { appPlatformTypes, platformContext } from '@remix-ui/app'
import { FormattedMessage } from "react-intl"
import '../css/electron-menu.css'
import { CustomTooltip } from '@remix-ui/helper'
export const ElectronMenu = () => {
const {platform} = useContext(AppContext)
const platform = useContext(platformContext)
const global = useContext(FileSystemContext)
useEffect(() => {

@ -1,17 +0,0 @@
import { getPathIcon } from '@remix-ui/helper'
import React, { SyntheticEvent, useEffect, useRef, useState } from 'react'
export const FileBlok = (props: any) => {
const { file } = props
const handleFileClick = (event: SyntheticEvent) => {
event.stopPropagation()
props.handleClickFile(file.path, file.type)
}
return (
<>
<div className={`pr-2 pl-2 ${getPathIcon(props.file.path)} caret caret_tv`}></div>
<div onClick={handleFileClick} className="btn">{props.file.name}</div>
</>)
}

@ -5,7 +5,9 @@ import {action, FileExplorerContextMenuProps} from '../types'
import '../css/file-explorer-context-menu.css'
import {customAction} from '@remixproject/plugin-api'
import UploadFile from './upload-file'
import { AppContext, appPlatformTypes } from '@remix-ui/app'
import { appPlatformTypes, platformContext } from '@remix-ui/app'
declare global {
interface Window {
@ -15,7 +17,7 @@ declare global {
const _paq = (window._paq = window._paq || []) //eslint-disable-line
export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => {
const {platform} = useContext(AppContext)
const platform = useContext(platformContext)
const {
actions,
createNewFile,

@ -0,0 +1,15 @@
import { FileType, WorkspaceElement } from "../types";
import React, { useEffect, useState, useRef, SyntheticEvent } from 'react' // eslint-disable-line
import { RecursiveTree } from "./file-recursive-tree";
export const NewFileExplorer = (props: any) => {
useEffect(() => {
console.log('new file explorer props', props)
}, [props])
return (<></>)
}

@ -1,19 +1,19 @@
import React, {useEffect, useState, useRef, SyntheticEvent} from 'react' // eslint-disable-line
import {useIntl} from 'react-intl'
import {TreeView} from '@remix-ui/tree-view' // eslint-disable-line
import {FileExplorerMenu} from './file-explorer-menu' // eslint-disable-line
import {FileExplorerContextMenu} from './file-explorer-context-menu' // eslint-disable-line
import {FileExplorerProps, FileType, WorkSpaceState, WorkspaceElement} from '../types'
import React, { useEffect, useState, useRef, SyntheticEvent } from 'react' // eslint-disable-line
import { useIntl } from 'react-intl'
import { TreeView } from '@remix-ui/tree-view' // eslint-disable-line
import { FileExplorerMenu } from './file-explorer-menu' // eslint-disable-line
import { FileExplorerContextMenu } from './file-explorer-context-menu' // eslint-disable-line
import { FileExplorerProps, FileType, WorkSpaceState, WorkspaceElement } from '../types'
import '../css/file-explorer.css'
import {checkSpecialChars, extractNameFromKey, extractParentFromKey, joinPath} from '@remix-ui/helper'
import { checkSpecialChars, extractNameFromKey, extractParentFromKey, getPathIcon, joinPath } from '@remix-ui/helper'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import {FileRender} from './file-render'
import {Drag, Draggable} from '@remix-ui/drag-n-drop'
import {ROOT_PATH} from '../utils/constants'
import { FileRender } from './file-render'
import { Drag, Draggable } from '@remix-ui/drag-n-drop'
import { ROOT_PATH } from '../utils/constants'
import { fileKeySort } from '../utils'
import { moveFileIsAllowed, moveFolderIsAllowed } from '../actions'
import { FileBlok } from './file-blok'
import { RecursiveTreeItem, RecursiveTree } from './file-recursive-tree'
export const FileExplorer = (props: FileExplorerProps) => {
const intl = useIntl()
@ -74,7 +74,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
const keyPressHandler = (e: KeyboardEvent) => {
if (e.shiftKey) {
setState((prevState) => {
return {...prevState, ctrlKey: true}
return { ...prevState, ctrlKey: true }
})
}
}
@ -82,7 +82,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
const keyUpHandler = (e: KeyboardEvent) => {
if (!e.shiftKey) {
setState((prevState) => {
return {...prevState, ctrlKey: false}
return { ...prevState, ctrlKey: false }
})
}
}
@ -107,10 +107,10 @@ export const FileExplorer = (props: FileExplorerProps) => {
props.dispatchCreateNewFile(newFilePath, ROOT_PATH)
} catch (error) {
return props.modal(
intl.formatMessage({id: 'filePanel.fileCreationFailed'}),
intl.formatMessage({ id: 'filePanel.fileCreationFailed' }),
typeof error === 'string' ? error : error.message,
intl.formatMessage({id: 'filePanel.close'}),
async () => {}
intl.formatMessage({ id: 'filePanel.close' }),
async () => { }
)
}
}
@ -120,10 +120,10 @@ export const FileExplorer = (props: FileExplorerProps) => {
props.dispatchCreateNewFolder(newFolderPath, ROOT_PATH)
} catch (e) {
return props.modal(
intl.formatMessage({id: 'filePanel.folderCreationFailed'}),
intl.formatMessage({ id: 'filePanel.folderCreationFailed' }),
typeof e === 'string' ? e : e.message,
intl.formatMessage({id: 'filePanel.close'}),
async () => {}
intl.formatMessage({ id: 'filePanel.close' }),
async () => { }
)
}
}
@ -133,22 +133,22 @@ export const FileExplorer = (props: FileExplorerProps) => {
props.dispatchRenamePath(oldPath, newPath)
} catch (error) {
props.modal(
intl.formatMessage({id: 'filePanel.renameFileFailed'}),
intl.formatMessage({id: 'filePanel.renameFileFailedMsg'}, {error: typeof error === 'string' ? error : error.message}),
intl.formatMessage({id: 'filePanel.close'}),
async () => {}
intl.formatMessage({ id: 'filePanel.renameFileFailed' }),
intl.formatMessage({ id: 'filePanel.renameFileFailedMsg' }, { error: typeof error === 'string' ? error : error.message }),
intl.formatMessage({ id: 'filePanel.close' }),
async () => { }
)
}
}
const publishToGist = (path?: string, type?: string) => {
props.modal(
intl.formatMessage({id: 'filePanel.createPublicGist'}),
intl.formatMessage({id: 'filePanel.createPublicGistMsg4'}, {name}),
intl.formatMessage({id: 'filePanel.ok'}),
intl.formatMessage({ id: 'filePanel.createPublicGist' }),
intl.formatMessage({ id: 'filePanel.createPublicGistMsg4' }, { name }),
intl.formatMessage({ id: 'filePanel.ok' }),
() => toGist(path, type),
intl.formatMessage({id: 'filePanel.cancel'}),
() => {}
intl.formatMessage({ id: 'filePanel.cancel' }),
() => { }
)
}
@ -165,7 +165,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
return !(el.key === '' && el.type === 'folder')
})
nonRootFocus.push({key: path, type})
nonRootFocus.push({ key: path, type })
props.dispatchSetFocusElement(nonRootFocus)
}
}
@ -182,7 +182,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
return !(el.key === '' && el.type === 'folder')
})
nonRootFocus.push({key: path, type})
nonRootFocus.push({ key: path, type })
props.dispatchSetFocusElement(nonRootFocus)
}
} else {
@ -195,7 +195,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
expandPath = [...new Set(props.expandPath.filter((key) => key && typeof key === 'string' && !key.startsWith(path)))]
}
props.dispatchSetFocusElement([{key: path, type}])
props.dispatchSetFocusElement([{ key: path, type }])
props.dispatchHandleExpandPath(expandPath)
}
}
@ -210,14 +210,14 @@ export const FileExplorer = (props: FileExplorerProps) => {
setState((prevState) => {
return {
...prevState,
focusEdit: {element: null, isNew: false, type: '', lastEdit: ''}
focusEdit: { element: null, isNew: false, type: '', lastEdit: '' }
}
})
} else {
setState((prevState) => {
return {
...prevState,
focusEdit: {element: null, isNew: false, type: '', lastEdit: ''}
focusEdit: { element: null, isNew: false, type: '', lastEdit: '' }
}
})
}
@ -226,26 +226,26 @@ export const FileExplorer = (props: FileExplorerProps) => {
return setState((prevState) => {
return {
...prevState,
focusEdit: {element: null, isNew: false, type: '', lastEdit: ''}
focusEdit: { element: null, isNew: false, type: '', lastEdit: '' }
}
})
}
if (checkSpecialChars(content)) {
props.modal(
intl.formatMessage({id: 'filePanel.validationError'}),
intl.formatMessage({id: 'filePanel.validationErrorMsg'}),
intl.formatMessage({id: 'filePanel.ok'}),
() => {}
intl.formatMessage({ id: 'filePanel.validationError' }),
intl.formatMessage({ id: 'filePanel.validationErrorMsg' }),
intl.formatMessage({ id: 'filePanel.ok' }),
() => { }
)
} else {
if (state.focusEdit.isNew) {
if (hasReservedKeyword(content)) {
props.dispatchRemoveInputField(parentFolder)
props.modal(
intl.formatMessage({id: 'filePanel.reservedKeyword'}),
intl.formatMessage({id: 'filePanel.reservedKeywordMsg'}, {content}),
intl.formatMessage({id: 'filePanel.close'}),
() => {}
intl.formatMessage({ id: 'filePanel.reservedKeyword' }),
intl.formatMessage({ id: 'filePanel.reservedKeywordMsg' }, { content }),
intl.formatMessage({ id: 'filePanel.close' }),
() => { }
)
} else {
state.focusEdit.type === 'file' ? createNewFile(joinPath(parentFolder, content)) : createNewFolder(joinPath(parentFolder, content))
@ -254,10 +254,10 @@ export const FileExplorer = (props: FileExplorerProps) => {
} else {
if (hasReservedKeyword(content)) {
props.modal(
intl.formatMessage({id: 'filePanel.reservedKeyword'}),
intl.formatMessage({id: 'filePanel.reservedKeywordMsg'}, {content}),
intl.formatMessage({id: 'filePanel.close'}),
() => {}
intl.formatMessage({ id: 'filePanel.reservedKeyword' }),
intl.formatMessage({ id: 'filePanel.reservedKeywordMsg' }, { content }),
intl.formatMessage({ id: 'filePanel.close' }),
() => { }
)
} else {
if (state.focusEdit.element) {
@ -272,7 +272,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
setState((prevState) => {
return {
...prevState,
focusEdit: {element: null, isNew: false, type: '', lastEdit: ''}
focusEdit: { element: null, isNew: false, type: '', lastEdit: '' }
}
})
}
@ -294,7 +294,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
}
const handleFileMove = async (dest: string, src: string) => {
if(await moveFileIsAllowed(src, dest) === false) return
if (await moveFileIsAllowed(src, dest) === false) return
try {
props.modal(
intl.formatMessage({ id: 'filePanel.moveFile' }),
@ -302,20 +302,20 @@ export const FileExplorer = (props: FileExplorerProps) => {
intl.formatMessage({ id: 'filePanel.yes' }),
() => props.dispatchMoveFile(src, dest),
intl.formatMessage({ id: 'filePanel.cancel' }),
() => {}
() => { }
)
} catch (error) {
props.modal(
intl.formatMessage({ id: 'filePanel.movingFileFailed' }),
intl.formatMessage({ id: 'filePanel.movingFileFailedMsg' }, { src }),
intl.formatMessage({ id: 'filePanel.close' }),
async () => {}
async () => { }
)
}
}
const handleFolderMove = async (dest: string, src: string) => {
if(await moveFolderIsAllowed(src, dest) === false) return
if (await moveFolderIsAllowed(src, dest) === false) return
try {
props.modal(
intl.formatMessage({ id: 'filePanel.moveFile' }),
@ -323,14 +323,14 @@ export const FileExplorer = (props: FileExplorerProps) => {
intl.formatMessage({ id: 'filePanel.yes' }),
() => props.dispatchMoveFolder(src, dest),
intl.formatMessage({ id: 'filePanel.cancel' }),
() => {}
() => { }
)
} catch (error) {
props.modal(
intl.formatMessage({ id: 'filePanel.movingFolderFailed' }),
intl.formatMessage({ id: 'filePanel.movingFolderFailedMsg' }, { src }),
intl.formatMessage({ id: 'filePanel.close' }),
async () => {}
async () => { }
)
}
}
@ -338,92 +338,93 @@ export const FileExplorer = (props: FileExplorerProps) => {
useEffect(() => {
console.log('fe files changed', ROOT_PATH)
},[files])
}, [files])
useEffect(() => {
console.log('FE RENDER', ROOT_PATH)
},[])
}, [])
const dragStatus = (isDragged: boolean) => {
props.dragStatus(isDragged)
}
useEffect(() => {
console.log('fe props', files)
console.log('fe props', props)
return
console.log('fe props', files[ROOT_PATH])
if (files[ROOT_PATH]){
if (files[ROOT_PATH]) {
try {
const children: FileType[] = files[ROOT_PATH] as any
setChildrenKeys(fileKeySort(children))
} catch (error) {
setChildrenKeys(Object.keys(files[ROOT_PATH]))
}
} else{
} else {
setChildrenKeys([])
}
}, [props])
const handleTreeClick = (e: SyntheticEvent) => {
console.log('tree click', e.target)
// find any parent of e.target that has a data-path attribute
// if found, call handleClickFolder with that path
// if not found, do nothing
let target = e.target as HTMLElement
while (target && target.getAttribute && !target.getAttribute('data-path')) {
target = target.parentElement
}
if (target && target.getAttribute) {
const path = target.getAttribute('data-path')
const type = target.getAttribute('data-type')
if (path && type === 'file') {
console.log('tree click', path)
handleClickFile(path, type as WorkspaceElement)
} else if (path && type === 'folder') {
console.log('tree click', path)
handleClickFolder(path, type)
}
}
}
return (
<Drag onFileMoved={handleFileMove} onFolderMoved={handleFolderMove} dragStatus={dragStatus}>
<div ref={treeRef} tabIndex={0} style={{outline: 'none'}}>
<TreeView id="treeView">
<li key={`treeViewLiMenu`} data-id={`treeViewLiMenu`} className="li_tv">
<div
key={`treeViewDivMenu`}
data-id={`treeViewDivMenu`}
className={`d-flex flex-row align-items-center`}
>
<span className="w-100 pl-2 mt-1">
<div onClick={handleFileExplorerMenuClick}>
<FileExplorerMenu
title={''}
menuItems={props.menuItems}
createNewFile={handleNewFileInput}
createNewFolder={handleNewFolderInput}
publishToGist={publishToGist}
uploadFile={uploadFile}
uploadFolder={uploadFolder}
/>
</div>
</span>
</div>
</li>
<div>
<TreeView id="treeViewMenu">
{files[ROOT_PATH] &&
Object.keys(files[ROOT_PATH]).map((key, index) => (
<>
<FileRender
file={files[ROOT_PATH][key]}
fileDecorations={fileState}
index={index}
focusContext={state.focusContext}
focusEdit={state.focusEdit}
focusElement={props.focusElement}
ctrlKey={state.ctrlKey}
expandPath={props.expandPath}
editModeOff={editModeOff}
handleClickFile={handleClickFile}
handleClickFolder={handleClickFolder}
handleContextMenu={handleContextMenu}
key={index}
showIconsMenu={props.showIconsMenu}
hideIconsMenu={props.hideIconsMenu}
dragStatus={state.dragStatus}
/>
</>
))
}
</TreeView>
<div ref={treeRef} tabIndex={0} style={{ outline: 'none' }}>
<TreeView id="treeView">
<li key={`treeViewLiMenu`} data-id={`treeViewLiMenu`} className="li_tv">
<div
key={`treeViewDivMenu`}
data-id={`treeViewDivMenu`}
className={`d-flex flex-row align-items-center`}
>
<span className="w-100 pl-2 mt-1">
<div onClick={handleFileExplorerMenuClick}>
<FileExplorerMenu
title={''}
menuItems={props.menuItems}
createNewFile={handleNewFileInput}
createNewFolder={handleNewFolderInput}
publishToGist={publishToGist}
uploadFile={uploadFile}
uploadFolder={uploadFolder}
/>
</div>
</span>
</div>
</li>
<div>
<div onClick={handleTreeClick}>
<RecursiveTree handleContextMenu={handleContextMenu} expandPath={props.expandPath} files={files} />
</div>
<Draggable isDraggable={false} file={{ name: '/', path: '/', type: 'folder', isDirectory: true }} expandedPath={props.expandPath} handleClickFolder={null}>
<div className='d-block w-100 pb-4 mb-4'></div>
</Draggable>
</TreeView>
</div>
</Drag>
</div>
<Draggable isDraggable={false} file={{ name: '/', path: '/', type: 'folder', isDirectory: true }} expandedPath={props.expandPath} handleClickFolder={null}>
<div className='d-block w-100 pb-4 mb-4'></div>
</Draggable>
</TreeView>
</div>
)
}

@ -0,0 +1,210 @@
import { CustomTooltip, getPathIcon } from '@remix-ui/helper'
import e from 'express'
import React, { SyntheticEvent, useEffect, useRef, useState } from 'react'
import { Overlay, OverlayTrigger, Popover, Tooltip } from 'react-bootstrap'
import { FileType } from '../types'
import { ROOT_PATH } from '../utils/constants'
interface RecursiveTreeProps {
files: { [x: string]: Record<string, FileType> },
expandPath: string[],
handleContextMenu: (pageX: number, pageY: number, path: string, content: string, type: string) => void
}
let mouseTimer: any = {
path: null,
timer: null
}
export const RecursiveTree = (props: RecursiveTreeProps) => {
const { files, expandPath } = props
const ref = useRef(null)
const [mouseOverTarget, setMouseOverTarget] = useState<{
path: string,
type: string,
content: string,
position: {
top: number,
left: number
}
}>(null)
const [showMouseOverTarget, setShowMouseOverTarget] = useState<boolean>(false)
useEffect(() => {
console.log('EXPAND', expandPath)
//files[ROOT_PATH] && Object.keys(files[ROOT_PATH]).map((key, index) => {
// console.log('recursive tree', files[ROOT_PATH][key])
//})
}, [expandPath])
const getEventTarget = async (e: any, useLabel: boolean = false) => {
let target = e.target as HTMLElement
while (target && target.getAttribute && !target.getAttribute(useLabel? 'data-label-path' : 'data-path')) {
target = target.parentElement
}
if (target && target.getAttribute) {
const path = target.getAttribute(useLabel? 'data-label-path' : 'data-path')
const type = target.getAttribute(useLabel? 'data-label-type' : 'data-type')
let position = target.getBoundingClientRect()
// get size of element
const endPosition = {
top: position.top - position.height * 2 + 4,
left: position.left ,
}
const content = target.textContent
return {
path,
type,
content,
position: endPosition
}
}
}
const handleContextMenu = async (e: any) => {
e.preventDefault()
e.stopPropagation()
console.log('context menu', e)
const target = await getEventTarget(e)
if (target) {
props.handleContextMenu(e.pageX, e.pageY, target.path, target.content, target.type)
}
}
const onDragEnd = (event: SyntheticEvent) => {
console.log('drag end', event)
}
const onDrop = async (event: SyntheticEvent) => {
event.preventDefault()
console.log('drop', event)
const target = await getEventTarget(event)
console.log('drop', target)
}
const onDragOver = async (e: SyntheticEvent) => {
e.preventDefault()
//console.log('drag over', e)
const target = await getEventTarget(e)
//console.log('drag over', target)
}
const onMouseMove = async (e: any) => {
///console.log('mouse move', e)
const target = await getEventTarget(e, true)
if (target && target.path) {
if (mouseTimer.path !== target.path) {
//console.log('set timer', target)
setShowMouseOverTarget(false)
mouseTimer = {
path: target.path,
timer: setTimeout(() => {
if (mouseTimer.path === target.path) {
setShowMouseOverTarget(true)
setMouseOverTarget(target)
}
}, 1000)
}
}
} else {
mouseTimer = {
path: null,
timer: null
}
setShowMouseOverTarget(false)
}
}
const onMouseLeave = async (e: any) => {
mouseTimer = {
path: null,
timer: null
}
setShowMouseOverTarget(false)
}
useEffect(() => {
console.log('show mouse over target', showMouseOverTarget)
}, [showMouseOverTarget])
return (
<div onMouseLeave={onMouseLeave} onMouseMove={onMouseMove} onDrop={onDrop} onDragOver={onDragOver} onContextMenu={handleContextMenu}>
{showMouseOverTarget && mouseOverTarget &&
<Popover id='popover-basic'
className='text-wrap bg-secondary'
placement='top'
ref={ref}
style={
{
position: 'fixed',
top: `${mouseOverTarget.position.top}px`,
left: `${mouseOverTarget.position.left}px`,
minWidth: 'fit-content'
}
}>
<Popover.Content className='py-1'>
{mouseOverTarget && mouseOverTarget.path}
</Popover.Content>
</Popover>
}
<ul className="ul_tv ml-0 pl-1" >{files[ROOT_PATH] &&
Object.keys(files[ROOT_PATH]).map((key, index) => {
return (<RecursiveTreeItem
expandPath={expandPath}
key={index}
file={files[ROOT_PATH][key]}
/>)
})}
</ul>
</div>
)
}
interface RecursiveTreeItemProps {
file: FileType
expandPath?: string[]
}
export const RecursiveTreeItem = (props: RecursiveTreeItemProps) => {
const [hover, setHover] = useState<boolean>(false)
const { file, expandPath } = props
const labelClass =
hover
? 'bg-light border-no-shift'
: ''
return (
<>
<li ref={null} key={`treeViewLi${file.path}`} data-type={file.isDirectory ? 'folder' : 'file'} data-path={`${file.path}`} data-id={`treeViewLi${file.path}`} className="li_tv">
<div
key={`treeViewDiv${file.path}`}
data-id={`treeViewDiv${file.path}`}
className={`d-flex flex-row align-items-center ${labelClass}`}
onMouseOver={() => setHover(true)}
onMouseOut={() => setHover(false)}
>
<div className={`pr-2 pl-2 ${file.isDirectory ? expandPath && expandPath.includes(file.path) ? 'fa fa-folder-open' : 'fa fa-folder' : getPathIcon(file.path)} caret caret_tv`}></div>
<span draggable="true" className="ml-1 pl-2" data-label-type={file.isDirectory ? 'folder' : 'file'} data-label-path={`${file.path}`}>{file.name}</span>
</div>
<ul className="ul_tv ml-0 pl-1" >
{
expandPath && expandPath.includes(file.path) &&
file.child && Object.keys(file.child).map((key, index) => {
return (<RecursiveTreeItem
expandPath={expandPath} key={index} file={file.child[key]} />)
})
}
</ul>
</li>
</>)
}

@ -2,7 +2,8 @@ import React, { useContext } from 'react'
import {CustomTooltip, CustomMenu, CustomIconsToggle} from '@remix-ui/helper'
import {Dropdown, NavDropdown} from 'react-bootstrap'
import {FormattedMessage} from 'react-intl'
import { AppContext, appPlatformTypes } from '@remix-ui/app'
import { AppContext, appPlatformTypes, platformContext } from '@remix-ui/app'
const _paq = (window._paq = window._paq || [])
export interface HamburgerMenuItemProps {
@ -15,7 +16,7 @@ export interface HamburgerMenuItemProps {
export function HamburgerMenuItem(props: HamburgerMenuItemProps) {
const {hideOption} = props
const {platform} = useContext(AppContext)
const platform = useContext(platformContext)
const uid = 'workspace' + props.kind
return (
<>

@ -1,4 +1,4 @@
import {extractNameFromKey} from '@remix-ui/helper'
import {extractNameFromKey, extractParentFromKey} from '@remix-ui/helper'
import {action, Actions, FileType, WorkspaceElement} from '../types'
import * as _ from 'lodash'
import {fileDecoration} from '@remix-ui/file-decorators'
@ -182,6 +182,11 @@ export const browserReducer = (state = browserInitialState, action: Actions) =>
case 'FETCH_DIRECTORY_SUCCESS': {
const payload = action.payload
console.log('make a flat tree', payload)
const startTime = new Date().getTime()
const fd = fetchDirectoryContent(state, payload)
const endTime = new Date().getTime()
console.log('fetchDirectoryContent tree', endTime - startTime)
return {
...state,
@ -189,7 +194,7 @@ export const browserReducer = (state = browserInitialState, action: Actions) =>
...state.browser,
files:
state.mode === 'browser'
? fetchDirectoryContent(state, payload)
? fd
: state.browser.files,
isRequestingDirectory: false,
isSuccessfulDirectory: true,
@ -246,6 +251,13 @@ export const browserReducer = (state = browserInitialState, action: Actions) =>
case 'FETCH_WORKSPACE_DIRECTORY_SUCCESS': {
const payload = action.payload
if(state.mode === 'browser'){
console.log('make a flat tree', payload)
}
const startTime = new Date().getTime()
const fd = fetchDirectoryContent(state, payload)
const endTime = new Date().getTime()
console.log('fetchDirectoryContent tree', endTime - startTime)
return {
...state,
@ -253,7 +265,7 @@ export const browserReducer = (state = browserInitialState, action: Actions) =>
...state.browser,
files:
state.mode === 'browser'
? fetchWorkspaceDirectoryContent(state, payload)
? fd
: state.browser.files,
isRequestingWorkspace: false,
isSuccessfulWorkspace: true,
@ -606,7 +618,7 @@ export const browserReducer = (state = browserInitialState, action: Actions) =>
popup: ''
}
}
case 'SET_FOCUS_ELEMENT': {
const payload = action.payload

@ -12,15 +12,18 @@ import {MenuItems, WorkSpaceState} from './types'
import {contextMenuActions} from './utils'
import FileExplorerContextMenu from './components/file-explorer-context-menu'
import { customAction } from '@remixproject/plugin-api'
import { AppContext, appPlatformTypes } from '@remix-ui/app'
import { appPlatformTypes, platformContext } from '@remix-ui/app'
import { ElectronMenu } from './components/electron-menu'
import { NewFileExplorer } from './components/file-explorer-new'
const _paq = (window._paq = window._paq || [])
const canUpload = window.File || window.FileReader || window.FileList || window.Blob
export function Workspace() {
const {platform} = useContext(AppContext)
const platform = useContext(platformContext)
const LOCALHOST = ' - connect to localhost - '
const NO_WORKSPACE = ' - none - '
const ELECTRON = 'electron'
@ -77,6 +80,10 @@ export function Workspace() {
dragStatus: false
})
useEffect(() => {
console.log("platform", platform)
},[platform])
useEffect(() => {
if (canPaste) {
addMenuItems([
@ -109,6 +116,14 @@ export function Workspace() {
}
}, [canPaste])
useEffect(() => {
console.log('WORKSPACE RENDER')
})
useEffect(() => {
console.log("workspace state")
},[currentWorkspace])
useEffect(() => {
let workspaceName = localStorage.getItem('currentWorkspace')
if (!workspaceName && global.fs.browser.workspaces.length) {
@ -908,6 +923,7 @@ export function Workspace() {
}}
onContextMenu={(e) => {
e.preventDefault()
console.log(e)
handleContextMenu(e.pageX, e.pageY, ROOT_PATH, 'workspace', 'workspace')
}}
>
@ -1041,7 +1057,7 @@ export function Workspace() {
<i className="fas fa-spinner fa-pulse fa-2x"></i>
</div>
)}
{!(global.fs.browser.isRequestingWorkspace || global.fs.browser.isRequestingCloning) && global.fs.mode === 'browser' && currentWorkspace !== NO_WORKSPACE && (
{global.fs.mode === 'browser' && currentWorkspace !== NO_WORKSPACE && (
<div className="h-100 remixui_treeview" data-id="filePanelFileExplorerTree">
<FileExplorer
fileState={global.fs.browser.fileState}

Loading…
Cancel
Save