├── .eslintrc.js
├── .github
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE.md
├── PULL_REQUEST_TEMPLATE.md
└── images
│ ├── ganache_banner.jpg
│ └── ganache_screenshot.jpg
├── .gitignore
├── .nvmrc
├── .travis.yml
├── AppXManifest.xml
├── LICENSE
├── README.md
├── appveyor.yml
├── build
├── appx
│ ├── LargeTile.scale-100.png
│ ├── LargeTile.scale-125.png
│ ├── LargeTile.scale-150.png
│ ├── LargeTile.scale-200.png
│ ├── LargeTile.scale-400.png
│ ├── MedTile.scale-100.png
│ ├── MedTile.scale-125.png
│ ├── MedTile.scale-150.png
│ ├── MedTile.scale-200.png
│ ├── MedTile.scale-400.png
│ ├── SmallTile.scale-100.png
│ ├── SmallTile.scale-125.png
│ ├── SmallTile.scale-150.png
│ ├── SmallTile.scale-200.png
│ ├── SmallTile.scale-400.png
│ ├── SplashScreen.scale-100.png
│ ├── SplashScreen.scale-125.png
│ ├── SplashScreen.scale-150.png
│ ├── SplashScreen.scale-200.png
│ ├── SplashScreen.scale-400.png
│ ├── Square150x150Logo.scale-100.png
│ ├── Square150x150Logo.scale-125.png
│ ├── Square150x150Logo.scale-150.png
│ ├── Square150x150Logo.scale-200.png
│ ├── Square150x150Logo.scale-400.png
│ ├── Square44x44Logo.scale-100.png
│ ├── Square44x44Logo.scale-125.png
│ ├── Square44x44Logo.scale-150.png
│ ├── Square44x44Logo.scale-200.png
│ ├── Square44x44Logo.scale-400.png
│ ├── Square44x44Logo.targetsize-16.png
│ ├── Square44x44Logo.targetsize-16_altform-unplated.png
│ ├── Square44x44Logo.targetsize-20.png
│ ├── Square44x44Logo.targetsize-20_altform-unplated.png
│ ├── Square44x44Logo.targetsize-24.png
│ ├── Square44x44Logo.targetsize-24_altform-unplated.png
│ ├── Square44x44Logo.targetsize-256.png
│ ├── Square44x44Logo.targetsize-256_altform-unplated.png
│ ├── Square44x44Logo.targetsize-26.png
│ ├── Square44x44Logo.targetsize-26_altform-unplated.png
│ ├── Square44x44Logo.targetsize-30.png
│ ├── Square44x44Logo.targetsize-30_altform-unplated.png
│ ├── Square44x44Logo.targetsize-32.png
│ ├── Square44x44Logo.targetsize-32_altform-unplated.png
│ ├── Square44x44Logo.targetsize-40.png
│ ├── Square44x44Logo.targetsize-40_altform-unplated.png
│ ├── Square44x44Logo.targetsize-48.png
│ ├── Square44x44Logo.targetsize-48_altform-unplated.png
│ ├── Square44x44Logo.targetsize-60.png
│ ├── Square44x44Logo.targetsize-60_altform-unplated.png
│ ├── Square44x44Logo.targetsize-64.png
│ ├── Square44x44Logo.targetsize-64_altform-unplated.png
│ ├── Square44x44Logo.targetsize-72.png
│ ├── Square44x44Logo.targetsize-72_altform-unplated.png
│ ├── Square44x44Logo.targetsize-80.png
│ ├── Square44x44Logo.targetsize-80_altform-unplated.png
│ ├── Square44x44Logo.targetsize-96.png
│ ├── Square44x44Logo.targetsize-96_altform-unplated.png
│ ├── StoreLogo.png
│ ├── StoreLogo.scale-100.png
│ ├── StoreLogo.scale-125.png
│ ├── StoreLogo.scale-150.png
│ ├── StoreLogo.scale-200.png
│ ├── StoreLogo.scale-400.png
│ ├── Wide310x150Logo.scale-100.png
│ ├── Wide310x150Logo.scale-125.png
│ ├── Wide310x150Logo.scale-150.png
│ ├── Wide310x150Logo.scale-200.png
│ └── Wide310x150Logo.scale-400.png
└── dmg
│ ├── background.png
│ ├── background.tiff
│ ├── background@2x.png
│ └── entitlements.mac.inherit.plist
├── certs
├── cert.pfx.enc
└── osx.p12.enc
├── dev-app-update.yml
├── package-lock.json
├── package.json
├── patches
└── webpack+4.46.0.patch
├── scripts
└── build
│ ├── AppRun
│ ├── afterPack.js
│ └── afterSignHook.js
├── src
├── common
│ ├── README.md
│ ├── extras
│ │ └── index.js
│ ├── redux
│ │ ├── appshell
│ │ │ ├── actions.js
│ │ │ └── reducers.js
│ │ ├── auto-update
│ │ │ ├── actions.js
│ │ │ └── reducers.js
│ │ ├── config
│ │ │ ├── actions.js
│ │ │ └── reducers.js
│ │ ├── core
│ │ │ ├── actions.js
│ │ │ └── reducers.js
│ │ ├── logs
│ │ │ ├── actions.js
│ │ │ └── reducers.js
│ │ ├── middleware
│ │ │ └── analytics
│ │ │ │ ├── engines
│ │ │ │ └── GoogleAnalytics.js
│ │ │ │ └── index.js
│ │ ├── network
│ │ │ ├── actions.js
│ │ │ └── reducers.js
│ │ ├── reducer.js
│ │ ├── search
│ │ │ └── actions.js
│ │ └── workspaces
│ │ │ ├── actions.js
│ │ │ └── reducers.js
│ ├── services
│ │ ├── AutoUpdateService.js
│ │ └── GoogleAnalyticsService.js
│ └── utils
│ │ ├── cleanup.js
│ │ ├── downloader.js
│ │ ├── jsonTheme.js
│ │ ├── patch-unzip-stream.js
│ │ └── pojofyError.js
├── integrations
│ ├── ethereum
│ │ ├── common
│ │ │ ├── redux
│ │ │ │ ├── accounts
│ │ │ │ │ ├── actions.js
│ │ │ │ │ └── reducers.js
│ │ │ │ ├── blocks
│ │ │ │ │ ├── actions.js
│ │ │ │ │ └── reducers.js
│ │ │ │ ├── core
│ │ │ │ │ ├── actions.js
│ │ │ │ │ └── reducers.js
│ │ │ │ ├── events
│ │ │ │ │ ├── actions.js
│ │ │ │ │ └── reducers.js
│ │ │ │ ├── request-cache
│ │ │ │ │ ├── actions.js
│ │ │ │ │ └── reducers.js
│ │ │ │ ├── transactions
│ │ │ │ │ ├── actions.js
│ │ │ │ │ └── reducers.js
│ │ │ │ ├── web3
│ │ │ │ │ ├── actions.js
│ │ │ │ │ ├── helpers
│ │ │ │ │ │ ├── ReduxWeb3Provider.js
│ │ │ │ │ │ └── Web3ActionCreator.js
│ │ │ │ │ └── reducers.js
│ │ │ │ └── workspaces
│ │ │ │ │ ├── actions.js
│ │ │ │ │ └── reducers.js
│ │ │ └── services
│ │ │ │ ├── EthereumChainService.js
│ │ │ │ └── TruffleIntegrationService.js
│ │ ├── index.js
│ │ ├── main
│ │ │ └── types
│ │ │ │ └── contracts
│ │ │ │ └── ContractCache.js
│ │ └── renderer
│ │ │ ├── components
│ │ │ ├── checksum-addresses
│ │ │ │ └── ChecksumAddress.js
│ │ │ └── formatted-ether-value
│ │ │ │ └── FormattedEtherValue.js
│ │ │ ├── init
│ │ │ └── Events.js
│ │ │ └── screens
│ │ │ ├── accounts
│ │ │ ├── AccountList.js
│ │ │ ├── AccountList.scss
│ │ │ ├── AccountsScreen.js
│ │ │ ├── AccountsScreen.scss
│ │ │ ├── KeyModal.js
│ │ │ ├── KeyModal.scss
│ │ │ ├── MnemonicAndHdPath.js
│ │ │ ├── MnemonicAndHdPath.scss
│ │ │ ├── MnemonicInfoModal.js
│ │ │ └── MnemonicInfoModal.scss
│ │ │ ├── blocks
│ │ │ ├── BlockCard.js
│ │ │ ├── BlockCard.scss
│ │ │ ├── BlockList.js
│ │ │ ├── BlockList.scss
│ │ │ ├── BlocksScreen.js
│ │ │ ├── BlocksScreen.scss
│ │ │ ├── MiniBlockCard.js
│ │ │ └── MiniBlockCard.scss
│ │ │ ├── config
│ │ │ └── ConfigScreens
│ │ │ │ ├── AccountsScreen.js
│ │ │ │ ├── AdvancedScreen.js
│ │ │ │ ├── ChainScreen.js
│ │ │ │ ├── ServerScreen.js
│ │ │ │ └── WorkspaceScreen.js
│ │ │ ├── contracts
│ │ │ ├── ContractCard.js
│ │ │ ├── ContractDetails.js
│ │ │ ├── ContractDetailsScreen.scss
│ │ │ ├── ContractsScreen.js
│ │ │ ├── ContractsScreen.scss
│ │ │ └── ProjectContracts.js
│ │ │ ├── event-details
│ │ │ ├── DecodedEventDetails.js
│ │ │ ├── DecodedEventDetails.scss
│ │ │ ├── EncodedEventDetails.js
│ │ │ ├── EncodedEventDetails.scss
│ │ │ ├── EventDetailsScreen.js
│ │ │ └── EventDetailsScreen.scss
│ │ │ ├── events
│ │ │ ├── EventItem.js
│ │ │ ├── EventItem.scss
│ │ │ ├── EventList.js
│ │ │ ├── EventList.scss
│ │ │ ├── EventsScreen.js
│ │ │ ├── EventsScreen.scss
│ │ │ └── RecentEvents.js
│ │ │ └── transactions
│ │ │ ├── DestinationAddress.js
│ │ │ ├── MiniTxCard.js
│ │ │ ├── MiniTxCard.scss
│ │ │ ├── RecentTransactions.js
│ │ │ ├── RecentTransactions.scss
│ │ │ ├── TransactionTypeBadge.js
│ │ │ ├── TransactionTypeBadge.scss
│ │ │ ├── TransactionsScreen.js
│ │ │ ├── TransactionsScreen.scss
│ │ │ ├── TxCard.js
│ │ │ ├── TxCard.scss
│ │ │ ├── TxList.js
│ │ │ └── TxList.scss
│ ├── filecoin
│ │ ├── common
│ │ │ ├── redux
│ │ │ │ ├── accounts
│ │ │ │ │ ├── actions.js
│ │ │ │ │ └── reducers.js
│ │ │ │ ├── core
│ │ │ │ │ ├── actions.js
│ │ │ │ │ └── reducers.js
│ │ │ │ ├── deals
│ │ │ │ │ ├── actions.js
│ │ │ │ │ └── reducers.js
│ │ │ │ ├── files
│ │ │ │ │ ├── actions.js
│ │ │ │ │ └── reducers.js
│ │ │ │ ├── lotus
│ │ │ │ │ ├── actions.js
│ │ │ │ │ ├── helpers
│ │ │ │ │ │ ├── LotusActionCreator.js
│ │ │ │ │ │ └── ReduxLotusProvider.js
│ │ │ │ │ └── reducers.js
│ │ │ │ ├── messages
│ │ │ │ │ ├── actions.js
│ │ │ │ │ └── reducers.js
│ │ │ │ ├── prefix.js
│ │ │ │ ├── reducer.js
│ │ │ │ ├── request-cache
│ │ │ │ │ ├── actions.js
│ │ │ │ │ └── reducers.js
│ │ │ │ └── tipsets
│ │ │ │ │ ├── actions.js
│ │ │ │ │ └── reducers.js
│ │ │ ├── services
│ │ │ │ └── FilecoinChainService.js
│ │ │ └── utils
│ │ │ │ └── cid.js
│ │ ├── index.js
│ │ └── renderer
│ │ │ ├── components
│ │ │ └── formatted-fil-value
│ │ │ │ └── FormattedFILValue.js
│ │ │ └── screens
│ │ │ ├── accounts
│ │ │ ├── AccountList.js
│ │ │ ├── AccountList.scss
│ │ │ ├── AccountsBanner.js
│ │ │ ├── AccountsBanner.scss
│ │ │ ├── AccountsScreen.js
│ │ │ ├── AccountsScreen.scss
│ │ │ ├── KeyModal.js
│ │ │ ├── KeyModal.scss
│ │ │ ├── SeedInfoModal.js
│ │ │ └── SeedInfoModal.scss
│ │ │ ├── config
│ │ │ └── ConfigScreens
│ │ │ │ ├── AccountsScreen.js
│ │ │ │ ├── MinerScreen.js
│ │ │ │ ├── ServerScreen.js
│ │ │ │ └── WorkspaceScreen.js
│ │ │ ├── deals
│ │ │ ├── DealList.js
│ │ │ ├── DealList.scss
│ │ │ ├── DealStatusBadge.js
│ │ │ ├── DealStatusBadge.scss
│ │ │ ├── DealsScreen.js
│ │ │ ├── DealsScreen.scss
│ │ │ ├── MiniDealCard.js
│ │ │ └── MiniDealCard.scss
│ │ │ ├── files
│ │ │ ├── FileList.js
│ │ │ ├── FileList.scss
│ │ │ ├── FilesScreen.js
│ │ │ ├── FilesScreen.scss
│ │ │ ├── MiniFileCard.js
│ │ │ └── MiniFileCard.scss
│ │ │ ├── messages
│ │ │ ├── MessageCard.js
│ │ │ ├── MessageCard.scss
│ │ │ ├── MessageList.js
│ │ │ ├── MessageList.scss
│ │ │ ├── MessageTypeBadge.js
│ │ │ ├── MessageTypeBadge.scss
│ │ │ ├── MessagesScreen.js
│ │ │ ├── MessagesScreen.scss
│ │ │ ├── MiniMessageCard.js
│ │ │ ├── MiniMessageCard.scss
│ │ │ ├── RecentMessages.js
│ │ │ └── RecentMessages.scss
│ │ │ └── tipsets
│ │ │ ├── BlockCard.js
│ │ │ ├── BlockCard.scss
│ │ │ ├── BlockList.js
│ │ │ ├── MiniBlockCard.js
│ │ │ ├── MiniBlockCard.scss
│ │ │ ├── MiniTipsetCard.js
│ │ │ ├── MiniTipsetCard.scss
│ │ │ ├── TipsetCard.js
│ │ │ ├── TipsetCard.scss
│ │ │ ├── TipsetList.js
│ │ │ ├── TipsetList.scss
│ │ │ ├── TipsetsScreen.js
│ │ │ └── TipsetsScreen.scss
│ ├── index.js
│ └── integrations.js
├── main
│ ├── index.js
│ ├── init
│ │ ├── AutoUpdate.js
│ │ └── migration.js
│ └── types
│ │ ├── json
│ │ ├── JsonStorage.js
│ │ └── JsonWithKeyPaths.js
│ │ ├── settings
│ │ ├── GlobalSettings.js
│ │ ├── Settings.js
│ │ ├── WorkspaceSettings.js
│ │ └── flavors
│ │ │ ├── ethereum.js
│ │ │ └── filecoin.js
│ │ └── workspaces
│ │ ├── Workspace.js
│ │ └── WorkspaceManager.js
└── renderer
│ ├── App.js
│ ├── README.md
│ ├── app.global.scss
│ ├── components
│ ├── file-picker
│ │ ├── FilePicker.js
│ │ └── FilePicker.scss
│ ├── google-analytics
│ │ └── GoogleAnalytics.js
│ ├── header-bar
│ │ ├── HeaderBar.css
│ │ └── HeaderBar.js
│ ├── logo
│ │ └── Logo.js
│ ├── modal
│ │ ├── ErrorModal.js
│ │ ├── Modal.js
│ │ ├── Modal.scss
│ │ └── ModalDetails.js
│ ├── only-if
│ │ └── OnlyIf.js
│ ├── progress-bar
│ │ ├── ProgressBar.js
│ │ └── ProgressBar.scss
│ ├── spinner
│ │ ├── Spinner.css
│ │ ├── Spinner.js
│ │ ├── SpinnerButton.css
│ │ └── SpinnerButton.js
│ ├── status-indicator
│ │ ├── StatusIndicator.js
│ │ └── StatusIndicator.scss
│ ├── styled-select
│ │ ├── StyledSelect.js
│ │ └── StyledSelect.scss
│ └── with-empty-state
│ │ └── WithEmptyState.js
│ ├── css.js
│ ├── icons
│ ├── account.svg
│ ├── blocks.svg
│ ├── bug.svg
│ ├── chain.svg
│ ├── chevron-up-o.svg
│ ├── chevron-up.svg
│ ├── console.svg
│ ├── contract-icon.svg
│ ├── contract.svg
│ ├── deals-icon.svg
│ ├── dots.svg
│ ├── download.svg
│ ├── eject.svg
│ ├── error.svg
│ ├── errorant.svg
│ ├── events-icon.svg
│ ├── file-icon.svg
│ ├── force_mine.svg
│ ├── ganache_logo.svg
│ ├── key.svg
│ ├── list.svg
│ ├── locked.svg
│ ├── logo.svg
│ ├── modal-error.svg
│ ├── modal-info.svg
│ ├── modal-update.svg
│ ├── no_transactions.svg
│ ├── restart.svg
│ ├── revert.svg
│ ├── save-icon.svg
│ ├── search.svg
│ ├── settings.svg
│ ├── snapshot.svg
│ ├── start.svg
│ ├── stop.svg
│ ├── transactions.svg
│ ├── trash-icon.svg
│ ├── unlocked.svg
│ ├── warning.svg
│ └── welcome-crane.svg
│ ├── index.js
│ ├── init
│ ├── AutoUpdate.js
│ ├── Config.js
│ ├── Core.js
│ ├── ErrorHandler.js
│ ├── Logs.js
│ ├── Network.js
│ ├── Workspaces.js
│ ├── index.js
│ └── store
│ │ ├── createStore.development.js
│ │ ├── createStore.js
│ │ └── createStore.production.js
│ ├── routes.js
│ ├── screens
│ ├── appshell
│ │ ├── AppShell.js
│ │ ├── AppShell.scss
│ │ ├── BugModal.js
│ │ ├── BugModal.scss
│ │ ├── TopNavbar.js
│ │ └── TopNavbar.scss
│ ├── auto-update
│ │ ├── UpdateModal.js
│ │ ├── UpdateModal.scss
│ │ ├── UpdateNotification.js
│ │ └── UpdateNotification.scss
│ ├── config
│ │ ├── ConfigScreen.js
│ │ ├── ConfigScreen.scss
│ │ └── ConfigScreens
│ │ │ └── AboutScreen.js
│ ├── first-run
│ │ ├── FirstRunScreen.js
│ │ └── FirstRunScreen.scss
│ ├── helpers
│ │ ├── connect.js
│ │ └── sanitize.js
│ ├── loader
│ │ ├── LoaderScreen.js
│ │ └── LoaderScreen.scss
│ ├── logs
│ │ ├── LogContainer.scss
│ │ ├── LogContainerLazy.js
│ │ ├── LogsLazy.js
│ │ ├── LogsScreen.js
│ │ ├── LogsScreen.scss
│ │ └── Row.js
│ ├── not-found
│ │ ├── NotFoundScreen.js
│ │ └── NotFoundScreen.scss
│ ├── startup
│ │ ├── HomeScreen.js
│ │ └── HomeScreen.scss
│ └── title
│ │ ├── TitleScreen.js
│ │ └── TitleScreen.scss
│ └── styles
│ ├── buttons.scss
│ ├── cards.scss
│ ├── clean_colors.scss
│ ├── colors.scss
│ ├── forms.scss
│ ├── logo.scss
│ ├── modals.scss
│ ├── normalize.scss
│ └── panels.scss
├── static
├── README.md
├── fonts
│ ├── FiraCode-Regular.ttf
│ ├── FiraSans-Bold.ttf
│ ├── FiraSans-Regular.ttf
│ ├── FiraSans-SemiBold.ttf
│ ├── GrandHotel-Regular.ttf
│ ├── RobotoCondensed-Bold.ttf
│ └── RobotoCondensed-Regular.ttf
├── icons
│ ├── mac
│ │ └── icon.icns
│ ├── png
│ │ ├── 1024x1024.png
│ │ ├── 128x128.png
│ │ ├── 16x16.png
│ │ ├── 24x24.png
│ │ ├── 256x256.png
│ │ ├── 32x32.png
│ │ ├── 48x48.png
│ │ ├── 512x512.png
│ │ ├── 64x64.png
│ │ └── 96x96.png
│ └── win
│ │ └── icon.ico
├── logo.png
└── node
│ ├── chain
│ ├── chain.ethereum.js
│ ├── chain.ethereum.v2.js
│ ├── chain.filecoin.js
│ └── logging.js
│ ├── package-lock.json
│ ├── package.json
│ ├── truffle-integration
│ ├── __tests__
│ │ └── projectFsWatcherUtils.test.js
│ ├── decode.js
│ ├── index.js
│ ├── projectDetails.js
│ ├── projectFsWatcher.js
│ ├── projectFsWatcherUtils.js
│ └── projectsWatcher.js
│ └── truffle-project-loader
│ └── index.js
├── test
├── README.md
└── mocha
│ ├── project-loader
│ ├── project-loader.test.js
│ └── truffle-project
│ │ ├── myfile.json
│ │ └── truffle.js
│ └── workspaces
│ ├── new-workspace.subtest.js
│ ├── test-workspaces
│ ├── default
│ │ └── Settings
│ ├── global
│ │ └── Settings
│ └── ui
│ │ └── workspaces
│ │ ├── Test-1
│ │ └── Settings
│ │ └── Test-2
│ │ └── Settings
│ ├── workspace-manager.subtest.js
│ └── workspaces.test.js
└── webpack
├── webpack.main.js
└── webpack.renderer.js
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ["prettier", "eslint:recommended", "plugin:react/recommended"],
3 | plugins: ["prettier", "react", "jest", "react-hooks"],
4 | rules: {
5 | "no-prototype-builtins": "warn",
6 | "no-console": "warn",
7 | "react/prop-types": 0,
8 | "react-hooks/rules-of-hooks": "error",
9 | "react-hooks/exhaustive-deps": "warn",
10 | },
11 | parserOptions: {
12 | ecmaVersion: 2020,
13 | sourceType: "module",
14 | },
15 | env: {
16 | es6: true,
17 | browser: true,
18 | node: true,
19 | mocha: true,
20 | "jest/globals": true,
21 | },
22 | settings: {
23 | react: {
24 | version: "detect",
25 | },
26 | },
27 | parser: "babel-eslint",
28 | };
29 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## Ganache
2 |
3 | Thank you for contributing! Take a moment to review our [**contributing guidelines**](https://github.com/trufflesuite/ganache-ui/blob/master/.github/CONTRIBUTING.md)
4 | to make the process easy and effective for everyone involved.
5 |
6 | **You must open an issue** before embarking on any significant pull request, especially those that
7 | add a new library or change existing tests, otherwise you risk spending a lot of time working
8 | on something that might not end up being merged into the project.
9 |
10 | Before opening a pull request, please ensure:
11 |
12 | - [ ] You have followed our [**contributing guidelines**](https://github.com/trufflesuite/ganache-ui/blob/master/.github/CONTRIBUTING.md)
13 | - [ ] Pull request has tests
14 | - [ ] Code is well-commented, linted and follows project conventions
15 | - [ ] Documentation is updated (if necessary)
16 | - [ ] Description explains the issue/use-case resolved and auto-closes related issues
17 |
18 | Be kind to code reviewers, please try to keep pull requests as small and focused as possible :)
19 |
20 | **IMPORTANT**: By submitting a patch via a Pull Request, you agree to allow the project
21 | owners to license your work under the terms of the [MIT License](https://github.com/trufflesuite/ganache-ui/blob/master/LICENSE.md).
22 |
--------------------------------------------------------------------------------
/.github/images/ganache_banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/.github/images/ganache_banner.jpg
--------------------------------------------------------------------------------
/.github/images/ganache_screenshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/.github/images/ganache_screenshot.jpg
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | certs/cert.pfx
2 | dist
3 | node_modules
4 | .DS_Store
5 | .vscode
6 | test/mocha/workspaces/test-workspaces/default/ContractCache
7 | test/mocha/workspaces/test-workspaces/workspaces/Test-1/ContractCache
8 | test/mocha/workspaces/test-workspaces/workspaces/Test-2/ContractCache
9 |
--------------------------------------------------------------------------------
/.nvmrc:
--------------------------------------------------------------------------------
1 | 14.21.1
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2022 ConsenSys Software Inc
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 | of the Software, and to permit persons to whom the Software is furnished to do
10 | so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/build/appx/LargeTile.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/LargeTile.scale-100.png
--------------------------------------------------------------------------------
/build/appx/LargeTile.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/LargeTile.scale-125.png
--------------------------------------------------------------------------------
/build/appx/LargeTile.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/LargeTile.scale-150.png
--------------------------------------------------------------------------------
/build/appx/LargeTile.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/LargeTile.scale-200.png
--------------------------------------------------------------------------------
/build/appx/LargeTile.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/LargeTile.scale-400.png
--------------------------------------------------------------------------------
/build/appx/MedTile.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/MedTile.scale-100.png
--------------------------------------------------------------------------------
/build/appx/MedTile.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/MedTile.scale-125.png
--------------------------------------------------------------------------------
/build/appx/MedTile.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/MedTile.scale-150.png
--------------------------------------------------------------------------------
/build/appx/MedTile.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/MedTile.scale-200.png
--------------------------------------------------------------------------------
/build/appx/MedTile.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/MedTile.scale-400.png
--------------------------------------------------------------------------------
/build/appx/SmallTile.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/SmallTile.scale-100.png
--------------------------------------------------------------------------------
/build/appx/SmallTile.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/SmallTile.scale-125.png
--------------------------------------------------------------------------------
/build/appx/SmallTile.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/SmallTile.scale-150.png
--------------------------------------------------------------------------------
/build/appx/SmallTile.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/SmallTile.scale-200.png
--------------------------------------------------------------------------------
/build/appx/SmallTile.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/SmallTile.scale-400.png
--------------------------------------------------------------------------------
/build/appx/SplashScreen.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/SplashScreen.scale-100.png
--------------------------------------------------------------------------------
/build/appx/SplashScreen.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/SplashScreen.scale-125.png
--------------------------------------------------------------------------------
/build/appx/SplashScreen.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/SplashScreen.scale-150.png
--------------------------------------------------------------------------------
/build/appx/SplashScreen.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/SplashScreen.scale-200.png
--------------------------------------------------------------------------------
/build/appx/SplashScreen.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/SplashScreen.scale-400.png
--------------------------------------------------------------------------------
/build/appx/Square150x150Logo.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square150x150Logo.scale-100.png
--------------------------------------------------------------------------------
/build/appx/Square150x150Logo.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square150x150Logo.scale-125.png
--------------------------------------------------------------------------------
/build/appx/Square150x150Logo.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square150x150Logo.scale-150.png
--------------------------------------------------------------------------------
/build/appx/Square150x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square150x150Logo.scale-200.png
--------------------------------------------------------------------------------
/build/appx/Square150x150Logo.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square150x150Logo.scale-400.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.scale-100.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.scale-125.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.scale-150.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.scale-200.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.scale-400.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-16.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-16_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-16_altform-unplated.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-20.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-20_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-20_altform-unplated.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-24.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-24_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-24_altform-unplated.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-256.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-256_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-256_altform-unplated.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-26.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-26.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-26_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-26_altform-unplated.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-30.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-30.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-30_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-30_altform-unplated.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-32.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-32_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-32_altform-unplated.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-40.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-40_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-40_altform-unplated.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-48.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-48_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-48_altform-unplated.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-60.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-60_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-60_altform-unplated.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-64.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-64_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-64_altform-unplated.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-72.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-72_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-72_altform-unplated.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-80.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-80_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-80_altform-unplated.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-96.png
--------------------------------------------------------------------------------
/build/appx/Square44x44Logo.targetsize-96_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Square44x44Logo.targetsize-96_altform-unplated.png
--------------------------------------------------------------------------------
/build/appx/StoreLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/StoreLogo.png
--------------------------------------------------------------------------------
/build/appx/StoreLogo.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/StoreLogo.scale-100.png
--------------------------------------------------------------------------------
/build/appx/StoreLogo.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/StoreLogo.scale-125.png
--------------------------------------------------------------------------------
/build/appx/StoreLogo.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/StoreLogo.scale-150.png
--------------------------------------------------------------------------------
/build/appx/StoreLogo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/StoreLogo.scale-200.png
--------------------------------------------------------------------------------
/build/appx/StoreLogo.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/StoreLogo.scale-400.png
--------------------------------------------------------------------------------
/build/appx/Wide310x150Logo.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Wide310x150Logo.scale-100.png
--------------------------------------------------------------------------------
/build/appx/Wide310x150Logo.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Wide310x150Logo.scale-125.png
--------------------------------------------------------------------------------
/build/appx/Wide310x150Logo.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Wide310x150Logo.scale-150.png
--------------------------------------------------------------------------------
/build/appx/Wide310x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Wide310x150Logo.scale-200.png
--------------------------------------------------------------------------------
/build/appx/Wide310x150Logo.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/appx/Wide310x150Logo.scale-400.png
--------------------------------------------------------------------------------
/build/dmg/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/dmg/background.png
--------------------------------------------------------------------------------
/build/dmg/background.tiff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/dmg/background.tiff
--------------------------------------------------------------------------------
/build/dmg/background@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/build/dmg/background@2x.png
--------------------------------------------------------------------------------
/build/dmg/entitlements.mac.inherit.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.cs.allow-jit
6 |
7 | com.apple.security.cs.allow-unsigned-executable-memory
8 |
9 | com.apple.security.cs.allow-dyld-environment-variables
10 |
11 |
12 |
--------------------------------------------------------------------------------
/certs/cert.pfx.enc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/certs/cert.pfx.enc
--------------------------------------------------------------------------------
/certs/osx.p12.enc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/certs/osx.p12.enc
--------------------------------------------------------------------------------
/dev-app-update.yml:
--------------------------------------------------------------------------------
1 | owner: trufflesuite
2 | repo: ganache
3 | provider: github
4 |
--------------------------------------------------------------------------------
/scripts/build/afterPack.js:
--------------------------------------------------------------------------------
1 | const { join } = require("path");
2 | const { chmodSync, readFileSync, writeFileSync } = require("fs-extra");
3 |
4 | const afterPack = async (context) => {
5 | if (context.electronPlatformName !== "linux") {
6 | return;
7 | }
8 | if (context.targets.length !== 1) {
9 | throw new Error("Linux can only target 1 build at a time.");
10 | }
11 | const target = context.targets[0];
12 | if (target.name !== "appImage") {
13 | throw new Error("I don't know if this will work with other linux targets. You'll need to test before removing this check!");
14 | }
15 |
16 | const appRunTemplate = readFileSync(join(__dirname, "AppRun"), {encoding: "utf-8"});
17 | const appRunFinal = appRunTemplate.replace(/{APP_NAME}/g, target.options.executableName);
18 | const appRunPath = join(context.appOutDir, "AppRun")
19 | writeFileSync(appRunPath, appRunFinal, {encoding: "utf-8"});
20 | // make sure this file is executable
21 | chmodSync(appRunPath, 0o755);
22 | };
23 |
24 | module.exports = afterPack;
25 |
--------------------------------------------------------------------------------
/scripts/build/afterSignHook.js:
--------------------------------------------------------------------------------
1 | // See: https://medium.com/@TwitterArchiveEraser/notarize-electron-apps-7a5f988406db
2 |
3 | const fs = require('fs');
4 | const path = require('path');
5 | const electron_notarize = require('electron-notarize');
6 | const pkg = require("../../package.json");
7 |
8 | module.exports = async function (params) {
9 | // Only notarize the app on Mac OS only.
10 | if (process.platform !== 'darwin' || process.env.NOTARIZE !== 'true') {
11 | return;
12 | }
13 | console.log('afterSign hook triggered', params);
14 |
15 | // Same appId in electron-builder.
16 | let appId = pkg.build.appId;
17 |
18 | let appPath = path.join(params.appOutDir, `${params.packager.appInfo.productFilename}.app`);
19 | if (!fs.existsSync(appPath)) {
20 | throw new Error(`Cannot find application at: ${appPath}`);
21 | }
22 |
23 | console.log(`Notarizing ${appId} found at ${appPath}`);
24 |
25 | const interval = setInterval(() => {
26 | console.log("...");
27 | }, 10000);
28 |
29 | try {
30 | await electron_notarize.notarize({
31 | appBundleId: appId,
32 | appPath: appPath,
33 | appleId: process.env.appleId,
34 | appleIdPassword: process.env.appleIdPassword
35 | });
36 | } catch (error) {
37 | console.error(error);
38 | } finally {
39 | clearInterval(interval);
40 | }
41 |
42 | console.log(`Done notarizing ${appId}`);
43 | };
--------------------------------------------------------------------------------
/src/common/README.md:
--------------------------------------------------------------------------------
1 | COMMON SCRIPTS
2 |
3 | This is a convenient place where you can place utility type files that you expect to use between both the main and render processor. Thanks to webpack aliasing, you can easily import files from here using the common alias.
4 |
--------------------------------------------------------------------------------
/src/common/extras/index.js:
--------------------------------------------------------------------------------
1 | const Downloader = require("../utils/downloader");
2 |
3 | module.exports = {
4 | init: (path) => {
5 | const downloader = new Downloader(path);
6 | return {
7 | downloader,
8 | };
9 | },
10 | };
11 |
--------------------------------------------------------------------------------
/src/common/redux/appshell/actions.js:
--------------------------------------------------------------------------------
1 | const prefix = "APPSHELL";
2 |
3 | export const SET_SCROLL_POSITION = `${prefix}/SET_SCROLL_POSITION`;
4 | export const setScrollPosition = function(scrollPosition) {
5 | return { type: SET_SCROLL_POSITION, scrollPosition };
6 | };
7 |
--------------------------------------------------------------------------------
/src/common/redux/appshell/reducers.js:
--------------------------------------------------------------------------------
1 | import * as AppShell from "./actions";
2 |
3 | const initialState = {
4 | scrollPosition: "top",
5 | };
6 |
7 | export default function(state = initialState, action) {
8 | switch (action.type) {
9 | case AppShell.SET_SCROLL_POSITION:
10 | return Object.assign({}, state, {
11 | scrollPosition: action.scrollPosition,
12 | });
13 | default:
14 | return state;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/common/redux/config/reducers.js:
--------------------------------------------------------------------------------
1 | import * as Config from "./actions";
2 | import cloneDeep from "lodash.clonedeep";
3 |
4 | const initialState = {
5 | validationErrors: {}, // of the format {SETTING_NAME (i.e. hostname would be server.hostname): "error text"}
6 | settings: {},
7 | startupMode: Config.STARTUP_MODE.NORMAL
8 | };
9 |
10 | export default function(state = initialState, action) {
11 | let nextState = cloneDeep(state);
12 | switch (action.type) {
13 | case Config.SET_SETTINGS:
14 | // Ignore state; we're overwriting the settings.
15 | nextState.settings.global = cloneDeep(action.global);
16 | nextState.settings.workspace = cloneDeep(action.workspace);
17 | break;
18 | case Config.SET_SETTING_ERROR:
19 | if (typeof nextState.validationErrors === "undefined") {
20 | nextState.validationErrors = {};
21 | }
22 | nextState.validationErrors[action.key] = action.errorText;
23 | break;
24 | case Config.CLEAR_SETTING_ERROR:
25 | if (action.key in nextState.validationErrors) {
26 | delete nextState.validationErrors[action.key];
27 | }
28 | break;
29 | case Config.CLEAR_ALL_SETTING_ERRORS:
30 | nextState.validationErrors = {};
31 | break;
32 | case Config.SET_STARTUP_MODE:
33 | nextState.startupMode = action.mode;
34 | break;
35 | default:
36 | break;
37 | }
38 |
39 | return nextState;
40 | }
41 |
--------------------------------------------------------------------------------
/src/common/redux/core/reducers.js:
--------------------------------------------------------------------------------
1 | const Core = require("./actions");
2 |
3 | const initialState = {
4 | started: false,
5 | systemError: null,
6 | showBugModal: false,
7 | modalError: null,
8 | updateInfo: {}
9 | };
10 |
11 | export default function (state = initialState, action) {
12 | state = {...initialState, ...state};
13 | switch (action.type) {
14 | case Core.SET_SERVER_STARTED:
15 | return Object.assign({}, state, {
16 | started: true,
17 | });
18 |
19 | case Core.SET_SYSTEM_ERROR:
20 | return Object.assign({}, state, {
21 | systemError: action.error,
22 | showBugModal: action.showBugModal,
23 | });
24 | case Core.SET_PROGRESS:
25 | return Object.assign({}, state, {
26 | progress: action.message,
27 | minDuration: action.minDuration
28 | });
29 | case Core.SET_MODAL_ERROR:
30 | return Object.assign({}, state, {
31 | modalError: action.error,
32 | });
33 |
34 | case Core.DISMISS_MODAL_ERROR:
35 | return Object.assign({}, state, {
36 | modalError: null,
37 | });
38 |
39 | case Core.SET_NEW_VERSION_INFO:
40 | return Object.assign({}, state, {
41 | updateInfo: {
42 | newVersion: action.newVersion,
43 | releaseNotes: action.releaseNotes,
44 | },
45 | });
46 |
47 | default:
48 | return state;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/common/redux/logs/actions.js:
--------------------------------------------------------------------------------
1 | const prefix = "LOGS";
2 |
3 | export const ADD_LOG_LINES = `${prefix}/ADD_LOG_LINES`;
4 | export const CLEAR_LOG_LINES = `${prefix}/CLEAR_LOG_LINES`;
5 |
6 | export const addLogLines = function(lines, context) {
7 | if (Array.isArray(lines) === false) {
8 | lines = [lines];
9 | }
10 | return { type: ADD_LOG_LINES, lines, context };
11 | };
12 |
13 | export const clearLogLines = function(context) {
14 | return { type: CLEAR_LOG_LINES, context };
15 | };
16 |
--------------------------------------------------------------------------------
/src/common/redux/logs/reducers.js:
--------------------------------------------------------------------------------
1 | import * as Logs from "./actions";
2 |
3 | const initialState = {
4 | "default": {
5 | lines: []
6 | }
7 | };
8 |
9 | export default function(state = initialState, action) {
10 | switch (action.type) {
11 | case Logs.ADD_LOG_LINES:
12 | var time = new Date();
13 | var newLines = action.lines.map(line => {
14 | return { time: time, line: line };
15 | });
16 |
17 | var context = action.context || "default";
18 | var group = state[context];
19 | var oldLines = group ? [...group.lines] : [];
20 | if (oldLines.length > 0 && newLines.length > 0) {
21 | const firstLine = newLines.shift();
22 | oldLines[oldLines.length - 1].line += firstLine.line;
23 | }
24 | return Object.assign({}, state, {
25 | [context]: {
26 | lines: oldLines.concat(newLines)
27 | }
28 | });
29 |
30 | case Logs.CLEAR_LOG_LINES:
31 | return Object.assign({}, state, {
32 | [action.context]: {
33 | lines: []
34 | }
35 | });
36 |
37 | default:
38 | return state;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/common/redux/middleware/analytics/index.js:
--------------------------------------------------------------------------------
1 | import * as GoogleAnalytics from "./engines/GoogleAnalytics";
2 |
3 | const engines = [GoogleAnalytics];
4 |
5 | export function processAction({ getState }) {
6 | return next => action => {
7 | engines.forEach(engine => {
8 | engine.process(action, getState());
9 | });
10 |
11 | const returnValue = next(action);
12 |
13 | return returnValue;
14 | };
15 | }
16 |
17 | export function processPage(path, state) {
18 | engines.forEach(engine => {
19 | engine.processPage(path, state);
20 | });
21 | }
22 |
--------------------------------------------------------------------------------
/src/common/redux/network/actions.js:
--------------------------------------------------------------------------------
1 | const prefix = "NETWORK";
2 |
3 | export const SET_INTERFACES = `${prefix}/SET_INTERFACES`;
4 | export function setInterfaces(interfaces) {
5 | return { type: SET_INTERFACES, interfaces };
6 | }
7 |
8 | export const SET_TOAST = `${prefix}/SET_TOAST`;
9 | export function setToast(message, infinite = false, buttonText = null, toastOnClick = null) {
10 | return { type: SET_TOAST, message, infinite, buttonText, toastOnClick };
11 | }
--------------------------------------------------------------------------------
/src/common/redux/network/reducers.js:
--------------------------------------------------------------------------------
1 | import * as Network from "./actions";
2 | import cloneDeep from "lodash.clonedeep";
3 |
4 | const initialState = {
5 | interfaces: {},
6 | toast: {date:Date.now(), message: null, infinite: false, buttonText: null, toastOnClick: null}
7 | };
8 |
9 | export default function(state = initialState, action) {
10 | let nextState = cloneDeep(state);
11 |
12 | switch (action.type) {
13 | case Network.SET_INTERFACES:
14 | // Ignore state; we're overwriting the settings.
15 | nextState.interfaces = cloneDeep(action.interfaces);
16 | break;
17 | case Network.SET_TOAST:
18 | // Ignore state; we're overwriting the settings.
19 | nextState.toast = {
20 | message: action.message,
21 | date: Date.now(),
22 | infinite: action.infinite,
23 | buttonText: action.buttonText,
24 | toastOnClick: action.toastOnClick
25 | };
26 | break;
27 | default:
28 | break;
29 | }
30 |
31 | return nextState;
32 | }
33 |
--------------------------------------------------------------------------------
/src/common/utils/cleanup.js:
--------------------------------------------------------------------------------
1 | const noop = () => {};
2 |
3 | // attach user callback to the process event emitter
4 | const Cleanup = (callback) => {
5 | // if no callback, it will still exit gracefully on Ctrl-C
6 | callback = callback || noop;
7 |
8 | //do something when app is closing
9 | process.on('exit', callback);
10 |
11 | //catches ctrl+c event
12 | process.on('SIGINT', callback);
13 |
14 | // catches "kill pid" (for example: nodemon restart)
15 | process.on('SIGUSR1', callback);
16 | process.on('SIGUSR2', callback);
17 |
18 | //catches uncaught exceptions
19 | process.on('uncaughtException', callback);
20 | };
21 |
22 | module.exports = Cleanup;
23 |
--------------------------------------------------------------------------------
/src/common/utils/jsonTheme.js:
--------------------------------------------------------------------------------
1 | export default {
2 | "scheme": "ganache",
3 | "author": "Ganache",
4 | //transparent main background
5 | "base00": "rgba(0, 0, 0, 0)",
6 | "base01": "rgb(245, 245, 245)",
7 | "base02": "#000", // lines and background color for: NULL, undefined, and brackets
8 | "base03": "rgb(26, 185, 70)", // blue grey -- not used?
9 | "base04": "rgba(0, 0, 0, 0.3)",
10 | "base05": "#aaa", // undefined text
11 | "base06": "#073642", // dark blue -- not sued?
12 | "base07": "#000", // JSON keys
13 | "base08": "#d33682", // pink -- not used?
14 | "base09": "rgb(208, 108, 0)", // string types text (ganache orange)
15 | "base0A": "rgb(208, 108, 0)", // NULL (ganache orange)
16 | "base0B": "#3fe0c5", //aka --truffle-green, for float types
17 | "base0C": "#777", // array indexes and item counts
18 | "base0D": "#000", // arrows
19 | "base0E": "#000", // used for some arrows and bool
20 | "base0F": "#268bd2", // a bright blue -- not used?
21 | "base10": "rgb(26, 185, 70)", // a bright blue -- not used?
22 | };
23 |
--------------------------------------------------------------------------------
/src/common/utils/pojofyError.js:
--------------------------------------------------------------------------------
1 | module.exports = function pojofyError(_error) {
2 | let error;
3 | if (_error instanceof Error) {
4 | // JSON.stringify can't serialize error objects
5 | // so we just convert the Error to an Object here
6 | error = {};
7 |
8 | Object.getOwnPropertyNames(_error).forEach((key) => {
9 | error[key] = _error[key];
10 | });
11 | } else {
12 | error = _error;
13 | }
14 | return error;
15 | }
16 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/common/redux/accounts/reducers.js:
--------------------------------------------------------------------------------
1 | import * as Accounts from "./actions";
2 |
3 | const initialState = {
4 | addresses: [],
5 | balances: {},
6 | nonces: {},
7 | };
8 |
9 | export default function(state = initialState, action) {
10 | let balances;
11 | let nonces;
12 | switch (action.type) {
13 | case Accounts.GET_ACCOUNTS:
14 | var addresses = action.addresses;
15 | balances = Object.assign({}, state.balances);
16 | nonces = Object.assign({}, state.nonces);
17 |
18 | // Set default balance to zero if this is a new account
19 | addresses.forEach(address => {
20 | if (!balances[address]) balances[address] = "0";
21 | if (!nonces[address]) nonces[address] = 0;
22 | });
23 |
24 | return Object.assign({}, state, {
25 | addresses,
26 | balances,
27 | nonces,
28 | });
29 |
30 | case Accounts.GET_ACCOUNT_BALANCE:
31 | balances = Object.assign({}, state.balances, {
32 | [action.address]: action.balance,
33 | });
34 | return Object.assign({}, state, {
35 | balances,
36 | });
37 |
38 | case Accounts.GET_ACCOUNT_NONCE:
39 | nonces = Object.assign({}, state.nonces, {
40 | [action.address]: action.nonce,
41 | });
42 | return Object.assign({}, state, {
43 | nonces,
44 | });
45 |
46 | default:
47 | return state;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/common/redux/request-cache/actions.js:
--------------------------------------------------------------------------------
1 | const prefix = "CACHE";
2 |
3 | const createCacheId = function(payload) {
4 | let params = payload.params
5 | .map(param => {
6 | return param.toString();
7 | })
8 | .join(",");
9 | return `${payload.method}(${params})`;
10 | };
11 |
12 | export const CACHE_REQUEST = `${prefix}/CACHE_REQUEST`;
13 | export const cacheRequest = function(payload, response) {
14 | let id = createCacheId(payload);
15 | return { type: CACHE_REQUEST, id, response };
16 | };
17 |
18 | export const checkCache = function(payload, getState) {
19 | // Never cache "eth_blockNumber"
20 | if (payload.method == "eth_blockNumber") {
21 | return null;
22 | }
23 |
24 | let cache = getState().requestCache;
25 | let id = createCacheId(payload);
26 | let hit = cache[id];
27 |
28 | if (!hit) {
29 | return null;
30 | }
31 |
32 | // Tailor the response to the new rpc id
33 | var response = Object.assign({}, hit);
34 | response.id = payload.id;
35 | return response;
36 | };
37 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/common/redux/request-cache/reducers.js:
--------------------------------------------------------------------------------
1 | import * as RequestCache from "./actions";
2 | import * as Core from "../core/actions";
3 |
4 | const initialState = {};
5 |
6 | // These requests are never invalidated.
7 | const HARD_CACHED = {
8 | eth_accounts: true,
9 | eth_gasPrice: true,
10 | eth_getBlockByNumber: blockNumber => {
11 | return blockNumber != "latest" && blockNumber != "pending";
12 | },
13 | eth_getBlockTransactionCountByNumber: blockNumber => {
14 | return blockNumber != "latest" && blockNumber != "pending";
15 | },
16 | eth_getTransactionByHash: true,
17 | };
18 |
19 | const isHardCached = function(id) {
20 | let method = id.substring(0, id.indexOf("("));
21 |
22 | var hardCachedResult = HARD_CACHED[method];
23 |
24 | if (typeof hardCachedResult == "function") {
25 | var split = id.split(/\(|\)/);
26 | var params = split[1];
27 |
28 | if (params == "") {
29 | params = [];
30 | } else {
31 | params = params.split(",");
32 | }
33 |
34 | return hardCachedResult.apply(null, params);
35 | } else {
36 | return !!hardCachedResult;
37 | }
38 | };
39 |
40 | export default function(state = initialState, action) {
41 | switch (action.type) {
42 | case RequestCache.CACHE_REQUEST:
43 | return Object.assign({}, state, {
44 | [action.id]: action.response,
45 | });
46 |
47 | case Core.SET_BLOCK_NUMBER: {
48 | // Invalidate the cache on new block number
49 | let cache = Object.assign({}, state);
50 |
51 | Object.keys(cache).forEach(id => {
52 | if (!isHardCached(id)) {
53 | delete cache[id];
54 | }
55 | });
56 |
57 | return cache;
58 | }
59 | default:
60 | return state;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/common/redux/web3/actions.js:
--------------------------------------------------------------------------------
1 | import ReduxWeb3Provider from "./helpers/ReduxWeb3Provider";
2 | import Web3 from "web3";
3 |
4 | const prefix = "WEB3";
5 |
6 | export const SET_WEB3_INSTANCE = `${prefix}/SET_WEB3_INSTANCE`;
7 | export function setWeb3Instance(web3Instance) {
8 | return { type: SET_WEB3_INSTANCE, web3Instance };
9 | }
10 |
11 | export const SET_RPC_PROVIDER_URL = `${prefix}/SET_RPC_PROVIDER_URL`;
12 | export function setRPCProviderUrl(url) {
13 | return function(dispatch, getState) {
14 | const provider = new ReduxWeb3Provider(url, dispatch, getState);
15 | const web3Instance = new Web3(provider);
16 | dispatch(setWeb3Instance(web3Instance));
17 | };
18 | }
19 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/common/redux/web3/helpers/Web3ActionCreator.js:
--------------------------------------------------------------------------------
1 | // const prefix = "WEB3ACTIONCREATOR"
2 | // export const WEB3_REQUEST_STARTED = `${prefix}/WEB3_REQUEST_STARTED`
3 | // export function Web3RequestStarted(name) {
4 | // return { type: WEB3_REQUEST_STARTED, name }
5 | // }
6 |
7 | // export const WEB3_REQUEST_FAILED = `${prefix}/WEB3_REQUEST_FAILED`
8 | // export function Web3RequestFailed(name, error) {
9 | // return { type: WEB3_REQUEST_FAILED, name, error}
10 | // }
11 |
12 | // export const WEB3_REQUEST_SUCCEEDED = `${prefix}/WEB3_REQUEST_SUCCEEDED`
13 | // export function Web3RequestSucceeded(name, result) {
14 | // return { type: WEB3_REQUEST_SUCCEEDED, name, result }
15 | // }
16 |
17 | export async function web3Request(name, args, web3Instance) {
18 | let fn = web3Instance.eth[name];
19 |
20 | return await fn.apply(web3Instance.eth, args);
21 | }
22 |
23 | export async function web3ActionCreator(dispatch, getState, name, args) {
24 | // This specifically pulls state from the web3 reducer. Smell?
25 | let web3Instance = getState().web3.web3Instance;
26 | // TODO: ETHEREUM
27 | if (web3Instance) {
28 | return await web3Request(name, args, web3Instance);
29 | }
30 | }
31 |
32 | export function web3CleanUpHelper(dispatch, getState) {
33 | let web3Instance = getState().web3.web3Instance;
34 | if (web3Instance) {
35 | let provider = web3Instance.currentProvider;
36 |
37 | // clear out current provider to stop active subscription monitoring
38 | web3Instance.setProvider(null);
39 |
40 | if (provider && provider.connection && provider.connection.close) {
41 | provider.connection.close();
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/common/redux/web3/reducers.js:
--------------------------------------------------------------------------------
1 | import * as Web3Action from "./actions";
2 |
3 | const initialState = {
4 | web3Instance: null,
5 | };
6 |
7 | export default function(state = initialState, action) {
8 | switch (action.type) {
9 | case Web3Action.SET_WEB3_INSTANCE:
10 | return Object.assign({}, state, {
11 | web3Instance: action.web3Instance,
12 | });
13 |
14 | default:
15 | return state;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/components/checksum-addresses/ChecksumAddress.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import Web3 from "web3";
3 |
4 | export default class ChecksumAddress extends Component {
5 | toChecksumAddress = address => {
6 | address = address.replace("0x", "").toLowerCase();
7 | const hash = Web3.utils.sha3(address).replace("0x", "");
8 | let ret = "0x";
9 |
10 | for (let i = 0; i < address.length; i++) {
11 | if (parseInt(hash[i], 16) >= 8) {
12 | ret += address[i].toUpperCase();
13 | } else {
14 | ret += address[i];
15 | }
16 | }
17 |
18 | return ret;
19 | };
20 |
21 | render() {
22 | return {this.toChecksumAddress(this.props.address)} ;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/components/formatted-ether-value/FormattedEtherValue.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import PropTypes from "prop-types";
3 | import EtherUnits from "ethereumjs-units";
4 |
5 | export default class FormattedEtherValue extends Component {
6 | render() {
7 | const weiValueInEth = parseFloat(
8 | EtherUnits.convert(
9 | this.props.value,
10 | this.props.fromUnit,
11 | this.props.toUnit,
12 | ),
13 | ).toFixed(2);
14 | return (
15 | {`${weiValueInEth} ${this.props.toUnit.toUpperCase()}`}
18 | );
19 | }
20 | }
21 |
22 | FormattedEtherValue.propTypes = {
23 | value: PropTypes.string,
24 | fromUnit: PropTypes.string,
25 | toUnit: PropTypes.string,
26 | };
27 |
28 | FormattedEtherValue.defaultProps = {
29 | fromUnit: "wei",
30 | toUnit: "eth",
31 | };
32 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/init/Events.js:
--------------------------------------------------------------------------------
1 | import { ipcRenderer } from "electron";
2 |
3 | import {
4 | SET_SUBSCRIBED_TOPICS,
5 | setSubscribedTopics,
6 | } from "../../common/redux/events/actions";
7 |
8 | export function initEvents(store) {
9 | ipcRenderer.on(SET_SUBSCRIBED_TOPICS, (event, topics) => {
10 | store.dispatch(setSubscribedTopics(topics));
11 | });
12 | }
13 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/accounts/AccountsScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | import connect from "../../../../../renderer/screens/helpers/connect";
4 |
5 | import MnemonicAndHdPath from "./MnemonicAndHdPath";
6 | import AccountList from "./AccountList";
7 |
8 | class AccountsScreen extends Component {
9 | constructor(props) {
10 | super(props);
11 |
12 | this.state = {};
13 | }
14 |
15 | render() {
16 | return (
17 |
18 |
19 |
20 |
24 |
25 |
31 |
32 |
33 | );
34 | }
35 | }
36 |
37 | export default connect(
38 | AccountsScreen,
39 | "core",
40 | "accounts",
41 | );
42 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/accounts/AccountsScreen.scss:
--------------------------------------------------------------------------------
1 | .AccountsScreen {
2 | width: 100%;
3 | display: flex;
4 | flex: 1;
5 | flex-direction: column;
6 | position: relative;
7 |
8 | main {
9 | padding: 0;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/accounts/KeyModal.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from "react";
2 |
3 | import ChecksumAddress from "../../components/checksum-addresses/ChecksumAddress";
4 | import Modal from "../../../../../renderer/components/modal/Modal";
5 |
6 | export default class KeyModal extends PureComponent {
7 | render() {
8 | return (
9 |
10 |
11 | ACCOUNT INFORMATION
12 |
13 |
14 |
15 |
16 | ACCOUNT ADDRESS
17 |
18 |
19 |
20 |
21 |
22 | PRIVATE KEY
23 |
24 | {this.props.privateKey}
25 |
26 |
27 | Do not use this private key on a public blockchain; use it for
28 | development purposes only!
29 |
30 |
31 |
32 |
35 |
36 |
37 | );
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/accounts/KeyModal.scss:
--------------------------------------------------------------------------------
1 | .KeyModal {
2 | section, header {
3 | width: 680px;
4 | }
5 | svg {
6 | width: 28px;
7 | height: 28px;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/accounts/MnemonicAndHdPath.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from "react";
2 |
3 | import MnemonicInfoModal from "./MnemonicInfoModal";
4 |
5 | import OnlyIf from "../../../../../renderer/components/only-if/OnlyIf";
6 |
7 | export default class MnemonicAndHdPath extends PureComponent {
8 | constructor(props) {
9 | super(props);
10 | this.state = {
11 | showWarning: false,
12 | };
13 | }
14 |
15 | showWarning() {
16 | this.setState({
17 | showWarning: true,
18 | });
19 | }
20 |
21 | hideWarning() {
22 | this.setState({
23 | showWarning: false,
24 | });
25 | }
26 |
27 | render() {
28 | return (
29 |
30 |
31 |
32 | MNEMONIC{" "}
33 |
37 | ?
38 |
39 |
40 |
41 | {this.props.mnemonic}{" "}
42 |
43 | note: this mnemonic is not secure; don't use it on a public
44 | blockchain.
45 |
46 |
47 |
48 |
49 |
HD PATH
50 | {this.props.hdPath}account_index
51 |
52 |
53 |
54 |
55 |
56 | );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/accounts/MnemonicAndHdPath.scss:
--------------------------------------------------------------------------------
1 |
2 | .MnemonicAndHdPath {
3 | display: flex;
4 | background-color: var(--app-mnemonic-background-color);
5 | font-size: 0.8em;
6 | margin: 0;
7 | border-bottom: 1px solid #aaa;
8 |
9 | .Mnemonic {
10 | flex-grow: 1;
11 | }
12 |
13 | .Mnemonic, .HDPath {
14 | margin: 1rem;
15 |
16 | h4 {
17 | margin: 0 0 .3rem 0;
18 | }
19 |
20 | span {
21 | font-family: "Fira Code Regular", monospace;
22 | color: var(--text-color);
23 | font-size: 0.9rem;
24 | }
25 |
26 | .WarningIndicator {
27 | font-size: 0.8rem;
28 | padding: 0 .125rem;
29 | border: 2px solid transparent;
30 | border-radius: .35rem;
31 | color: white;
32 | background: #DDD;
33 | display: inline-block;
34 | margin-left: .3rem;
35 | font-weight: bold;
36 | cursor: pointer;
37 |
38 | &:hover {
39 | background: #ebb67e;
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/accounts/MnemonicInfoModal.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from "react";
2 |
3 | import Modal from "../../../../../renderer/components/modal/Modal";
4 |
5 | export default class MnemonicInfoModal extends PureComponent {
6 | render() {
7 | return (
8 |
9 |
10 | About Your Mnemonic
11 |
12 |
13 |
14 |
15 | Your mnemonic is a special secret created for you by Ganache. It's
16 | used to generate the addresses available during development as well
17 | as sign transactions sent from those addresses.
18 |
19 |
20 | You should only use this mnemonic during development. If you use a
21 | wallet application configured with this mnemonic, ensure you switch
22 | to a separate configuration when using that wallet with production
23 | blockchains.
24 |
25 |
26 | This mnemonic is not secure. You should not trust it to manage
27 | blockchain assets.
28 |
29 |
32 |
33 |
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/accounts/MnemonicInfoModal.scss:
--------------------------------------------------------------------------------
1 | .MnemonicInfoModal {
2 | section, header {
3 | width: 680px;
4 | }
5 | svg {
6 | width: 28px;
7 | height: 28px;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/blocks/BlockCard.scss:
--------------------------------------------------------------------------------
1 | .BlockCard {
2 | font-family: "Fira Code Regular", sans-serif;
3 | background: var(--app-card-default-background);
4 | display: flex;
5 | flex-direction: column;
6 | flex-grow: 1;
7 | margin: 0;
8 | border-radius: 4px;
9 | word-wrap: break-word;
10 | width: 100%;
11 |
12 | header {
13 | width: 100%;
14 | height: 64px;
15 | display: flex;
16 | flex-direction: row;
17 | justify-content: flex-start;
18 | background-color: #fff;
19 | border-bottom: 1px solid #aaa;
20 | line-height: 1;
21 |
22 | h1 {
23 | font-size: 1.5rem;
24 | padding: 1.25rem;
25 | margin: 0;
26 | }
27 | }
28 |
29 | .Button {
30 | text-decoration: none;
31 | text-align: center;
32 | margin: 0;
33 | }
34 |
35 | header button {
36 | border-radius: 0;
37 | line-height: 1;
38 | height: 100%;
39 | }
40 |
41 | .BlockBody {
42 | padding: 1rem 0;
43 | border-bottom: 1px solid #aaa;
44 |
45 | > div {
46 | padding: 1rem;
47 | }
48 | }
49 |
50 | .HeaderSecondaryInfo {
51 | display: flex;
52 | align-items: center;
53 | justify-content: space-between;
54 | width: 100%;
55 | padding: 1rem;
56 | }
57 |
58 | .HasTxs {
59 | border-color: var(--primary-color);
60 | }
61 |
62 | .TransactionList {
63 | .Waiting {
64 | margin-top: 10rem;
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/blocks/BlockList.scss:
--------------------------------------------------------------------------------
1 | .BlockList {
2 | width: 100%;
3 | background: white;
4 | }
5 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/blocks/BlocksScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import connect from "../../../../../renderer/screens/helpers/connect";
3 | import * as Blocks from "../../../common/redux/blocks/actions";
4 | import BlockList from "./BlockList";
5 | import BlockCard from "./BlockCard";
6 |
7 | class BlockContainer extends Component {
8 | constructor(props) {
9 | super(props);
10 | }
11 |
12 | componentDidMount() {
13 | this.props.dispatch(Blocks.requestPage());
14 | }
15 |
16 | render() {
17 | var content;
18 | if (this.props.match.params.blockNumber != null) {
19 | content = ;
20 | } else {
21 | content = ;
22 | }
23 | return {content}
;
24 | }
25 | }
26 |
27 | export default connect(
28 | BlockContainer,
29 | "blocks",
30 | );
31 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/blocks/BlocksScreen.scss:
--------------------------------------------------------------------------------
1 | .BlocksScreen {
2 | display: flex;
3 | flex-direction: column;
4 |
5 | height: 100%;
6 | width: 100%;
7 | }
8 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/contracts/ContractDetailsScreen.scss:
--------------------------------------------------------------------------------
1 | .ContractDetailsScreen {
2 |
3 | .ContractDetailsBody {
4 | .Title {
5 | border: solid var(--app-card-default-border);
6 | border-width: 1px 0;
7 | h2 {
8 | margin: 18px;
9 | }
10 | }
11 |
12 | .Waiting {
13 | margin: 1rem 0;
14 | }
15 | }
16 |
17 | .DecodeError {
18 | padding: 28px 18px;
19 | background: var(--app-card-default-background);
20 | text-align: center;
21 |
22 | div {
23 | margin-top: 10px;
24 | }
25 | }
26 |
27 | .react-json-view .pretty-json-container {
28 | // TODO-DAVID: there are now a couple of `padding: 28px 18px;` in this file and other places too, maybe
29 | // this should be abstracted out as a global class?
30 | padding: 28px 18px;
31 | background: var(--app-card-default-background);
32 | }
33 |
34 | .TxList > a.Link:last-child > .MiniTxCard{
35 | // the last transaction in the transactions list shouldn't have a border
36 | // because the next section starts with a border
37 | border-bottom:0;
38 | }
39 |
40 | .ContractInfoBody {
41 | padding: 28px 18px;
42 | background: var(--app-card-default-background);
43 |
44 | .data {
45 | display: grid;
46 | grid-template-columns: 1fr 1fr;
47 | grid-gap: 1rem;
48 | }
49 |
50 | .label {
51 | font-size: 0.75rem;
52 | font-family: "RobotoCondensed-Regular";
53 | font-weight: 800;
54 | color: var(--app-card-label);
55 | }
56 |
57 | .value {
58 | font-size: .875rem;
59 | font-family: "Fira Code Regular";
60 | color: var(--app-card-value);
61 | word-break: break-all;
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/contracts/ProjectContracts.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | import connect from "../../../../../renderer/screens/helpers/connect";
4 |
5 | import ContractCard from "./ContractCard";
6 |
7 | class ProjectContracts extends Component {
8 | render() {
9 | let content;
10 | if (this.props.contracts.length > 0) {
11 | content = this.props.contracts.map(contract => {
12 | const cache = this.props.contractCache[contract.address];
13 | return (
14 |
23 | );
24 | });
25 | } else {
26 | content = (
27 |
28 | ⚠ {" "}
29 | To see rich contract data compile the contracts
30 | within your Truffle Project.
31 |
32 | );
33 | }
34 |
35 | return {content}
;
36 | }
37 | }
38 |
39 | export default connect(ProjectContracts);
40 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/event-details/DecodedEventDetails.scss:
--------------------------------------------------------------------------------
1 | .DecodedEventDetails {
2 | margin: 0;
3 |
4 | .DataRow {
5 | display: flex;
6 | justify-content: space-between;
7 | }
8 |
9 | .DataSection {
10 | background: var(--app-card-default-background);
11 | border-bottom: 1px solid aaa;
12 | }
13 |
14 | .SectionHeading {
15 | background: #fff;
16 | padding: 1rem;
17 | border-bottom: 1px solid #aaa;
18 |
19 | h1 {
20 | font-size: 1.25rem;
21 | margin: 0;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/event-details/EncodedEventDetails.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Moment from "react-moment";
3 | import { Link } from "react-router-dom";
4 |
5 | const EncodedEventDetails = ({ event }) => {
6 | const { transactionHash, timestamp, contractAddress, logIndex } = event;
7 | return (
8 |
9 |
10 | ⚠ {" "}
11 | To see rich event data {" "}
12 |
13 | link a Truffle Project
14 | {" "}
15 | containing the contract that emits this event.
16 |
17 |
18 |
19 |
TX HASH
20 |
{transactionHash}
21 |
22 |
23 |
LOG INDEX
24 |
{logIndex}
25 |
26 |
27 |
BLOCK TIME
28 |
29 |
30 | {timestamp}
31 |
32 |
33 |
34 |
35 |
36 |
37 |
CONTRACT
38 |
{contractAddress}
39 |
40 |
41 |
42 | );
43 | };
44 |
45 | export default EncodedEventDetails;
46 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/event-details/EncodedEventDetails.scss:
--------------------------------------------------------------------------------
1 | .EncodedEventDetails {
2 | background: var(--app-card-default-background);
3 | margin: 0;
4 | padding: 1rem;
5 | border-bottom: 1px solid #aaa;
6 |
7 | .Notice {
8 | background: #ddd;
9 | padding: 1rem;
10 | border-radius: 6px;
11 | margin-bottom: 1rem;
12 | text-align: center;
13 |
14 | .settingsLink {
15 | color: #df7b0e;
16 | }
17 | }
18 |
19 | .Warning {
20 | font-size: 24px;
21 | vertical-align: middle;
22 | }
23 |
24 | .DataRow {
25 | display: flex;
26 | justify-content: space-between;
27 | margin-bottom: 1rem;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/event-details/EventDetailsScreen.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/src/integrations/ethereum/renderer/screens/event-details/EventDetailsScreen.scss
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/events/EventItem.scss:
--------------------------------------------------------------------------------
1 | .EventItem {
2 | font-family: "Fira Code Regular", monospaced;
3 | width: 100%;
4 | cursor: pointer;
5 | margin: .5rem 0;
6 | background: var(--app-card-default-background);
7 | padding: 28px 18px;
8 | word-wrap: break-word;
9 | cursor: pointer;
10 | display: flex;
11 | flex-direction: column;
12 | margin: 0;
13 | transition: all .3s;
14 | border-bottom: 1px solid #aaa;
15 |
16 | .Row {
17 | // display: flex;
18 | // align-items: center;
19 | // flex-direction: row;
20 | margin-bottom: 1rem;
21 | // justify-content: space-between;
22 | display: grid;
23 | grid-template-columns: 1fr 1fr 120px 200px;
24 |
25 | &.Top {
26 | display: flex;
27 | justify-content: space-between;
28 | }
29 |
30 | &:last-of-type {
31 | margin-bottom: 0;
32 | }
33 | }
34 |
35 | .RowItem {
36 | display: flex;
37 | flex-direction: row;
38 | justify-content: space-between;
39 | cursor: pointer;
40 | margin-right: 2rem;
41 | }
42 |
43 | .Name {
44 | .Value {
45 | font-weight: bold;
46 | }
47 | }
48 |
49 | .SecondaryItems {
50 | .Value {
51 | font-size: .825rem;
52 | }
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/events/EventList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import MDSpinner from "react-md-spinner";
3 |
4 | import connect from "../../../../../renderer/screens/helpers/connect";
5 |
6 | import EventItem from "./EventItem";
7 |
8 | class EventList extends Component {
9 | render() {
10 | if (this.props.eventList.length === 0) {
11 | if (this.props.loading) {
12 | return (
13 |
24 | );
25 | } else {
26 | return (
27 |
30 | );
31 | }
32 | }
33 |
34 | return (
35 |
36 | {this.props.eventList.map((event, index) => (
37 |
38 | ))}
39 |
40 | );
41 | }
42 | }
43 |
44 | export default connect(EventList);
45 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/events/EventList.scss:
--------------------------------------------------------------------------------
1 | .EventList {
2 | width: 100%;
3 | height: 100%;
4 | background: white;
5 |
6 | .EventItem {
7 | font-family: "Fira Code Regular", monospaced;
8 | width: 100%;
9 | cursor: pointer;
10 | margin: 0;
11 | background: var(--app-card-default-background);
12 | padding: 28px 18px;
13 | word-wrap: break-word;
14 | transition: all 0.3s;
15 | border-bottom: 1px solid #aaa;
16 |
17 | .name {
18 | margin-bottom: 1rem;
19 |
20 | > .label {
21 | font-size: 1.125rem;
22 | }
23 | }
24 |
25 | .data {
26 | // display: flex;
27 | // justify-content: space-between;
28 | display: grid;
29 | grid-template-columns: 1fr 1fr 120px 240px;
30 | }
31 |
32 | .blockTime {
33 | margin-left: auto;
34 | }
35 |
36 | .label {
37 | font-size: 0.75rem;
38 | font-family: "RobotoCondensed-Regular";
39 | font-weight: 800;
40 | color: var(--app-card-label);
41 | margin-bottom: 0.25rem;
42 | }
43 |
44 | .value {
45 | font-size: 0.875rem;
46 | font-family: "Fira Code Regular";
47 | color: var(--app-card-value);
48 | word-break: break-all;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/events/EventsScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import connect from "../../../../../renderer/screens/helpers/connect";
3 | import EventList from "./EventList";
4 |
5 | import * as Events from "../../../common/redux/events/actions";
6 |
7 | class EventsScreen extends Component {
8 | componentDidMount() {
9 | this.props.dispatch(Events.requestPage());
10 | }
11 |
12 | componentWillUnmount() {
13 | this.props.dispatch(Events.clearEventsInView());
14 | }
15 |
16 | render() {
17 | return (
18 |
19 |
23 |
24 | );
25 | }
26 | }
27 |
28 | export default connect(
29 | EventsScreen,
30 | "core",
31 | "appshell",
32 | "events",
33 | );
34 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/events/EventsScreen.scss:
--------------------------------------------------------------------------------
1 | .EventsScreen {
2 | height: 100%;
3 | width: 100%;
4 |
5 | > main {
6 | padding: 0;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/events/RecentEvents.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | import connect from "../helpers/connect";
4 |
5 | import EventList from "./EventList";
6 |
7 | import * as Events from "../../../common/redux/events/actions";
8 |
9 | class RecentEvents extends Component {
10 | componentDidUpdate(prevProps) {
11 | // If the scroll position changed...
12 | if (
13 | this.props.appshell.scrollPosition != prevProps.appshell.scrollPosition
14 | ) {
15 | if (this.props.appshell.scrollPosition == "top") {
16 | this.props.dispatch(Events.requestPreviousPage());
17 | } else if (this.props.appshell.scrollPosition == "bottom") {
18 | this.props.dispatch(Events.requestNextPage());
19 | }
20 | return;
21 | }
22 |
23 | // No change in scroll position?
24 | const blocksRequested = Object.keys(this.props.events.blocksRequested);
25 | const latestBlockRequested = Math.max.apply(
26 | Math,
27 | blocksRequested.concat(-1),
28 | );
29 | if (
30 | this.props.appshell.scrollPosition == "top" &&
31 | this.props.core.latestBlock > latestBlockRequested
32 | ) {
33 | this.props.dispatch(Events.requestPreviousPage());
34 | }
35 | }
36 |
37 | render() {
38 | return (
39 |
40 |
41 |
42 | );
43 | }
44 | }
45 |
46 | export default connect(
47 | RecentEvents,
48 | "appshell",
49 | "core",
50 | "events",
51 | );
52 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/transactions/DestinationAddress.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | export default class DestinationAddress extends Component {
4 | render() {
5 | const isContractCall =
6 | (this.props.receipt.hasOwnProperty("contractAddress") &&
7 | this.props.receipt.contractAddress !== null) ||
8 | (this.props.tx.to && this.props.tx.input !== "0x");
9 |
10 | const isContractCreationCall =
11 | this.props.receipt.hasOwnProperty("contractAddress") &&
12 | this.props.receipt.contractAddress !== null;
13 |
14 | return (
15 |
16 |
17 | {isContractCreationCall
18 | ? "CREATED CONTRACT ADDRESS"
19 | : isContractCall
20 | ? `TO CONTRACT ADDRESS`
21 | : `TO ADDRESS`}
22 |
23 |
24 | {isContractCreationCall ? (
25 |
26 | {this.props.receipt.contractAddress}
27 |
28 | ) : (
29 |
{this.props.contractName || this.props.tx.to}
30 | )}
31 |
32 |
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/transactions/MiniTxCard.scss:
--------------------------------------------------------------------------------
1 | .MiniTxCard {
2 | font-family: "Fira Code Regular", monospaced;
3 | width: 100%;
4 | cursor: pointer;
5 | margin: .5rem 0;
6 | background: var(--app-card-default-background);
7 | padding: 28px 18px;
8 | word-wrap: break-word;
9 | cursor: pointer;
10 | display: flex;
11 | flex-direction: column;
12 | margin: 0;
13 | transition: all .3s;
14 | border-bottom: 1px solid #aaa;
15 |
16 | .Row {
17 | // display: flex;
18 | // align-items: center;
19 | // flex-direction: row;
20 | margin-bottom: 1rem;
21 | // justify-content: space-between;
22 | display: grid;
23 | grid-template-columns: 1fr 1fr 120px 200px;
24 |
25 | &.Top {
26 | display: flex;
27 | justify-content: space-between;
28 | }
29 |
30 | &:last-of-type {
31 | margin-bottom: 0;
32 | }
33 | }
34 |
35 | .RowItem {
36 | display: flex;
37 | flex-direction: row;
38 | justify-content: space-between;
39 | cursor: pointer;
40 | }
41 |
42 | .Nonce,
43 | .GasUsed,
44 | .Value,
45 | .MinedOn {
46 | .Label {
47 | font-size: .625rem;
48 | letter-spacing: 1.2px;
49 | }
50 |
51 | .Value {
52 | font-size: .825rem;
53 | }
54 | }
55 |
56 | .TxHash {
57 | .Value {
58 | font-weight: bold;
59 | }
60 | }
61 |
62 | .SecondaryItems {
63 | .Value {
64 | font-size: .825rem;
65 | }
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/transactions/RecentTransactions.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | import connect from "../../../../../renderer/screens/helpers/connect";
4 |
5 | import * as Transactions from "../../../common/redux/transactions/actions";
6 |
7 | import TxList from "./TxList";
8 |
9 | class RecentTransactions extends Component {
10 | componentDidUpdate(prevProps) {
11 | // If the scroll position changed...
12 | if (
13 | prevProps.appshell.scrollPosition != this.props.appshell.scrollPosition
14 | ) {
15 | if (prevProps.appshell.scrollPosition == "top") {
16 | this.props.dispatch(Transactions.requestPreviousPage());
17 | } else if (prevProps.appshell.scrollPosition == "bottom") {
18 | this.props.dispatch(Transactions.requestNextPage());
19 | }
20 | return;
21 | }
22 |
23 | // No change in scroll position?
24 | var blocksRequested = Object.keys(prevProps.transactions.blocksRequested);
25 | var latestBlockRequested = Math.max.apply(Math, blocksRequested.concat(-1));
26 | if (
27 | prevProps.appshell.scrollPosition == "top" &&
28 | prevProps.core.latestBlock > latestBlockRequested
29 | ) {
30 | this.props.dispatch(Transactions.requestPreviousPage());
31 | }
32 | }
33 |
34 | render() {
35 | return (
36 |
37 |
42 |
43 | );
44 | }
45 | }
46 |
47 | export default connect(
48 | RecentTransactions,
49 | "transactions",
50 | "core",
51 | "appshell",
52 | );
53 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/transactions/RecentTransactions.scss:
--------------------------------------------------------------------------------
1 | .RecentTransactions {
2 | flex-grow: 1;
3 | display: flex;
4 | height: 100%;
5 | }
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/transactions/TransactionTypeBadge.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | export default class TransactionTypeBadge extends Component {
4 | render() {
5 | if (
6 | this.props.receipt.hasOwnProperty("contractAddress") &&
7 | this.props.receipt.contractAddress !== null
8 | ) {
9 | return (
10 |
11 | CONTRACT CREATION
12 |
13 | );
14 | }
15 |
16 | if (this.props.tx.to && this.props.tx.input !== "0x") {
17 | return (
18 |
19 | CONTRACT CALL
20 |
21 | );
22 | }
23 |
24 | if (this.props.tx.to && this.props.tx.value > 0) {
25 | return (
26 |
27 | VALUE TRANSFER
28 |
29 | );
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/transactions/TransactionTypeBadge.scss:
--------------------------------------------------------------------------------
1 | .TransactionTypeBadge {
2 | font-size: .75rem;
3 | padding: 8px;
4 | height: 28px;
5 | border-radius: 25px;
6 |
7 | &.ContractCallBadge {
8 | background-color: var(--complimentary1);
9 | color: white;
10 | }
11 |
12 | &.ContractCreationBadge {
13 | background-color: darken(rgba(222, 142, 149, 1.000), 10%);
14 | color: white;
15 | }
16 |
17 | &.ValueTransferBadge {
18 | background-color: var(--truffle-green);
19 | color: white;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/transactions/TransactionsScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import connect from "../../../../../renderer/screens/helpers/connect";
3 | import * as Transactions from "../../../common/redux/transactions/actions";
4 | import RecentTransactions from "./RecentTransactions";
5 | import TxCard from "./TxCard";
6 |
7 | class TransactionsScreen extends Component {
8 | componentDidMount() {
9 | this.props.dispatch(Transactions.requestPage());
10 | }
11 |
12 | componentWillUnmount() {
13 | this.props.dispatch(Transactions.clearTransactionsInView());
14 | }
15 |
16 | render() {
17 | var content;
18 | if (this.props.match.params.transactionHash != null) {
19 | content = ;
20 | } else {
21 | content = (
22 |
23 | );
24 | }
25 | return {content}
;
26 | }
27 | }
28 |
29 | export default connect(TransactionsScreen);
30 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/transactions/TransactionsScreen.scss:
--------------------------------------------------------------------------------
1 | .TransactionsScreen {
2 | display: flex;
3 | flex-direction: column;
4 |
5 | height: 100%;
6 | width: 100%;
7 |
8 | > main {
9 | padding: 0;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/integrations/ethereum/renderer/screens/transactions/TxList.scss:
--------------------------------------------------------------------------------
1 | .TxList {
2 | width: 100%;
3 | height: 100%;
4 | background: white;
5 | display: flex;
6 | flex-direction: column;
7 | flex-grow: 1;
8 | }
9 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/common/redux/accounts/reducers.js:
--------------------------------------------------------------------------------
1 | import * as Accounts from "./actions";
2 |
3 | const initialState = {
4 | addresses: [],
5 | balances: {},
6 | nonces: {},
7 | };
8 |
9 | export default function(state = initialState, action) {
10 | let balances;
11 | let nonces;
12 | switch (action.type) {
13 | case Accounts.GET_ACCOUNTS:
14 | var addresses = action.addresses;
15 | balances = Object.assign({}, state.balances);
16 | nonces = Object.assign({}, state.nonces);
17 |
18 | // Set default balance to zero if this is a new account
19 | addresses.forEach(address => {
20 | if (!balances[address]) balances[address] = "0";
21 | if (!nonces[address]) nonces[address] = 0;
22 | });
23 |
24 | return Object.assign({}, state, {
25 | addresses,
26 | balances,
27 | nonces,
28 | });
29 |
30 | case Accounts.GET_ACCOUNT_BALANCE:
31 | balances = Object.assign({}, state.balances, {
32 | [action.address]: action.balance,
33 | });
34 | return Object.assign({}, state, {
35 | balances,
36 | });
37 |
38 | case Accounts.GET_ACCOUNT_NONCE:
39 | nonces = Object.assign({}, state.nonces, {
40 | [action.address]: action.nonce,
41 | });
42 | return Object.assign({}, state, {
43 | nonces,
44 | });
45 |
46 | default:
47 | return state;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/common/redux/core/reducers.js:
--------------------------------------------------------------------------------
1 | const Core = require("./actions");
2 |
3 | const initialState = {
4 | flavor: "filecoin",
5 | isMining: true,
6 | seed: "",
7 | ipfsUrl: "",
8 | options: {},
9 | privateKeys: {},
10 | latestTipset: 0, // Tipset the current chain is on
11 | minerEnabled: null,
12 | latestDeal: 0,
13 | StorageDealStatus: {}
14 | };
15 |
16 | export default function(state = initialState, action) {
17 | switch (action.type) {
18 | case Core.SET_KEY_DATA:
19 | return Object.assign({}, state, {
20 | seed: action.seed,
21 | privateKeys: action.privateKeys,
22 | });
23 |
24 | case Core.SET_IPFS_URL:
25 | return Object.assign({}, state, {
26 | ipfsUrl: action.url
27 | });
28 |
29 | case Core.SET_CURRENT_OPTIONS:
30 | return Object.assign({}, state, {
31 | options: action.options
32 | });
33 |
34 | case Core.SET_TIPSET_NUMBER:
35 | return Object.assign({}, state, {
36 | latestTipset: action.number,
37 | });
38 |
39 | case Core.SET_MINER_ENABLED:
40 | return Object.assign({}, state, {
41 | minerEnabled: action.minerEnabled
42 | });
43 |
44 | case Core.SET_LATEST_DEAL_ID:
45 | return Object.assign({}, state, {
46 | latestDeal: action.id
47 | });
48 |
49 | case Core.SET_STORAGE_DEAL_STATUS_ENUM:
50 | return Object.assign({}, state, {
51 | StorageDealStatus: action.StorageDealStatus
52 | });
53 |
54 | default:
55 | return state;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/common/redux/lotus/actions.js:
--------------------------------------------------------------------------------
1 | import ReduxLotusProvider from "./helpers/ReduxLotusProvider";
2 | import { LotusRPC } from "@filecoin-shipyard/lotus-client-rpc";
3 | import FilecoinPrefix from "../prefix";
4 |
5 | const prefix = `${FilecoinPrefix}/LOTUS`;
6 |
7 | export const SET_LOTUS_INSTANCE = `${prefix}/SET_LOTUS_INSTANCE`;
8 | export function setLotusInstance(lotusInstance) {
9 | return { type: SET_LOTUS_INSTANCE, lotusInstance };
10 | }
11 |
12 | export const SET_LOTUS_SCHEMA = `${prefix}/SET_LOTUS_SCHEMA`;
13 | export function setLotusSchema(schema) {
14 | return { type: SET_LOTUS_SCHEMA, schema };
15 | }
16 |
17 | export async function createLotusInstance(dispatch, getState, url) {
18 | const reduxProvider = new ReduxLotusProvider(url, dispatch, getState);
19 | await reduxProvider.initialize();
20 | const schema = getState().filecoin.lotus.schema;
21 | const lotusInstance = new LotusRPC(reduxProvider, { schema });
22 | return lotusInstance;
23 | }
24 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/common/redux/lotus/helpers/LotusActionCreator.js:
--------------------------------------------------------------------------------
1 | export async function lotusRequest(name, args, lotusInstance) {
2 | const fn = lotusInstance[name];
3 |
4 | return await fn.apply(lotusInstance, args);
5 | }
6 |
7 | export async function lotusActionCreator(dispatch, getState, name, args) {
8 | // This specifically pulls state from the web3 reducer. Smell?
9 | const lotusInstance = getState().filecoin.lotus.lotusInstance;
10 | if (lotusInstance) {
11 | return await lotusRequest(name, args, lotusInstance);
12 | } else {
13 | return null;
14 | }
15 | }
16 |
17 | export function lotusCleanUpHelper(dispatch, getState) {
18 | const lotusInstance = getState().filecoin.lotus.lotusInstance;
19 | if (lotusInstance && lotusInstance.provider) {
20 | lotusInstance.provider.destroy();
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/common/redux/lotus/reducers.js:
--------------------------------------------------------------------------------
1 | import * as LotusAction from "./actions";
2 |
3 | const initialState = {
4 | lotusInstance: null,
5 | schema: {}
6 | };
7 |
8 | export default function(state = initialState, action) {
9 | switch (action.type) {
10 | case LotusAction.SET_LOTUS_INSTANCE:
11 | return Object.assign({}, state, {
12 | lotusInstance: action.lotusInstance,
13 | });
14 |
15 | case LotusAction.SET_LOTUS_SCHEMA:
16 | return Object.assign({}, state, {
17 | schema: action.schema,
18 | });
19 |
20 | default:
21 | return state;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/common/redux/prefix.js:
--------------------------------------------------------------------------------
1 | export default "FILECOIN";
2 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/common/redux/reducer.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from "redux";
2 |
3 | import AccountsReducer from "./accounts/reducers";
4 | import CoreReducer from "./core/reducers";
5 | import LotusReducer from "./lotus/reducers";
6 | import RequestCacheReducer from "./request-cache/reducers";
7 | import TipsetsReducer from "./tipsets/reducers";
8 | import MessagesReducer from "./messages/reducers";
9 | import DealsReducer from "./deals/reducers";
10 | import FilesReducer from "./files/reducers";
11 |
12 | export default () => {
13 | const appReducer = combineReducers({
14 | accounts: AccountsReducer,
15 | core: CoreReducer,
16 | lotus: LotusReducer,
17 | requestCache: RequestCacheReducer,
18 | tipsets: TipsetsReducer,
19 | messages: MessagesReducer,
20 | deals: DealsReducer,
21 | files: FilesReducer,
22 | });
23 |
24 | return appReducer;
25 | };
26 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/common/redux/request-cache/actions.js:
--------------------------------------------------------------------------------
1 | import FilecoinPrefix from "../prefix";
2 |
3 | const prefix = `${FilecoinPrefix}/CACHE`;
4 |
5 | const createCacheId = function(payload) {
6 | let params = payload.params
7 | .map(param => {
8 | return param.toString();
9 | })
10 | .join(",");
11 | return `${payload.method}(${params})`;
12 | };
13 |
14 | export const CACHE_REQUEST = `${prefix}/CACHE_REQUEST`;
15 | export const cacheRequest = function(payload, response) {
16 | let id = createCacheId(payload);
17 | return { type: CACHE_REQUEST, id, response };
18 | };
19 |
20 | export const checkCache = function(payload, getState) {
21 | // Never cache "Filecoin.ChainHead"
22 | if (payload.method == "Filecoin.ChainHead") {
23 | return null;
24 | }
25 |
26 | let cache = getState().requestCache;
27 | let id = createCacheId(payload);
28 | let hit = cache[id];
29 |
30 | if (!hit) {
31 | return null;
32 | }
33 |
34 | // Tailor the response to the new rpc id
35 | var response = Object.assign({}, hit);
36 | response.id = payload.id;
37 | return response;
38 | };
39 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/common/redux/request-cache/reducers.js:
--------------------------------------------------------------------------------
1 | import * as RequestCache from "./actions";
2 | import * as Core from "../core/actions";
3 |
4 | const initialState = {};
5 |
6 | // These requests are never invalidated.
7 | const HARD_CACHED = {
8 | version: true,
9 | chainGetGenesis: true,
10 | actorAddress: true,
11 | stateListMiners: true,
12 | stateMinerPower: true,
13 | // stateMinerInfo: true, // TODO
14 | walletValidateAddress: true
15 | };
16 |
17 | const isHardCached = function(id) {
18 | const method = id.substring(0, id.indexOf("("));
19 |
20 | const hardCachedResult = HARD_CACHED[method];
21 |
22 | if (typeof hardCachedResult == "function") {
23 | const split = id.split(/\(|\)/);
24 | let params = split[1];
25 |
26 | if (params == "") {
27 | params = [];
28 | } else {
29 | params = params.split(",");
30 | }
31 |
32 | return hardCachedResult.apply(null, params);
33 | } else {
34 | return !!hardCachedResult;
35 | }
36 | };
37 |
38 | export default function(state = initialState, action) {
39 | switch (action.type) {
40 | case RequestCache.CACHE_REQUEST:
41 | return Object.assign({}, state, {
42 | [action.id]: action.response,
43 | });
44 |
45 | case Core.SET_TIPSET_NUMBER: {
46 | // Invalidate the cache on new block number
47 | const cache = Object.assign({}, state);
48 |
49 | Object.keys(cache).forEach(id => {
50 | if (!isHardCached(id)) {
51 | delete cache[id];
52 | }
53 | });
54 |
55 | return cache;
56 | }
57 | default:
58 | return state;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/common/utils/cid.js:
--------------------------------------------------------------------------------
1 | export function abbreviateCid(cid, numChars) {
2 | return `${cid.slice(0, numChars)}…${cid.slice(cid.length - numChars)}`;
3 | }
4 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/components/formatted-fil-value/FormattedFILValue.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import PropTypes from "prop-types";
3 |
4 | export default class FormattedFILValue extends Component {
5 | render() {
6 | let attoFil;
7 | if (this.props.fromUnit === "fil") {
8 | // Using BigInt with the current versions of eslint
9 | // and babel-eslint require larger upgrades to both.
10 | // I chose not to do this currently as it may not be worth
11 | // the effort, especially if y'all are thinking of doing
12 | // a refactor
13 | // eslint-disable-next-line no-undef
14 | attoFil = BigInt(this.props.value) * 1000000000000000000n
15 | } else {
16 | // eslint-disable-next-line no-undef
17 | attoFil = BigInt(this.props.value);
18 | }
19 |
20 | let resultFil;
21 | if (this.props.toUnit === "fil") {
22 | resultFil = Number(attoFil * 100n / 1000000000000000000n) / 100;
23 | } else {
24 | resultFil = attoFil;
25 | }
26 | const value = resultFil.toFixed(2);
27 | return (
28 | {`${value} ${this.props.toUnit.toUpperCase()}`}
31 | );
32 | }
33 | }
34 |
35 | FormattedFILValue.propTypes = {
36 | value: PropTypes.string,
37 | fromUnit: PropTypes.string,
38 | toUnit: PropTypes.string,
39 | };
40 |
41 | FormattedFILValue.defaultProps = {
42 | fromUnit: "attofil",
43 | toUnit: "fil",
44 | };
45 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/accounts/AccountList.scss:
--------------------------------------------------------------------------------
1 | .FilecoinAccountList {
2 | width: 100%;
3 | padding: 0;
4 |
5 | position: relative;
6 |
7 | .AccountCard {
8 | display: flex;
9 | flex-direction: row;
10 | align-items: center;
11 | justify-content: space-between;
12 | padding: 1.3rem .8rem;
13 | background-color: var(--app-card-default-background);
14 | position: relative;
15 | border-bottom: 1px solid #aaa;
16 |
17 | svg {
18 | stroke-width: 4;
19 | width: 24px;
20 | height: 24px;
21 | }
22 | }
23 |
24 | .AccountAddress {
25 | font-weight: bold;
26 | margin-right: 2rem;
27 |
28 | .Value {
29 | font-size: 1.222222222rem;
30 | }
31 | }
32 |
33 | .AccountBalance {
34 | width: 20%;
35 | .Value {
36 | font-weight: bold;
37 | font-size: 1.222222222rem;
38 | }
39 | }
40 |
41 | .AddressAndBalance {
42 | display: flex;
43 | flex-direction: row;
44 | }
45 |
46 | .AccountPrivateKey {
47 | .Label,
48 | .Value {
49 | font-size: 14px;
50 | }
51 | }
52 |
53 | .AccountState {
54 | font-size: 2rem;
55 | background: #ffffff;
56 | border-radius: 50%;
57 | width: 3rem;
58 | height: 3rem;
59 | border: 2px solid gray;
60 | display: flex;
61 | align-items: center;
62 | justify-content: center;
63 | margin-left: 1rem;
64 | }
65 |
66 | .SecondaryInfo {
67 | display: flex;
68 | justify-content: flex-end;
69 | align-items: center;
70 | width: 20%;
71 |
72 | > div {
73 | width: 30%;
74 | margin-right: 0.5rem;
75 | }
76 | }
77 |
78 | .ShowKeys {
79 | cursor: pointer;
80 | margin-right: 0.7rem;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/accounts/AccountsBanner.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from "react";
2 |
3 | import SeedInfoModal from "./SeedInfoModal";
4 |
5 | import OnlyIf from "../../../../../renderer/components/only-if/OnlyIf";
6 |
7 | export default class AccountsBanner extends PureComponent {
8 | constructor(props) {
9 | super(props);
10 | this.state = {
11 | showWarning: false,
12 | };
13 | }
14 |
15 | showWarning() {
16 | this.setState({
17 | showWarning: true,
18 | });
19 | }
20 |
21 | hideWarning() {
22 | this.setState({
23 | showWarning: false,
24 | });
25 | }
26 |
27 | render() {
28 | return (
29 |
30 |
31 |
32 | SEED{" "}
33 |
37 | ?
38 |
39 |
40 | {this.props.seed}
41 |
42 |
43 |
44 |
45 |
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/accounts/AccountsBanner.scss:
--------------------------------------------------------------------------------
1 |
2 | .FilecoinAccountsBanner {
3 | display: flex;
4 | background-color: var(--app-mnemonic-background-color);
5 | font-size: 0.8em;
6 | margin: 0;
7 | border-bottom: 1px solid #aaa;
8 |
9 | .Seed {
10 | flex-grow: 1;
11 | }
12 |
13 | .Seed {
14 | margin: 1rem;
15 |
16 | h4 {
17 | margin: 0 0 .3rem 0;
18 | }
19 |
20 | span {
21 | font-family: "Fira Code Regular", monospace;
22 | color: var(--text-color);
23 | font-size: 0.9rem;
24 | }
25 |
26 | .WarningIndicator {
27 | font-size: 0.8rem;
28 | padding: 0 .125rem;
29 | border: 2px solid transparent;
30 | border-radius: .35rem;
31 | color: white;
32 | background: #DDD;
33 | display: inline-block;
34 | margin-left: .3rem;
35 | font-weight: bold;
36 | cursor: pointer;
37 |
38 | &:hover {
39 | background: #ebb67e;
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/accounts/AccountsScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | import connect from "../../../../../renderer/screens/helpers/connect";
4 |
5 | import AccountsBanner from "./AccountsBanner";
6 | import AccountList from "./AccountList";
7 |
8 | class AccountsScreen extends Component {
9 | constructor(props) {
10 | super(props);
11 |
12 | this.state = {};
13 | }
14 |
15 | render() {
16 | return (
17 |
32 | );
33 | }
34 | }
35 |
36 | export default connect(
37 | AccountsScreen,
38 | ["filecoin.core", "core"],
39 | ["filecoin.accounts", "accounts"]
40 | );
41 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/accounts/AccountsScreen.scss:
--------------------------------------------------------------------------------
1 | .FilecoinAccountsScreen {
2 | width: 100%;
3 | display: flex;
4 | flex: 1;
5 | flex-direction: column;
6 | position: relative;
7 |
8 | main {
9 | padding: 0;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/accounts/KeyModal.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from "react";
2 |
3 | import Modal from "../../../../../renderer/components/modal/Modal";
4 |
5 | export default class KeyModal extends PureComponent {
6 | render() {
7 | return (
8 |
9 |
10 | ACCOUNT INFORMATION
11 |
12 |
13 |
14 |
15 | ACCOUNT ADDRESS
16 |
17 | {this.props.accountAddress}
18 |
19 |
20 |
21 | PRIVATE KEY
22 |
23 | {this.props.privateKey}
24 |
25 |
26 | Do not use this private key on a public blockchain; use it for
27 | development purposes only!
28 |
29 |
30 |
31 |
34 |
35 |
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/accounts/KeyModal.scss:
--------------------------------------------------------------------------------
1 | .FilecoinKeyModal {
2 | section, header {
3 | width: 680px;
4 | }
5 | svg {
6 | width: 28px;
7 | height: 28px;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/accounts/SeedInfoModal.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from "react";
2 |
3 | import Modal from "../../../../../renderer/components/modal/Modal";
4 |
5 | export default class SeedInfoModal extends PureComponent {
6 | render() {
7 | return (
8 |
9 |
10 | About Your Seed
11 |
12 |
13 |
14 |
15 | Your seed is used by Ganache to initiate the random number generator.
16 | The random number generator is used to generate the addresses available
17 | during development as well as any other randomness.
18 |
19 |
20 | Using the same seed will generate the same accounts and be as close to
21 | deterministic behavior as possible.
22 |
23 |
24 | Ganache currently doesn't generate a mnemonic for Filecoin addresses.
25 |
26 |
29 |
30 |
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/accounts/SeedInfoModal.scss:
--------------------------------------------------------------------------------
1 | .FilecoinSeedInfoModal {
2 | section, header {
3 | width: 680px;
4 | }
5 | svg {
6 | width: 28px;
7 | height: 28px;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/config/ConfigScreens/WorkspaceScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | class WorkspaceScreen extends Component {
4 | state = { selectedIdx: null };
5 |
6 | validateChange = e => {
7 | this.props.validateChange(e, {});
8 | };
9 |
10 | render() {
11 | const { name } = this.props.config.settings.workspace;
12 | return (
13 |
14 |
WORKSPACE
15 |
16 | WORKSPACE NAME
17 |
18 |
19 |
26 |
27 |
28 |
A friendly name for this workspace.
29 |
30 |
31 |
32 |
33 | );
34 | }
35 | }
36 |
37 | export default WorkspaceScreen;
38 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/deals/DealList.scss:
--------------------------------------------------------------------------------
1 | .DealList {
2 | width: 100%;
3 | height: 100%;
4 | background: white;
5 | }
6 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/deals/DealStatusBadge.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import connect from "../../../../../renderer/screens/helpers/connect";
3 |
4 | class DealStatusBadge extends Component {
5 | render() {
6 | return (
7 |
8 | {this.props.core.StorageDealStatus[this.props.status] || "UNKNOWN"}
9 |
10 | );
11 | }
12 | }
13 |
14 | export default connect(
15 | DealStatusBadge,
16 | ["filecoin.core", "core"]
17 | );
18 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/deals/DealStatusBadge.scss:
--------------------------------------------------------------------------------
1 | .DealStatusBadge {
2 | font-size: .75rem;
3 | padding: 8px;
4 | height: 28px;
5 | border-radius: 25px;
6 | font-weight: bold;
7 | background-color: var(--complimentary1);
8 | color: white;
9 | }
10 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/deals/DealsScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import connect from "../../../../../renderer/screens/helpers/connect";
3 | import * as Deals from "../../../common/redux/deals/actions";
4 | import DealList from "./DealList";
5 |
6 | class DealsContainer extends Component {
7 | constructor(props) {
8 | super(props);
9 | }
10 |
11 | componentDidMount() {
12 | this.props.dispatch(Deals.requestPage());
13 | }
14 |
15 | render() {
16 | return (
17 |
18 |
19 |
20 | );
21 | }
22 | }
23 |
24 | export default connect(
25 | DealsContainer,
26 | ["filecoin.deals", "deals"]
27 | );
28 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/deals/DealsScreen.scss:
--------------------------------------------------------------------------------
1 | .DealsScreen {
2 | display: flex;
3 | flex-direction: column;
4 |
5 | height: 100%;
6 | width: 100%;
7 | }
8 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/deals/MiniDealCard.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from "react";
2 | import Moment from "react-moment";
3 |
4 | import DealStatusBadge from "./DealStatusBadge";
5 |
6 | export default class MiniDealCard extends PureComponent {
7 | render() {
8 | const { deal } = this.props;
9 | const cardStyles = `MiniDealCard`;
10 |
11 | return (
12 |
13 |
14 |
15 |
DEAL
16 |
{deal.DealID}
17 |
18 |
19 |
20 |
21 |
22 |
DEAL CID
23 |
{deal.ProposalCid["/"]}
24 |
25 |
26 |
27 |
28 |
CREATED
29 |
30 |
31 | {deal.CreationTime}
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/deals/MiniDealCard.scss:
--------------------------------------------------------------------------------
1 | .MiniDealCard {
2 | width: 100%;
3 | background: var(--app-card-default-background);
4 | word-wrap: break-word;
5 | margin: 0;
6 | display: flex;
7 | align-items: center;
8 | transition: all .3s;
9 | border-bottom: 1px solid #aaa;
10 |
11 | &:hover {
12 | }
13 |
14 | .Link {
15 | text-decoration: none;
16 | width: 100%;
17 | }
18 |
19 | .RowItem {
20 | display: flex;
21 | flex-direction: row;
22 | justify-content: space-between;
23 | align-items: center;
24 | }
25 |
26 | .PrimaryItems {
27 | display: flex;
28 | align-items: center;
29 | justify-content: space-between;
30 | padding: 0 2rem;
31 | width: 100%;
32 | }
33 |
34 | .DealID,
35 | .DealCID {
36 | display: flex;
37 | flex-direction: column;
38 | }
39 |
40 | .DealID {
41 | align-items: center;
42 | padding: .8rem;
43 | background-color: var(--subtle-green);
44 | min-width: 8vw;
45 |
46 | .Value {
47 | font-weight: bold;
48 | }
49 | }
50 |
51 | .DealCID {
52 | .Value {
53 | font-size: 1.46vw;
54 | }
55 | }
56 |
57 | .MinedOn {
58 | .Label {
59 | font-size: .625rem;
60 | letter-spacing: 1.2px;
61 | }
62 |
63 | .Value {
64 | font-size: .825rem;
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/files/FileList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import MDSpinner from "react-md-spinner";
3 | import connect from "../../../../../renderer/screens/helpers/connect";
4 |
5 | import MiniFileCard from "./MiniFileCard";
6 |
7 | class FileList extends Component {
8 | constructor(props) {
9 | super(props);
10 | }
11 |
12 | render() {
13 | var content;
14 | if (this.props.files.inView.length > 0) {
15 | content = this.props.files.inView.map(file => {
16 | return (
17 |
21 | );
22 | });
23 | } else {
24 | if (this.props.loading) {
25 | content = (
26 |
27 |
34 |
35 | );
36 | } else {
37 | content = No files
;
38 | }
39 | }
40 |
41 | return {content}
;
42 | }
43 | }
44 |
45 | export default connect(
46 | FileList,
47 | ["filecoin.core", "core"],
48 | ["filecoin.files", "files"],
49 | "appshell",
50 | );
51 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/files/FileList.scss:
--------------------------------------------------------------------------------
1 | .FileList {
2 | width: 100%;
3 | height: 100%;
4 | background: white;
5 | }
6 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/files/FilesScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import connect from "../../../../../renderer/screens/helpers/connect";
3 | import * as Files from "../../../common/redux/files/actions";
4 | import FileList from "./FileList";
5 |
6 | class FilesContainer extends Component {
7 | constructor(props) {
8 | super(props);
9 |
10 | this.state = {
11 | pollInterval: null
12 | };
13 | }
14 |
15 | componentDidMount() {
16 | this.props.dispatch(Files.addFilesToView());
17 | const pollInterval = setInterval(() => {
18 | this.props.dispatch(Files.addFilesToView());
19 | }, 5000);
20 |
21 | this.setState({
22 | pollInterval
23 | });
24 | }
25 |
26 | componentWillUnmount() {
27 | if (this.state.pollInterval) {
28 | clearInterval(this.state.pollInterval);
29 | this.setState({
30 | pollInterval: null
31 | });
32 | }
33 | }
34 |
35 | render() {
36 | return (
37 |
45 | );
46 | }
47 | }
48 |
49 | export default connect(
50 | FilesContainer,
51 | );
52 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/files/FilesScreen.scss:
--------------------------------------------------------------------------------
1 | .FilesScreen {
2 | display: flex;
3 | flex-direction: column;
4 |
5 | height: 100%;
6 | width: 100%;
7 |
8 | .Header {
9 | margin-left: 1rem;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/files/MiniFileCard.scss:
--------------------------------------------------------------------------------
1 | .MiniFileCard {
2 | width: 100%;
3 | background: var(--app-card-default-background);
4 | word-wrap: break-word;
5 | margin: 0;
6 | display: flex;
7 | align-items: center;
8 | transition: all .3s;
9 | border-bottom: 1px solid #aaa;
10 |
11 | &:first-child {
12 | border-top: 1px solid #aaa;
13 | }
14 |
15 | &:hover {
16 | }
17 |
18 | .Link {
19 | text-decoration: none;
20 | width: 100%;
21 | }
22 |
23 | .RowItem {
24 | display: flex;
25 | flex-direction: row;
26 | justify-content: space-between;
27 | align-items: center;
28 | }
29 |
30 | .PrimaryItems {
31 | display: flex;
32 | align-items: center;
33 | justify-content: space-between;
34 | padding: 1rem;
35 | width: 100%;
36 | }
37 |
38 | .Name {
39 | min-width: 15rem;
40 | }
41 |
42 | .Size {
43 | min-width: 7rem;
44 | }
45 |
46 | .Name,
47 | .Size {
48 | .Label {
49 | font-size: .625rem;
50 | letter-spacing: 1.2px;
51 | }
52 |
53 | .Value {
54 | font-size: .825rem;
55 | }
56 | }
57 |
58 | .Download {
59 | button.Error {
60 | background-color: var(--error);
61 | }
62 |
63 | button.Complete {
64 | background-color: var(--subtle-green);
65 | }
66 |
67 | span {
68 | font-size: 1rem;
69 | }
70 |
71 | svg {
72 | margin-left: 0.5rem;
73 | width: 1rem;
74 | vertical-align: text-bottom;
75 | fill: var(--app-button-primary-background-color);
76 | }
77 |
78 | .ProgressBarOuter {
79 | height: 0.3rem;
80 | border-width: 0;
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/messages/MessageList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import MDSpinner from "react-md-spinner";
3 |
4 | import MiniMessageCard from "./MiniMessageCard";
5 |
6 | class MessageList extends Component {
7 | render() {
8 | var content;
9 | if (this.props.messages.length > 0) {
10 | content = this.props.messages.map(message => {
11 | return (
12 |
16 | );
17 | });
18 | } else {
19 | if (this.props.loading) {
20 | content = (
21 |
22 |
29 |
30 | );
31 | } else {
32 | content = No messages
;
33 | }
34 | }
35 |
36 | return {content}
;
37 | }
38 | }
39 |
40 | export default MessageList;
41 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/messages/MessageList.scss:
--------------------------------------------------------------------------------
1 | .MessageList {
2 | width: 100%;
3 | height: 100%;
4 | background: white;
5 | display: flex;
6 | flex-direction: column;
7 | flex-grow: 1;
8 | }
9 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/messages/MessageTypeBadge.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | export default class MessageTypeBadge extends Component {
4 | render() {
5 | if (this.props.method === 0) {
6 | return (
7 |
8 | VALUE TRANSFER
9 |
10 | );
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/messages/MessageTypeBadge.scss:
--------------------------------------------------------------------------------
1 | .MessageTypeBadge {
2 | font-size: .75rem;
3 | padding: 8px;
4 | height: 28px;
5 | border-radius: 25px;
6 | font-weight: bold;
7 | min-width: 7.5rem;
8 |
9 | &.ValueTransferBadge {
10 | background-color: var(--truffle-green);
11 | color: white;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/messages/MessagesScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import connect from "../../../../../renderer/screens/helpers/connect";
3 | import * as Messages from "../../../common/redux/messages/actions";
4 | import RecentMessages from "./RecentMessages";
5 | import MessageCard from "./MessageCard";
6 |
7 | class MessagesScreen extends Component {
8 | componentDidMount() {
9 | this.props.dispatch(Messages.requestPage());
10 | }
11 |
12 | componentWillUnmount() {
13 | this.props.dispatch(Messages.clearMessagesInView());
14 | }
15 |
16 | render() {
17 | var content;
18 | if (this.props.match.params.messageCid != null) {
19 | content = ;
20 | } else {
21 | content = (
22 |
23 | );
24 | }
25 | return {content}
;
26 | }
27 | }
28 |
29 | export default connect(MessagesScreen);
30 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/messages/MessagesScreen.scss:
--------------------------------------------------------------------------------
1 | .MessagesScreen {
2 | display: flex;
3 | flex-direction: column;
4 |
5 | height: 100%;
6 | width: 100%;
7 |
8 | > main {
9 | padding: 0;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/messages/MiniMessageCard.scss:
--------------------------------------------------------------------------------
1 | .MiniMessageCard {
2 | font-family: "Fira Code Regular", monospaced;
3 | width: 100%;
4 | cursor: pointer;
5 | margin: .5rem 0;
6 | background: var(--app-card-default-background);
7 | padding: 28px 18px;
8 | word-wrap: break-word;
9 | cursor: pointer;
10 | display: flex;
11 | flex-direction: column;
12 | margin: 0;
13 | transition: all .3s;
14 | border-bottom: 1px solid #aaa;
15 |
16 | .Row {
17 | // display: flex;
18 | // align-items: center;
19 | // flex-direction: row;
20 | margin-bottom: 1rem;
21 | // justify-content: space-between;
22 | display: grid;
23 | grid-template-columns: 1fr 1fr 120px 200px;
24 |
25 | &.Top {
26 | display: flex;
27 | justify-content: space-between;
28 | }
29 |
30 | &:last-of-type {
31 | margin-bottom: 0;
32 | }
33 | }
34 |
35 | .RowItem {
36 | display: flex;
37 | flex-direction: row;
38 | justify-content: space-between;
39 | cursor: pointer;
40 |
41 | &:not(:last-child) {
42 | padding-right: 1rem;
43 | }
44 | }
45 |
46 | .Nonce,
47 | .GasUsed,
48 | .Value,
49 | .MinedOn {
50 | .Label {
51 | font-size: .625rem;
52 | letter-spacing: 1.2px;
53 | }
54 |
55 | .Value {
56 | font-size: .825rem;
57 | }
58 | }
59 |
60 | .MessageCID {
61 | .Value {
62 | font-weight: bold;
63 | }
64 | }
65 |
66 | .SecondaryItems {
67 | .Value {
68 | font-size: .825rem;
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/messages/RecentMessages.scss:
--------------------------------------------------------------------------------
1 | .RecentMessages {
2 | flex-grow: 1;
3 | display: flex;
4 | height: 100%;
5 | }
6 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/tipsets/BlockCard.scss:
--------------------------------------------------------------------------------
1 | .FilecoinBlockCard {
2 | font-family: "Fira Code Regular", sans-serif;
3 | background: var(--app-card-default-background);
4 | display: flex;
5 | flex-direction: column;
6 | flex-grow: 1;
7 | margin: 0;
8 | border-radius: 4px;
9 | word-wrap: break-word;
10 | width: 100%;
11 |
12 | header {
13 | width: 100%;
14 | height: 64px;
15 | display: flex;
16 | flex-direction: row;
17 | justify-content: flex-start;
18 | background-color: #fff;
19 | border-bottom: 1px solid #aaa;
20 | line-height: 1;
21 |
22 | h1 {
23 | font-size: 1.5rem;
24 | padding: 1.25rem;
25 | margin: 0;
26 | }
27 | }
28 |
29 | .Button {
30 | text-decoration: none;
31 | text-align: center;
32 | margin: 0;
33 | }
34 |
35 | header button {
36 | border-radius: 0;
37 | line-height: 1;
38 | height: 100%;
39 | }
40 |
41 | .BlockBody {
42 | padding: 1rem 0;
43 | border-bottom: 1px solid #aaa;
44 |
45 | > div {
46 | padding: 1rem;
47 | }
48 | }
49 |
50 | .HeaderSecondaryInfo {
51 | display: flex;
52 | align-items: center;
53 | justify-content: space-between;
54 | width: 100%;
55 | padding: 1rem;
56 | }
57 |
58 | .MessageList {
59 | .Waiting {
60 | margin-top: 10rem;
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/tipsets/BlockList.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import connect from "../../../../../renderer/screens/helpers/connect";
3 |
4 | import MiniBlockCard from "./MiniBlockCard";
5 |
6 | class BlockList extends Component {
7 | constructor(props) {
8 | super(props);
9 | }
10 |
11 | render() {
12 | const blocksWithCids = [];
13 | for (let i = 0; i < this.props.blocks.length; i++) {
14 | blocksWithCids.push({
15 | block: this.props.blocks[i],
16 | cid: this.props.cids[i]["/"]
17 | });
18 | }
19 |
20 | return (
21 |
22 | {blocksWithCids.map(blockWithCid => {
23 | return (
24 |
29 | );
30 | })}
31 |
32 | );
33 | }
34 | }
35 |
36 | export default connect(
37 | BlockList,
38 | ["filecoin.core", "core"],
39 | ["filecoin.tipsets", "tipsets"],
40 | "appshell",
41 | );
42 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/tipsets/TipsetCard.scss:
--------------------------------------------------------------------------------
1 | .TipsetCard {
2 | font-family: "Fira Code Regular", sans-serif;
3 | background: var(--app-card-default-background);
4 | display: flex;
5 | flex-direction: column;
6 | flex-grow: 1;
7 | margin: 0;
8 | border-radius: 4px;
9 | word-wrap: break-word;
10 | width: 100%;
11 |
12 | header {
13 | width: 100%;
14 | height: 64px;
15 | display: flex;
16 | flex-direction: row;
17 | justify-content: flex-start;
18 | background-color: #fff;
19 | border-bottom: 1px solid #aaa;
20 | line-height: 1;
21 |
22 | h1 {
23 | font-size: 1.5rem;
24 | padding: 1.25rem;
25 | margin: 0;
26 | }
27 | }
28 |
29 | .Button {
30 | text-decoration: none;
31 | text-align: center;
32 | margin: 0;
33 | }
34 |
35 | header button {
36 | border-radius: 0;
37 | line-height: 1;
38 | height: 100%;
39 | }
40 |
41 | .TipsetBody {
42 | padding: 1rem 0;
43 | border-bottom: 1px solid #aaa;
44 |
45 | > div {
46 | padding: 1rem;
47 | }
48 | }
49 |
50 | .HeaderSecondaryInfo {
51 | display: flex;
52 | align-items: center;
53 | width: 100%;
54 | padding: 1rem;
55 |
56 | > div {
57 | margin-right: 2rem;
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/tipsets/TipsetList.scss:
--------------------------------------------------------------------------------
1 | .TipsetList {
2 | width: 100%;
3 | background: white;
4 | }
5 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/tipsets/TipsetsScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import connect from "../../../../../renderer/screens/helpers/connect";
3 | import * as Tipsets from "../../../common/redux/tipsets/actions";
4 | import TipsetList from "./TipsetList";
5 | import TipsetCard from "./TipsetCard";
6 |
7 | class TipsetsContainer extends Component {
8 | constructor(props) {
9 | super(props);
10 | }
11 |
12 | componentDidMount() {
13 | this.props.dispatch(Tipsets.requestPage());
14 | }
15 |
16 | render() {
17 | var content;
18 | if (this.props.match.params.tipsetHeight != null) {
19 | content = ;
20 | } else {
21 | content = ;
22 | }
23 | return {content}
;
24 | }
25 | }
26 |
27 | export default connect(
28 | TipsetsContainer,
29 | ["filecoin.tipsets", "tipsets"]
30 | );
31 |
--------------------------------------------------------------------------------
/src/integrations/filecoin/renderer/screens/tipsets/TipsetsScreen.scss:
--------------------------------------------------------------------------------
1 | .TipsetsScreen {
2 | display: flex;
3 | flex-direction: column;
4 |
5 | height: 100%;
6 | width: 100%;
7 | }
8 |
--------------------------------------------------------------------------------
/src/integrations/integrations.js:
--------------------------------------------------------------------------------
1 | import { EventEmitter } from "events";
2 |
3 | class Integrations extends EventEmitter {
4 | constructor(integrationManager) {
5 | super();
6 | this._integrationManager = integrationManager;
7 | this.ipc = this._integrationManager.ipc;
8 | this.chain = null;
9 | this.send = integrationManager.emit.bind(integrationManager, "send");
10 | }
11 | async start() {
12 | if (this.chain) {
13 | return this.chain.start();
14 | }
15 | }
16 | async startServer(workspaceSettings, workspaceDirectory) {
17 | if (this.chain) {
18 | return this.chain.startServer(workspaceSettings, workspaceDirectory);
19 | }
20 | }
21 | async stop() {
22 | if (this.chain) {
23 | return this.chain.stop();
24 | }
25 | }
26 | async stopServer() {
27 | if (this.chain) {
28 | return this.chain.stopServer();
29 | }
30 | }
31 | }
32 |
33 | export default Integrations;
34 |
--------------------------------------------------------------------------------
/src/main/types/json/JsonStorage.js:
--------------------------------------------------------------------------------
1 | import { LocalStorage } from "node-localstorage";
2 |
3 | import JsonWithKeyPaths from "./JsonWithKeyPaths";
4 |
5 | class JsonStorage {
6 | constructor(directory, name, obj) {
7 | this.obj = new JsonWithKeyPaths(obj);
8 | this.name = name;
9 | this.setStorageDirectory(directory);
10 | }
11 |
12 | setStorageDirectory(directory) {
13 | this.directory = directory;
14 | this.storage = new LocalStorage(this.directory, Infinity);
15 | }
16 |
17 | getFromStorage() {
18 | const data = JSON.parse(this.storage.getItem(this.name));
19 | this.obj.setAll(data);
20 | return data;
21 | }
22 |
23 | // if defaultValue is set, and neither the cache nor storage has the key
24 | // the cache and storage will be set to the defaultValue
25 | get(key, defaultValue = null) {
26 | if (this.obj.has(key)) {
27 | return this.obj.get(key);
28 | } else {
29 | // check storage
30 | this.getFromStorage();
31 | // we use this.obj again because getFromStorage refreshes the cache
32 | if (this.obj.has(key)) {
33 | return this.obj.get(key);
34 | } else if (defaultValue !== null) {
35 | this.set(key, defaultValue);
36 | return defaultValue;
37 | } else {
38 | return undefined;
39 | }
40 | }
41 | }
42 |
43 | getAll() {
44 | return this.getFromStorage();
45 | }
46 |
47 | setToStorage() {
48 | this.storage.setItem(this.name, JSON.stringify(this.obj.obj));
49 | }
50 |
51 | set(key, value) {
52 | this.obj.set(key, value);
53 | this.setToStorage();
54 | }
55 |
56 | setAll(value) {
57 | this.obj.setAll(value);
58 | this.setToStorage();
59 | }
60 | }
61 |
62 | export default JsonStorage;
63 |
--------------------------------------------------------------------------------
/src/main/types/settings/GlobalSettings.js:
--------------------------------------------------------------------------------
1 | import Settings from "./Settings";
2 |
3 | const initialSettings = {
4 | googleAnalyticsTracking: true,
5 | cpuAndMemoryProfiling: false,
6 | firstRun: true,
7 | };
8 |
9 | class GlobalSettings extends Settings {
10 | constructor(directory) {
11 | super(directory, initialSettings);
12 | }
13 |
14 | bootstrap() {
15 | super.bootstrap();
16 | }
17 | }
18 |
19 | export default GlobalSettings;
20 |
--------------------------------------------------------------------------------
/src/main/types/settings/flavors/ethereum.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | name: "Quickstart",
3 | isDefault: true,
4 | verboseLogging: false,
5 | randomizeMnemonicOnStart: false,
6 | logsDirectory: null,
7 | server: {
8 | hostname: "127.0.0.1",
9 | port: 7545,
10 | network_id: 5777,
11 | default_balance_ether: 100,
12 | total_accounts: 10,
13 | unlocked_accounts: [],
14 | locked: false,
15 | vmErrorsOnRPCResponse: true,
16 | logger: null,
17 | verbose: false,
18 | gasLimit: 6721975,
19 | gasPrice: 20000000000,
20 | hardfork: "merge",
21 | fork: null,
22 | fork_block_number: null
23 | },
24 | projects: [],
25 | }
--------------------------------------------------------------------------------
/src/main/types/settings/flavors/filecoin.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | name: "Quickstart",
3 | isDefault: true,
4 | verboseLogging: false,
5 | randomizeSeedOnStart: true,
6 | logsDirectory: null,
7 | server: {
8 | hostname: "127.0.0.1",
9 | port: 7777,
10 | chain: {},
11 | database: {},
12 | logging: {},
13 | miner: {},
14 | wallet: {}
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/renderer/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import routes from "./routes";
3 | import { ConnectedRouter } from "connected-react-router";
4 |
5 | class App extends Component {
6 | render() {
7 | return ({routes} );
8 | }
9 | }
10 |
11 | export default App;
12 |
--------------------------------------------------------------------------------
/src/renderer/README.md:
--------------------------------------------------------------------------------
1 | Here you can add all of your renderer process code. Bundling of the renderer process is optional for cases where you may want to use an external tool such as electron-next: https://github.com/leo/electron-next
2 |
3 |
4 | Notice that there isn’t a entry index.html, that’s because it is created for you
5 | More info: https://webpack.electron.build/development#use-of-html-webpack-plugin
6 |
--------------------------------------------------------------------------------
/src/renderer/components/google-analytics/GoogleAnalytics.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from "react";
2 |
3 | export default class HeaderBar extends PureComponent {
4 | render() {
5 | return (
6 | <>
7 | ANALYTICS
8 |
9 | GOOGLE ANALYTICS
10 |
11 |
12 |
13 |
23 |
24 | GOOGLE ANALYTICS
25 |
26 |
27 |
28 |
29 |
30 | We use Google Analytics to track Ganache usage. This information
31 | helps us gain more insight into how Ganache is used. This
32 | tracking is anonymous. We do not track personally identifiable
33 | information, account data or private keys.
34 |
35 | Note: This setting is global and will persist between
36 | workspaces.
37 |
38 |
39 |
40 |
41 | >
42 | );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/renderer/components/header-bar/HeaderBar.css:
--------------------------------------------------------------------------------
1 | @import "colors.css";
2 |
3 | .Header {
4 | position: -webkit-sticky;
5 | position: sticky;
6 | top: -1px;
7 | background: white;
8 | font-size: 2.5vw;
9 | height: 32px;
10 | font-family: "RobotoCondensed-Bold";
11 | margin: .5em;
12 | padding: .8em 0;
13 | border-bottom: 2px solid rgba(155, 152, 150, 1.000);
14 | z-index: 2;
15 | display: flex;
16 | align-items: center;
17 |
18 | * {
19 | stroke: var(--primary-color) !important;
20 | }
21 |
22 | > div {
23 | margin-right: .25em;
24 | }
25 |
26 | > h4 {
27 | flex: 1;
28 | line-height: 1;
29 | margin: 0;
30 | }
31 |
32 | span {
33 | a {
34 | background: rgba(44, 54, 67, 1.000);
35 | border-radius: 4px;
36 | color: var(--app-button-primary-color);
37 | padding: .5rem;
38 | text-decoration: none;
39 | font-size: .8rem;
40 | text-transform: uppercase;
41 |
42 | &:hover {
43 | color: lighten( var(--app-button-primary-color), 10%);
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/renderer/components/header-bar/HeaderBar.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from "react";
2 |
3 | import Styles from "./HeaderBar.css";
4 |
5 | export default class HeaderBar extends PureComponent {
6 | render() {
7 | return ;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/renderer/components/logo/Logo.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import LogoSvg from "../../icons/logo.svg";
3 |
4 | class Logo extends React.Component {
5 | render() {
6 | const className = "Logo" + (this.props.fadeInElement ? " FadeInElement" : "")
7 | return (
8 |
13 | );
14 | }
15 | }
16 |
17 | export default Logo;
18 |
--------------------------------------------------------------------------------
/src/renderer/components/modal/Modal.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from "react";
2 |
3 | export default class Modal extends PureComponent {
4 | render() {
5 | return (
6 |
7 | {this.props.children}
8 |
9 | );
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/renderer/components/modal/ModalDetails.js:
--------------------------------------------------------------------------------
1 | import {
2 | setModalError,
3 | dismissModalError,
4 | } from "../../../common/redux/core/actions";
5 |
6 | export default class ModalDetails extends Error {
7 | static types = {
8 | WARNING: 0,
9 | ERROR: 1,
10 | };
11 |
12 | static actions = {
13 | setModalError,
14 | dismissModalError,
15 | };
16 |
17 | constructor(type, buttons, title, ...params) {
18 | super(...params);
19 |
20 | if (Error.captureStackTrace) {
21 | Error.captureStackTrace(this, ModalDetails);
22 | }
23 |
24 | this.data = {
25 | type,
26 | buttons,
27 | title,
28 | message: params[0],
29 | };
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/renderer/components/only-if/OnlyIf.js:
--------------------------------------------------------------------------------
1 | import { PureComponent } from "react";
2 |
3 | class OnlyIf extends PureComponent {
4 | render() {
5 | return this.props.test ? this.props.children : null;
6 | }
7 | }
8 |
9 | export default OnlyIf;
10 |
--------------------------------------------------------------------------------
/src/renderer/components/progress-bar/ProgressBar.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | export default class ProgressBar extends Component {
4 | render() {
5 | return (
6 |
7 |
17 | {this.props.children}
18 |
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/renderer/components/progress-bar/ProgressBar.scss:
--------------------------------------------------------------------------------
1 | .ProgressBar {
2 | .ProgressBarOuter {
3 | display: block;
4 | border-width:1px;
5 | border-style:solid;
6 | border-color: black;
7 | border-radius: 0.25rem;
8 | height: 1rem;
9 | overflow-x: hidden;
10 | overflow-y: hidden;
11 | width: 100%;
12 |
13 | .ProgressBarInner {
14 | height: 100%;
15 | width: 0%;
16 | background-color: var(--primary-color);
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/renderer/components/spinner/Spinner.css:
--------------------------------------------------------------------------------
1 | .Spinner,
2 | .Spinner:before,
3 | .Spinner:after {
4 | color: var(--primary-color);
5 | font-size: 3px;
6 | text-indent: -99999em;
7 | border-radius: 50%;
8 | position: absolute;
9 | content: '';
10 | background:var(--app-statusbar-background);
11 | }
12 | .Spinner {
13 | margin: 5em auto;
14 | position: relative;
15 | width: 10em;
16 | height: 10em;
17 | box-shadow: inset 0 0 0 1em;
18 | transform: translateZ(0);
19 | }
20 | .Spinner:before {
21 | width: 5.2em;
22 | height: 10.2em;
23 | border-radius: 10.2em 0 0 10.2em;
24 | top: 0;
25 | left: -0.1em;
26 | transform-origin: 5.2em 5.1em;
27 | animation: load2 2s infinite ease 1.5s;
28 | }
29 | .Spinner:after {
30 | width: 5.2em;
31 | height: 10.2em;
32 | border-radius: 0 10.2em 10.2em 0;
33 | top: 0;
34 | left: 5.1em;
35 | transform-origin: 0px 5.1em;
36 | animation: load2 2s infinite ease;
37 | }
38 | @keyframes load2 {
39 | 0% {
40 | transform: rotate(0deg);
41 | }
42 | 100% {
43 | transform: rotate(360deg);
44 | }
45 | }
--------------------------------------------------------------------------------
/src/renderer/components/spinner/Spinner.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | class Spinner extends Component {
4 | render() {
5 | return
;
6 | }
7 | }
8 |
9 | export default Spinner;
10 |
--------------------------------------------------------------------------------
/src/renderer/components/spinner/SpinnerButton.css:
--------------------------------------------------------------------------------
1 | .SpinnerButton {
2 | border: none;
3 | cursor: pointer;
4 | display: inline-block;
5 | position: relative;
6 | text-align: center;
7 | text-decoration: none;
8 | appearance: none;
9 | transition:padding .25s cubic-bezier(0.175, 0.885, 0.32, 1.275);
10 | }
11 |
12 | .Active {
13 | padding-right:3rem;
14 | }
15 |
16 | .Label {
17 | cursor: pointer;
18 | }
19 |
20 | .Loader {
21 | display:inline-block;
22 | font-size:3px;
23 | position:absolute;
24 | overflow:hidden;
25 | opacity:0;
26 | pointer-events: none;
27 | right:1rem;
28 | top:50%;
29 | margin-top:-3.25em;
30 | animation: spin 1s infinite steps(8);
31 | transition:opacity .5s ease-out .2s;
32 | transform-origin: 3.25em;
33 |
34 | }
35 |
36 | .Active .Loader {
37 | height:6.5em;
38 | opacity:1;
39 | width:6.5em;
40 | }
41 |
42 | .Loader:before,
43 | .Loader:after,
44 | .Loader div:before,
45 | .Loader div:after {
46 | top:0;
47 | left:3em;
48 | background-color:#999;
49 | border-radius:.2em;
50 | content:"";
51 | height:2.5em;
52 | position:absolute;
53 | width:.5em;
54 | box-shadow:0 4em #eee;
55 | transform-origin:50% 3.25em;
56 | }
57 |
58 | .Loader:after {
59 | background-color:#aaa;
60 | transform:rotate(45deg)}
61 |
62 | .Loader div:before {
63 | background-color:#bbb;
64 | transform:rotate(90deg)}
65 |
66 | .Loader div:after {
67 | background-color:#ccc;
68 | transform:rotate(135deg)}
69 |
70 | @keyframes spin {
71 | to { transform: rotate(1turn); }
72 | }
73 |
--------------------------------------------------------------------------------
/src/renderer/components/spinner/SpinnerButton.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | import Styles from "./SpinnerButton.css";
4 |
5 | export default class SpinnerButton extends Component {
6 | render() {
7 | const className = `${Styles.SpinnerButton} ${
8 | this.props.isActive ? Styles.Active : ""
9 | } ${this.props.className ? this.props.className : ""}`;
10 |
11 | return (
12 |
13 | {this.props.label}
14 |
15 |
16 |
17 |
18 | );
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/renderer/components/status-indicator/StatusIndicator.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | import OnlyIf from "../only-if/OnlyIf";
4 |
5 | export default class StatusIndicator extends Component {
6 | render() {
7 | return (
8 |
9 |
10 |
{this.props.title}
11 | {this.props.value}
12 |
13 |
14 | {this.props.children}
15 |
16 |
17 | );
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/renderer/components/status-indicator/StatusIndicator.scss:
--------------------------------------------------------------------------------
1 | .StatusIndicator {
2 | padding: 0 0rem 0 1rem;
3 | display: flex;
4 | flex-direction: row;
5 | justify-content: space-between;
6 | height: 55px;
7 | border-right: 1px solid var(--app-statusbar-item-border-color);
8 |
9 | .Metric {
10 | display: flex;
11 | flex-direction: column;
12 | justify-content: center;
13 | flex-shrink: 0;
14 |
15 | padding-right: 1rem;
16 |
17 | h4 {
18 | font-size: 10px;
19 | margin: 0;
20 | padding: 0;
21 | }
22 |
23 | span {
24 | font-size: 13px;
25 | color: var(--primary-color);
26 |
27 | &.upper {
28 | text-transform: uppercase;
29 | }
30 | }
31 | }
32 |
33 | .Indicator {
34 | display: flex;
35 | flex: 2;
36 | align-items: center;
37 | justify-content: flex-end;
38 | }
39 |
40 | .Metric + .Indicator {
41 | padding-right: 1rem;
42 | }
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/src/renderer/components/styled-select/StyledSelect.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | class StyledSelect extends Component {
4 | render() {
5 | return (
6 |
7 |
14 | {this.props.children}
15 |
16 |
17 | );
18 | }
19 | }
20 |
21 | export default StyledSelect;
22 |
--------------------------------------------------------------------------------
/src/renderer/components/styled-select/StyledSelect.scss:
--------------------------------------------------------------------------------
1 | div.StyledSelect {
2 | display: flex;
3 | position: relative;
4 | align-items: center;
5 |
6 | select {
7 | -webkit-appearance: none;
8 | color: var(--text-color);
9 | border: 1px solid var(--text-color);
10 | background-color: transparent;
11 | padding: .5rem;
12 | }
13 |
14 | &::after {
15 | display: inline-flex;
16 | position: absolute;
17 | right: 0.5rem;
18 | content: '\25bc';
19 | color: var(--text-color);
20 | pointer-events: none;
21 | }
22 | }
--------------------------------------------------------------------------------
/src/renderer/components/with-empty-state/WithEmptyState.js:
--------------------------------------------------------------------------------
1 | import React, { PureComponent } from "react";
2 |
3 | export default class WithEmptyState extends PureComponent {
4 | render() {
5 | const EmptyStateComponent = this.props.emptyStateComponent;
6 |
7 | if (this.props.test) {
8 | return ;
9 | }
10 |
11 | return this.props.children;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/renderer/icons/account.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/renderer/icons/blocks.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/renderer/icons/chain.svg:
--------------------------------------------------------------------------------
1 | chain-icon
--------------------------------------------------------------------------------
/src/renderer/icons/chevron-up-o.svg:
--------------------------------------------------------------------------------
1 | icon-chevron-up-o
--------------------------------------------------------------------------------
/src/renderer/icons/chevron-up.svg:
--------------------------------------------------------------------------------
1 | icon-chevron-up
--------------------------------------------------------------------------------
/src/renderer/icons/console.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/renderer/icons/contract-icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/icons/dots.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/renderer/icons/download.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/icons/eject.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/renderer/icons/error.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/renderer/icons/events-icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/icons/file-icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/renderer/icons/force_mine.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/src/renderer/icons/key.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/renderer/icons/list.svg:
--------------------------------------------------------------------------------
1 | list-icon
--------------------------------------------------------------------------------
/src/renderer/icons/locked.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/renderer/icons/no_transactions.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/renderer/icons/restart.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/renderer/icons/revert.svg:
--------------------------------------------------------------------------------
1 |
3 |
5 |
7 |
--------------------------------------------------------------------------------
/src/renderer/icons/save-icon.svg:
--------------------------------------------------------------------------------
1 | save-icon
--------------------------------------------------------------------------------
/src/renderer/icons/search.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/renderer/icons/settings.svg:
--------------------------------------------------------------------------------
1 | gear-icon
--------------------------------------------------------------------------------
/src/renderer/icons/snapshot.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/renderer/icons/start.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/renderer/icons/stop.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/renderer/icons/transactions.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/renderer/icons/trash-icon.svg:
--------------------------------------------------------------------------------
1 | trash-icon
--------------------------------------------------------------------------------
/src/renderer/icons/unlocked.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/src/renderer/icons/warning.svg:
--------------------------------------------------------------------------------
1 | warning-icon_1
--------------------------------------------------------------------------------
/src/renderer/index.js:
--------------------------------------------------------------------------------
1 | import { showTitleScreen } from "../common/redux/core/actions";
2 |
3 | import React from "react";
4 | import ReactDOM from "react-dom";
5 | import { AppContainer } from "react-hot-loader";
6 | import { Provider } from "react-redux";
7 | import createRootReducer from "../common/redux/reducer";
8 | import { createHashHistory } from "history";
9 | import createStore from "./init/store/createStore";
10 | import { initRenderer } from "./init/index";
11 | import { ipcRenderer } from "electron";
12 | import App from "./App";
13 | import "./css";
14 |
15 | const hashHistory = createHashHistory();
16 | const rootReducer = createRootReducer(hashHistory);
17 | const store = createStore(rootReducer, hashHistory);
18 | initRenderer(store);
19 |
20 | ipcRenderer.on("navigate", (_, path) => {
21 | hashHistory.push(path);
22 | });
23 |
24 | const render = () => {
25 | ReactDOM.render(
26 |
27 |
28 |
29 |
30 | ,
31 | document.getElementById("app"),
32 | );
33 | };
34 |
35 | render();
36 |
37 | store.dispatch(showTitleScreen());
38 |
39 |
40 | if (module.hot) {
41 | module.hot.accept('./App', () => {
42 | render()
43 | });
44 |
45 | module.hot.accept('../common/redux/reducer', () => {
46 | store.replaceReducer(rootReducer(history))
47 | })
48 | }
49 |
--------------------------------------------------------------------------------
/src/renderer/init/AutoUpdate.js:
--------------------------------------------------------------------------------
1 | import { ipcRenderer } from "electron";
2 |
3 | import {
4 | UPDATE_AVAILABLE,
5 | DOWNLOAD_PROGRESS,
6 | UPDATE_DOWNLOADED,
7 | DOWNLOAD_ERROR,
8 | setUpdateAvailable,
9 | setDownloadProgress,
10 | setUpdateDownloaded,
11 | setDownloadError,
12 | } from "../../common/redux/auto-update/actions";
13 |
14 | export function initAutoUpdates(store) {
15 | ipcRenderer.on(UPDATE_AVAILABLE, (event, updateInfo) => {
16 | store.dispatch(setUpdateAvailable(updateInfo));
17 | });
18 | ipcRenderer.on(DOWNLOAD_PROGRESS, (event, progressInfo) => {
19 | store.dispatch(setDownloadProgress(progressInfo));
20 | });
21 | ipcRenderer.on(UPDATE_DOWNLOADED, () => {
22 | store.dispatch(setUpdateDownloaded());
23 | });
24 | ipcRenderer.on(DOWNLOAD_ERROR, (event, errorInfo) => {
25 | store.dispatch(setDownloadError(errorInfo));
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/src/renderer/init/Config.js:
--------------------------------------------------------------------------------
1 | import { ipcRenderer } from "electron";
2 |
3 | import {
4 | SHOW_CONFIG_SCREEN,
5 | SET_SETTING_ERROR,
6 | CLEAR_SETTING_ERROR,
7 | CLEAR_ALL_SETTING_ERRORS,
8 | SET_SETTINGS,
9 | showConfigScreen,
10 | setSettingError,
11 | clearSettingError,
12 | clearAllSettingErrors,
13 | setSettings,
14 | setVaultDataUpdated,
15 | } from "../../common/redux/config/actions";
16 |
17 | export function initConfig(store) {
18 | ipcRenderer.on(SHOW_CONFIG_SCREEN, () => {
19 | store.dispatch(showConfigScreen());
20 | });
21 |
22 | ipcRenderer.on(SET_SETTING_ERROR, (event, key, value) => {
23 | store.dispatch(setSettingError(key, value));
24 | });
25 |
26 | ipcRenderer.on(CLEAR_SETTING_ERROR, (event, key) => {
27 | store.dispatch(clearSettingError(key));
28 | });
29 |
30 | ipcRenderer.on(CLEAR_ALL_SETTING_ERRORS, () => {
31 | store.dispatch(clearAllSettingErrors());
32 | });
33 |
34 | ipcRenderer.on(SET_SETTINGS, (event, globalSettings, workspaceSettings) => {
35 | store.dispatch(setSettings(globalSettings, workspaceSettings));
36 | });
37 |
38 | ipcRenderer.on("VAULT_DATA", (event, message) => {
39 | store.dispatch(setVaultDataUpdated());
40 | })
41 | }
42 |
--------------------------------------------------------------------------------
/src/renderer/init/Logs.js:
--------------------------------------------------------------------------------
1 | import { ipcRenderer } from "electron";
2 |
3 | import { ADD_LOG_LINES, addLogLines } from "../../common/redux/logs/actions";
4 |
5 | export function initLogs(store) {
6 | ipcRenderer.on(ADD_LOG_LINES, (event, lines, context) => {
7 | store.dispatch(addLogLines(lines, context));
8 | });
9 | }
10 |
--------------------------------------------------------------------------------
/src/renderer/init/Network.js:
--------------------------------------------------------------------------------
1 | import { ipcRenderer } from "electron";
2 |
3 | import {
4 | SET_INTERFACES,
5 | setInterfaces,
6 | } from "../../common/redux/network/actions";
7 |
8 | export function initNetwork(store) {
9 | ipcRenderer.on(SET_INTERFACES, (event, interfaces) => {
10 | store.dispatch(setInterfaces(interfaces));
11 | });
12 | }
13 |
--------------------------------------------------------------------------------
/src/renderer/init/Workspaces.js:
--------------------------------------------------------------------------------
1 | import { ipcRenderer } from "electron";
2 |
3 | import {
4 | SET_WORKSPACES,
5 | SET_CURRENT_WORKSPACE,
6 | setWorkspaces,
7 | setCurrentWorkspace
8 | } from "../../common/redux/workspaces/actions";
9 |
10 | import {
11 | PROJECT_UPDATED,
12 | CONTRACT_DEPLOYED,
13 | CONTRACT_EVENT,
14 | CONTRACT_TRANSACTION,
15 | contractDeployed,
16 | contractTransaction,
17 | contractEvent,
18 | projectUpdated
19 | } from "../../integrations/ethereum/common/redux/workspaces/actions";
20 |
21 | export function initWorkspaces(store) {
22 | ipcRenderer.on(SET_WORKSPACES, (event, workspaceNames) => {
23 | store.dispatch(setWorkspaces(workspaceNames));
24 | });
25 |
26 | ipcRenderer.on(SET_CURRENT_WORKSPACE, (event, workspace, contractCache) => {
27 | store.dispatch(setCurrentWorkspace(workspace, contractCache));
28 | });
29 |
30 | ipcRenderer.on(CONTRACT_DEPLOYED, (event, data) => {
31 | store.dispatch(contractDeployed(data));
32 | });
33 |
34 | ipcRenderer.on(CONTRACT_TRANSACTION, (event, data) => {
35 | store.dispatch(contractTransaction(data));
36 | });
37 |
38 | ipcRenderer.on(CONTRACT_EVENT, (event, data) => {
39 | store.dispatch(contractEvent(data));
40 | });
41 |
42 | ipcRenderer.on(PROJECT_UPDATED, (event, data) => {
43 | store.dispatch(projectUpdated(data));
44 | });
45 | }
46 |
--------------------------------------------------------------------------------
/src/renderer/init/index.js:
--------------------------------------------------------------------------------
1 | import { initAutoUpdates } from "./AutoUpdate";
2 | import { initCore } from "./Core";
3 | import { initConfig } from "./Config";
4 | import { initLogs } from "./Logs";
5 | import { initNetwork } from "./Network";
6 | import { initWorkspaces } from "./Workspaces";
7 | import { initEvents } from "../../integrations/ethereum/renderer/init/Events";
8 |
9 | // This will be called before the very first render, so you can do whatever
10 | // you want here. The Redux Store is available at this point, so you can
11 | // dispatch any action you want
12 | export function initRenderer(store) {
13 | initCore(store);
14 | initConfig(store);
15 | initLogs(store);
16 | initNetwork(store);
17 | initAutoUpdates(store);
18 | initWorkspaces(store);
19 | initEvents(store);
20 | }
21 |
--------------------------------------------------------------------------------
/src/renderer/init/store/createStore.js:
--------------------------------------------------------------------------------
1 | if (process.env.NODE_ENV === "production") {
2 | module.exports = require("./createStore.production");
3 | } else {
4 | module.exports = require("./createStore.development");
5 | }
6 |
--------------------------------------------------------------------------------
/src/renderer/init/store/createStore.production.js:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware, compose } from "redux";
2 | import thunk from "redux-thunk";
3 | import { routerMiddleware } from 'connected-react-router';
4 | import {
5 | processAction,
6 | processPage,
7 | } from "../../../common/redux/middleware/analytics/index";
8 |
9 | export default function configureStore(reducers, history, initialState) {
10 | const router = routerMiddleware(history);
11 |
12 | const enhancer = compose(applyMiddleware(thunk, router, processAction));
13 |
14 | const store = createStore(reducers, initialState, enhancer);
15 |
16 | // add google analytics to production
17 | history.listen(location => {
18 | processPage(location.pathname + (location.search ? location.search : ""), store.getState())
19 | });
20 |
21 | return store;
22 | }
23 |
--------------------------------------------------------------------------------
/src/renderer/screens/appshell/AppShell.scss:
--------------------------------------------------------------------------------
1 | .AppShell {
2 | display: flex;
3 | flex-direction: column;
4 | height: 100%;
5 |
6 | .ShellContainer {
7 | display: flex;
8 | flex-grow: 1;
9 | justify-content: center;
10 | overflow: hidden; // Scrolling is handled using react-custom-scrollbars
11 | height: 100%;
12 | }
13 |
14 | .ShellContainer > span {
15 | position: relative;
16 | width: 100%;
17 | top: 0;
18 | bottom: 0;
19 | left: 0;
20 | right: 0;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/renderer/screens/appshell/BugModal.scss:
--------------------------------------------------------------------------------
1 | .Modal {
2 | &.BugModal {
3 | .Bug {
4 | textarea {
5 | min-height: 5rem; /* Overwrite Modal textarea styles */
6 | max-height: 5rem;
7 | background-color: var(--app-button-primary-disabled-border-color);
8 | width: 100%;
9 | margin-bottom: 1rem;
10 | }
11 |
12 | svg {
13 | width: 192px;
14 | height: 192px;
15 | }
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/renderer/screens/auto-update/UpdateModal.scss:
--------------------------------------------------------------------------------
1 | .Modal {
2 | &.UpdateModal {
3 | .Update {
4 | .releaseName {
5 | width: 100%
6 | }
7 |
8 | .releaseNotesOrError {
9 | height: 5rem;
10 | background-color: var(--app-button-primary-disabled-border-color);
11 | width: 100%;
12 | margin-bottom: 1rem;
13 | border: 1px solid #888888;
14 | overflow-y: scroll;
15 | }
16 |
17 | .updateDetails {
18 | display: flex;
19 | flex-direction: column;
20 | align-items: center;
21 | }
22 |
23 | .ProgressBar {
24 | width: 200px
25 | }
26 |
27 | .downloadSpeed {
28 | text-align: right;
29 | }
30 |
31 | footer {
32 | .delayButton {
33 | background-color: rgba(227, 227, 227, 0.9);
34 | float: left;
35 | }
36 |
37 | .ctaButton {
38 | float: right;
39 | }
40 | }
41 |
42 | svg {
43 | width: 192px;
44 | height: 192px;
45 | }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/renderer/screens/auto-update/UpdateNotification.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | import connect from "../helpers/connect";
4 |
5 | import { showUpdateModal } from "../../../common/redux/auto-update/actions";
6 |
7 | import UpdateIcon from "../../icons/chevron-up-o.svg";
8 |
9 | class UpdateNotification extends Component {
10 | constructor() {
11 | super();
12 | this.state = {};
13 | }
14 |
15 | handleUpdateClick() {
16 | this.props.dispatch(showUpdateModal());
17 | }
18 |
19 | render() {
20 | return (
21 |
26 | );
27 | }
28 | }
29 |
30 | export default connect(UpdateNotification);
31 |
--------------------------------------------------------------------------------
/src/renderer/screens/auto-update/UpdateNotification.scss:
--------------------------------------------------------------------------------
1 | .UpdateNotification {
2 | display: flex;
3 | justify-content: flex-end;
4 | align-items: center;
5 |
6 | a {
7 | padding: .5rem;
8 | margin: .3rem;
9 | color: var(--app-navbar-text);
10 | cursor: pointer;
11 | text-decoration: none;
12 | position: relative;
13 | text-transform: uppercase;
14 | display: flex;
15 | align-items: center;
16 | font-size: 0.89rem;
17 | line-height: 0.89rem;
18 | transition: all .25s;
19 |
20 | > div {
21 | margin-right: .5rem;
22 | }
23 |
24 | svg {
25 | width: 36px;
26 | height: 36px;
27 | color: var(--primary-color);
28 | stroke: var(--primary-color);
29 | margin-right: 0.5rem;
30 | }
31 |
32 | &:hover {
33 | color: white;
34 |
35 | svg {
36 | color: var(--primary-color);
37 | stroke: var(--primary-color);
38 | cursor: pointer;
39 | }
40 | }
41 | }
42 | }
43 |
44 |
--------------------------------------------------------------------------------
/src/renderer/screens/config/ConfigScreens/AboutScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import * as pkg from "../../../../../package.json";
3 | import Logo from "../../../components/logo/Logo.js";
4 |
5 | class AccountsScreen extends Component {
6 | render() {
7 | return (
8 |
9 |
10 |
11 |
12 | Ganache
13 | v{pkg.version}
14 |
15 |
16 | Ganache is created with
♥ by{" "}
17 |
Truffle
18 |
19 | Follow development and report issues on{" "}
20 |
GitHub
21 |
22 |
23 |
24 | );
25 | }
26 | }
27 |
28 | export default AccountsScreen;
29 |
--------------------------------------------------------------------------------
/src/renderer/screens/helpers/connect.js:
--------------------------------------------------------------------------------
1 | import { compose } from "redux";
2 | import { connect } from "react-redux";
3 | import { withRouter } from "react-router";
4 |
5 | // Connect a component to specific reducer names.
6 | // e.g., connect(MyComponent, "core", "config")
7 | export default function(component, ...reducers) {
8 | let connector = connect(
9 | state => {
10 | var props = {};
11 | reducers.forEach(reducer => {
12 | let name = reducer;
13 | let propName = reducer;
14 | if (Array.isArray(reducer)) {
15 | name = reducer[0];
16 | propName = reducer[1];
17 | }
18 |
19 | const reducerTree = name.split(".");
20 | let value = state;
21 | for (let i = 0; i < reducerTree.length; i++) {
22 | value = value[reducerTree[i]];
23 |
24 | if (!value) {
25 | throw new Error(
26 | `Tried connecting '${component.name}' to unknown state: ${name}`,
27 | );
28 | }
29 | }
30 |
31 | props[propName] = value;
32 | });
33 |
34 | return props;
35 | }
36 | );
37 | return compose(withRouter, connector)(component);
38 | }
39 |
--------------------------------------------------------------------------------
/src/renderer/screens/helpers/sanitize.js:
--------------------------------------------------------------------------------
1 | const { app } = require("@electron/remote");
2 |
3 | // return a sanitized error string from an Error object or string which contains an error message
4 | export function sanitizeError(errorUnsanitized) {
5 | return sanitizePaths(errorUnsanitized.stack || errorUnsanitized);
6 | }
7 |
8 | // Remove any user-specific paths in exception messages
9 | export function sanitizePaths(message) {
10 | // Prepare our paths so we *always* will get a match no matter
11 | // path separator (oddly, on Windows, different errors will give
12 | // us different path separators)
13 | var appPath = app.getAppPath().replace(/\\/g, "/");
14 | // I couldn't figure out the regex, so a loop will do.
15 | while (message && message.indexOf && message.indexOf(appPath) >= 0) {
16 | message = message.replace(appPath, "");
17 | }
18 |
19 | return message;
20 | }
21 |
--------------------------------------------------------------------------------
/src/renderer/screens/logs/LogContainer.scss:
--------------------------------------------------------------------------------
1 |
2 | .LogContainer {
3 | overflow: hidden;
4 | position: relative;
5 | height: 100%;
6 | width: 100%;
7 |
8 | ul {
9 | list-style:none;
10 | font-size: 13px;
11 | color: #eff1f5;
12 | border-radius: 0;
13 | background: #333;
14 | white-space: pre-wrap;
15 | word-wrap: break-word;
16 | box-sizing: border-box;
17 | margin: 0;
18 | padding: 1rem;
19 | font-family: "Fira Code Regular", monospace;
20 | position: absolute;
21 | top: 0em;
22 | left: 0em;
23 | right: 0em;
24 | bottom: 0em;
25 |
26 | li:not(:last-child) {
27 | margin-bottom: .3rem;
28 | }
29 | }
30 | }
31 |
32 | .LogContainer .plain {
33 | font-weight: 100;
34 | }
35 |
36 | .LogContainer .command {
37 | font-weight: 500;
38 | }
39 |
40 | .LogContainer .error {
41 | font-weight: 500;
42 | color: red;
43 | }
44 |
--------------------------------------------------------------------------------
/src/renderer/screens/logs/LogContainerLazy.js:
--------------------------------------------------------------------------------
1 | import LogsLazy from "./LogsLazy";
2 | import connect from "../helpers/connect";
3 |
4 | export default connect(
5 | LogsLazy,
6 | "logs",
7 | );
8 |
--------------------------------------------------------------------------------
/src/renderer/screens/logs/LogsLazy.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import { List, AutoSizer, CellMeasurer } from "react-virtualized";
3 | import Row from "./Row";
4 |
5 | class LogsLazy extends Component {
6 | shouldComponentUpdate(nextProps) {
7 | const isDifferentContext = nextProps.context !== this.props.context;
8 | if (isDifferentContext) {
9 | return true;
10 | }
11 |
12 | const isLineLengthDiff =
13 | nextProps.logs[this.props.context].lines.length !==
14 | this.props.logs[this.props.context].lines.length;
15 |
16 | return isLineLengthDiff;
17 | }
18 |
19 | renderRow = ({ index, style, parent }) => (
20 |
27 |
32 |
33 | );
34 |
35 | clearCache = () => this.props.cache.clearAll();
36 |
37 | render() {
38 | const { logs } = this.props;
39 |
40 | return (
41 |
42 |
43 |
44 | {({ height, width }) => (
45 |
52 | )}
53 |
54 |
55 |
56 | );
57 | }
58 | }
59 |
60 | export default LogsLazy;
61 |
--------------------------------------------------------------------------------
/src/renderer/screens/logs/LogsScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import connect from "../helpers/connect";
3 | import LogContainerLazy from "./LogContainerLazy";
4 | import { CellMeasurerCache } from "react-virtualized";
5 |
6 | class Logs extends Component {
7 | constructor() {
8 | super();
9 | }
10 |
11 | caches = new Map();
12 |
13 | render() {
14 | const context = this.props.match.params.context || "default";
15 |
16 | let logCache;
17 | if (this.caches.has(context)) {
18 | logCache = this.caches.get(context);
19 | } else {
20 | logCache = new CellMeasurerCache({
21 | defaultHeight: 50,
22 | fixedWidth: true,
23 | });
24 | this.caches.set(context, logCache);
25 | }
26 |
27 | return (
28 |
29 |
30 |
31 |
32 |
33 | );
34 | }
35 | }
36 |
37 | export default connect(Logs, "config");
38 |
--------------------------------------------------------------------------------
/src/renderer/screens/logs/LogsScreen.scss:
--------------------------------------------------------------------------------
1 | .LogsScreen {
2 | position: relative;
3 | display: flex !important;
4 | flex-direction: column;
5 | flex: 1;
6 | width: 100%;
7 | height: 100%;
8 |
9 | > h4 {
10 | position: -webkit-sticky;
11 | position: sticky;
12 | top: -5px;
13 | background: white;
14 | font-size: 32px;
15 | font-family: "RobotoCondensed-Bold";
16 | margin: 1rem .8rem;
17 | border-bottom: 2px solid #9b9896;
18 | z-index: 2;
19 | display: flex;
20 | align-items: center;
21 | line-height: 52px;
22 |
23 | > div {
24 | margin-right: .5rem;
25 | margin-bottom: 10px;
26 | }
27 | }
28 |
29 | main {
30 | height: 100%;
31 | display: flex;
32 | flex: 1;
33 | padding: 0;
34 | }
35 |
36 | footer {
37 | padding: 0 1rem 1rem 1rem;
38 | }
39 |
40 | .xtermContainer {
41 | background: #333;
42 | &, > div, > div > div {
43 | height: 100%;
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/renderer/screens/logs/Row.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import PropTypes from "prop-types";
3 |
4 | // react-virtualized doesn't respect the margin-bottom from LogContainer.scss, so do it here
5 | const myStyle = {
6 | padding: "0 0 0.3rem 0",
7 | };
8 |
9 | const Row = ({ index, log, style }) => (
10 |
11 | {`[${new Date(log.time).toLocaleTimeString()}]`} {log.line}
12 |
13 | );
14 |
15 | Row.propTypes = {
16 | index: PropTypes.number,
17 | log: PropTypes.shape({
18 | time: PropTypes.instanceOf(Date).isRequired,
19 | line: PropTypes.string.isRequired,
20 | }).isRequired,
21 | style: PropTypes.object, // passed down by react-virtualized
22 | };
23 |
24 | export default Row;
25 |
--------------------------------------------------------------------------------
/src/renderer/screens/not-found/NotFoundScreen.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 |
3 | class NotFoundScreen extends Component {
4 | render() {
5 | return (
6 |
7 | Nothing found
8 |
9 | );
10 | }
11 | }
12 |
13 | export default NotFoundScreen;
14 |
--------------------------------------------------------------------------------
/src/renderer/screens/not-found/NotFoundScreen.scss:
--------------------------------------------------------------------------------
1 | .NotFoundScreen {
2 | display: flex;
3 |
4 | height: 100%;
5 | width: 100%;
6 |
7 | main {
8 | width: 100%;
9 | height: 100%;
10 | display: flex;
11 | flex-direction: column;
12 | align-items: center;
13 | justify-content: center;
14 | flex-grow: 1;
15 | font-family: RobotoCondensed-Bold;
16 | text-transform: uppercase;
17 | font-size: 1.3rem;
18 | color: var(--app-page-intentionally-left-blank);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/renderer/styles/buttons.scss:
--------------------------------------------------------------------------------
1 | button,
2 | .Button {
3 | margin: 0;
4 | padding: 0;
5 | resize: none;
6 | border: 0;
7 | background-color: var(--app-button-primary-color);
8 | height: 32px;
9 | padding: 0 20px;
10 | cursor: pointer;
11 | white-space: nowrap;
12 | text-transform: uppercase;
13 | color: var(--app-button-primary-background-color);
14 | border-radius: 3px;
15 | font-family: "RobotoCondensed-Bold";
16 | font-size: 12px;
17 | font-weight: 600;
18 | line-height: 32px;
19 | transition: all .3s;
20 |
21 | &[disabled] {
22 | background-color: transparent;
23 | color: #888;
24 | border: 1px solid #888;
25 | cursor: not-allowed;
26 | }
27 |
28 | &:hover {
29 | filter: brightness(108%);
30 | color: color(var(--app-button-primary-background-color) shade(20%));
31 | box-shadow: none;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/renderer/styles/cards.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/src/renderer/styles/cards.scss
--------------------------------------------------------------------------------
/src/renderer/styles/clean_colors.scss:
--------------------------------------------------------------------------------
1 | :root {
2 | --primary-color: rgba(38, 191, 149, 1);
3 | --text-color: rgba(54, 65, 83, 1.000);
4 |
5 | --app-highlight-color: rgba(138, 193, 238, 1.000);
6 |
7 | --app-background-color: rgba(247, 249, 250, 1.000);
8 |
9 | --app-panel-background-color: rgba(247, 249, 250, 1.000);
10 | --app-panel-text-color: rgba(54, 65, 83, 1.000);
11 | --app-panel-divider-color: rgba(223, 226, 229, 1.000);
12 |
13 | --app-sidebar-background-color: rgba(255, 255, 255, 1.000);
14 | --app-sidebar-header-color: rgba(127, 143, 164, 1.000);
15 | --app-sidebar-divider-color: rgba(223, 226, 229, 1.000);
16 |
17 | --app-button-primary-background-color: rgba(138, 193, 238, 1.000);
18 | --app-button-primary-color: rgba(53, 64, 82, 1.000);
19 | --app-button-primary-disabled-border-color: rgba(227, 227, 227, 1.000);
20 |
21 | --app-account-list-background: rgba(255, 255, 255, 1.000);
22 | --app-account-list-header-divider-color: rgba(223, 226, 229, 1.000);
23 |
24 | --app-mnemonic-background-color: rgba(255, 255, 255, 1.000);
25 |
26 | --app-title-bar-btn-close: rgba(255, 96, 88, 1.000);
27 | --app-title-bar-btn-min: rgba(255, 191, 47, 1.000);
28 | --app-title-bar-btn-max: rgba(40, 201, 64, 1.000);
29 | }
30 |
--------------------------------------------------------------------------------
/src/renderer/styles/forms.scss:
--------------------------------------------------------------------------------
1 | input {
2 | color: var(--text-color);
3 | border: 1px solid var(--text-color);
4 | background-color: transparent;
5 | padding: .5rem;
6 | }
7 |
8 | $switch-width: 60px;
9 | $switch-height: 30px;
10 |
11 | .Switch {
12 | :hover, :focus {
13 | filter: brightness(105%);
14 | }
15 | display: flex;
16 | align-items: center;
17 |
18 | i {
19 | margin-left: 1rem;
20 | }
21 |
22 | input[type=checkbox] {
23 | height: 0;
24 | width: 0;
25 | visibility: hidden;
26 | }
27 |
28 | label {
29 | cursor: pointer;
30 | text-indent: -9999px;
31 | width: $switch-width;
32 | height: $switch-height;
33 | background: grey;
34 | display: block;
35 | border-radius: 4px;
36 | position: relative;
37 | }
38 |
39 | label:after {
40 | content: '';
41 | position: absolute;
42 | top: 5px;
43 | left: 5px;
44 | width: $switch-height - 10px;
45 | height: $switch-height - 10px;
46 | background: #fff;
47 | border-radius: 4px;
48 | transition: 0.3s;
49 | }
50 |
51 | input:checked + label {
52 | background: var(--primary-color);
53 | }
54 |
55 | input:checked + label:after {
56 | left: calc(100% - 5px);
57 | transform: translateX(-100%);
58 | }
59 |
60 | label:active:after {
61 | width: $switch-width - 30px;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/renderer/styles/logo.scss:
--------------------------------------------------------------------------------
1 | .LogoWrapper {
2 | display: flex;
3 | align-items: center;
4 | justify-content: center;
5 | flex-direction: column;
6 | font-size: 20px;
7 |
8 | font-weight: 700;
9 | line-height: 3.2;
10 |
11 | .Logo {
12 | height: 145px;
13 | width: 128px;
14 | background-image: url(~@/icons/logo.svg);
15 | background-position: center center;
16 | background-repeat: no-repeat;
17 | background-size: 128px 145px;
18 | will-change: opacity;
19 |
20 | opacity: 0;
21 |
22 | animation: fadeIn 500ms .8s forwards;
23 | svg {
24 | g,
25 | path,
26 | circle {
27 | stroke: none !important;
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/renderer/styles/panels.scss:
--------------------------------------------------------------------------------
1 | @import './colors';
2 |
3 | .Panel {
4 | background: var(--app-panel-background-color);
5 | padding: 0 1em 1em 1em;
6 |
7 | border-bottom: 1px solid var(--app-panel-divider-color);
8 |
9 | overflow-y: scroll;
10 |
11 | > h3 {
12 | color: var(--app-panel-text-color);
13 | }
14 |
15 | > h4 {
16 | margin: 0 0 1em 0;
17 | padding-top: 4px;
18 | color: var(--app-panel-text-color);
19 | }
20 |
21 | > h3,
22 | > h4 {
23 | border-top: 4px solid var(--app-panel-header-border-color);
24 | display: inline-table;
25 | }
26 |
27 | header,
28 | main,
29 | footer {
30 | display: flex;
31 | }
32 |
33 | header,
34 | footer {
35 | flex-shrink: 0;
36 | }
37 |
38 | main {
39 | overflow: scroll;
40 | height: 100%;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/static/README.md:
--------------------------------------------------------------------------------
1 | STATIC ASSETS
2 | There are some instances were we may not want webpack to bundle particular assets, like those being consumed by modules like fs. Here is where we can put them and then reliably access them in both development and production
3 |
4 | More info: https://webpack.electron.build/using-static-assets
5 |
--------------------------------------------------------------------------------
/static/fonts/FiraCode-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/fonts/FiraCode-Regular.ttf
--------------------------------------------------------------------------------
/static/fonts/FiraSans-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/fonts/FiraSans-Bold.ttf
--------------------------------------------------------------------------------
/static/fonts/FiraSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/fonts/FiraSans-Regular.ttf
--------------------------------------------------------------------------------
/static/fonts/FiraSans-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/fonts/FiraSans-SemiBold.ttf
--------------------------------------------------------------------------------
/static/fonts/GrandHotel-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/fonts/GrandHotel-Regular.ttf
--------------------------------------------------------------------------------
/static/fonts/RobotoCondensed-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/fonts/RobotoCondensed-Bold.ttf
--------------------------------------------------------------------------------
/static/fonts/RobotoCondensed-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/fonts/RobotoCondensed-Regular.ttf
--------------------------------------------------------------------------------
/static/icons/mac/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/icons/mac/icon.icns
--------------------------------------------------------------------------------
/static/icons/png/1024x1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/icons/png/1024x1024.png
--------------------------------------------------------------------------------
/static/icons/png/128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/icons/png/128x128.png
--------------------------------------------------------------------------------
/static/icons/png/16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/icons/png/16x16.png
--------------------------------------------------------------------------------
/static/icons/png/24x24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/icons/png/24x24.png
--------------------------------------------------------------------------------
/static/icons/png/256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/icons/png/256x256.png
--------------------------------------------------------------------------------
/static/icons/png/32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/icons/png/32x32.png
--------------------------------------------------------------------------------
/static/icons/png/48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/icons/png/48x48.png
--------------------------------------------------------------------------------
/static/icons/png/512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/icons/png/512x512.png
--------------------------------------------------------------------------------
/static/icons/png/64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/icons/png/64x64.png
--------------------------------------------------------------------------------
/static/icons/png/96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/icons/png/96x96.png
--------------------------------------------------------------------------------
/static/icons/win/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/icons/win/icon.ico
--------------------------------------------------------------------------------
/static/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trufflesuite/ganache-ui/6dbf54c00d9d89ab5321d7e2f6ffa2d94b4995c1/static/logo.png
--------------------------------------------------------------------------------
/static/node/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "@ganache/filecoin": "0.9.2",
4 | "@truffle/config": "1.2.17",
5 | "@truffle/decoder": "3.0.16",
6 | "electron": "^26.1.0",
7 | "electron-fetch": "1.7.3",
8 | "fs-extra": "9.0.0",
9 | "ganache": "7.9.1",
10 | "ganache-core": "2.13.1",
11 | "lodash.clonedeep": "4.5.0",
12 | "lodash.merge": "4.6.2",
13 | "lodash.padstart": "4.6.1",
14 | "temp": "0.9.1",
15 | "web3-eth-abi": "1.2.6",
16 | "web3-providers-http": "1.2.6",
17 | "web3-providers-ws": "1.2.6"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/static/node/truffle-integration/__tests__/projectFsWatcherUtils.test.js:
--------------------------------------------------------------------------------
1 | const { getAncestorDirs } = require("../projectFsWatcherUtils");
2 |
3 | describe("projectFsWatcherUtils", () => {
4 | describe("getAncestorDirs", () => {
5 | const truffle_directory = "/path/to/awesome/project";
6 |
7 | test("returns a list of all ancestor dirs up to truffle_directory when contracts_build_directory is a child of truffle_directory", () => {
8 | const contracts_build_directory = `${truffle_directory}/contracts`;
9 | const dirs = getAncestorDirs(
10 | truffle_directory,
11 | contracts_build_directory,
12 | );
13 |
14 | expect(dirs).toEqual([truffle_directory]);
15 | });
16 |
17 | test("returns a list of all ancestor dirs up to truffle_directory when contracts_build_directory is a descendant of truffle_directory", () => {
18 | const contracts_build_directory = `${truffle_directory}/build/contracts`;
19 | const dirs = getAncestorDirs(
20 | truffle_directory,
21 | contracts_build_directory,
22 | );
23 |
24 | expect(dirs).toEqual([truffle_directory, `${truffle_directory}/build`]);
25 | });
26 |
27 | test("returns a list of all ancestor dirs when contracts_build_directory is not a descendent of truffle_directory", () => {
28 | const contracts_build_directory = `/path/to/build/contracts`;
29 | const dirs = getAncestorDirs(
30 | truffle_directory,
31 | contracts_build_directory,
32 | );
33 |
34 | expect(dirs).toEqual(["/", "/path", "/path/to", "/path/to/build"]);
35 | });
36 | });
37 | });
38 |
--------------------------------------------------------------------------------
/static/node/truffle-integration/projectFsWatcherUtils.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 |
3 | /**
4 | *
5 | * @param {string} truffle_directory The directory of your Truffle project
6 | * @param {string} currDir The current directory
7 | * @param {string[]} ancestorDirs The current array of ancestor dirs found
8 | * @returns {string[]} An array of directory names which are ancestors to currDir
9 | */
10 | const getAncestorDirs = (truffle_directory, currDir, ancestorDirs = []) => {
11 | if (currDir == null) return [];
12 | const parent = path.dirname(currDir);
13 |
14 | if (parent === currDir) return ancestorDirs;
15 | else if (parent === truffle_directory) return [parent, ...ancestorDirs];
16 | return getAncestorDirs(truffle_directory, parent, [parent, ...ancestorDirs]);
17 | };
18 |
19 | module.exports = {
20 | getAncestorDirs,
21 | };
22 |
--------------------------------------------------------------------------------
/static/node/truffle-project-loader/index.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | const path = require("path");
3 |
4 | if (process.argv.length < 3) {
5 | throw new Error(
6 | `The truffle-project-loader process requires atleast 3 arguments, received ${
7 | process.argv.length
8 | }.`,
9 | );
10 | }
11 |
12 | const projectFile = process.argv[2];
13 |
14 | const configFileDirectory = path.dirname(projectFile);
15 | const name = path.basename(configFileDirectory);
16 | if (!fs.existsSync(projectFile)) {
17 | process.send({
18 | name,
19 | configFile: projectFile,
20 | error: "project-does-not-exist",
21 | });
22 | } else if (
23 | path.basename(projectFile).match(/^truffle(-config)?.js$/) === null
24 | ) {
25 | process.send({
26 | name,
27 | configFile: projectFile,
28 | error: "invalid-project-file",
29 | });
30 | } else {
31 | const output = require(projectFile);
32 |
33 | // it isn't "safe" to serialize the output itself, as it may have functions and circular dependencies
34 | // all we actually need are the following three properties, and I'm type checking them just to be on the safe side.
35 | process.send({
36 | truffle_directory:
37 | typeof output.truffle_directory === "string"
38 | ? output.truffle_directory
39 | : undefined,
40 | build_directory:
41 | typeof output.build_directory === "string"
42 | ? output.build_directory
43 | : undefined,
44 | contracts_build_directory:
45 | typeof output.contracts_build_directory === "string"
46 | ? output.contracts_build_directory
47 | : undefined,
48 | });
49 | }
50 |
--------------------------------------------------------------------------------
/test/README.md:
--------------------------------------------------------------------------------
1 | # Contributing to Ganache UI Tests
2 |
3 | Tests are to live in as many subdirectories as necessary for organizational purposes. Tests **are not** supposed to live in the root `/test` directory or the `/test/mocha` or `/test/spectron` (doesn't exist yet) directories.
4 |
5 | ## Executing Tests
6 | You can execute tests by running `npm test`. This will `npm run test-mocha` ~~and `npm run test-spectron`~~ (not added yet).
7 |
8 | ## Mocha
9 | For components that do not require Electron, it is recommended to write Mocha tests instead as they are lighter.
10 |
11 | For a Mocha test to be executed by `npm test` or `npm run test-mocha`, it must be located in a subdirectory of `/test/mocha` matching the glob pattern `*.test.js`.
12 |
13 | ### Subtests
14 | You may see files with the glob pattern `*.subtest.js`. These files are not named `*.test.js` for the purpose of organizing them in a single Mocha `describe()`. A main loader `*.test.js` file will require the `*.subtest.js` files for execution. See how [workspace tests implement this](mocha/workspaces/workspaces.test.js).
15 |
16 | ## Spectron
17 | Currently, there are no Spectron tests, nor is there the framework necessary to execute Spectron tests. However, Spectron test support will be added eventually.
--------------------------------------------------------------------------------
/test/mocha/project-loader/truffle-project/myfile.json:
--------------------------------------------------------------------------------
1 | {
2 | "dir": "./123"
3 | }
--------------------------------------------------------------------------------
/test/mocha/project-loader/truffle-project/truffle.js:
--------------------------------------------------------------------------------
1 | //make sure we execute the config file at the proper `cwd`:
2 | // by attempting to read a local file:
3 | const json = JSON.parse(require("fs").readFileSync("./myfile.json", "utf-8"));
4 |
5 | // make sure we don't throw if something is logged to console.error:
6 | // eslint-disable-next-line no-console
7 | console.error("Just a friendly error message. Don't be alarmed.");
8 |
9 | // make sure we can handle circular json in the project file:
10 | const circles = {};
11 | circles.circles = circles;
12 | module.exports = {
13 | networks: {
14 | provider: circles,
15 | },
16 | otherThings: 123,
17 | build_directory: json.dir,
18 | };
19 |
--------------------------------------------------------------------------------
/test/mocha/workspaces/test-workspaces/default/Settings:
--------------------------------------------------------------------------------
1 | {"server":{"gasLimit":6721975,"gasPrice":20000000000,"hostname":"127.0.0.1","port":7545,"network_id":5777,"default_balance_ether":100,"total_accounts":10,"unlocked_accounts":[],"locked":false,"vmErrorsOnRPCResponse":true,"logger":null,"verbose":false},"name":"Quickstart","isDefault":true,"verboseLogging":false,"randomizeMnemonicOnStart":false,"logsDirectory":null,"projects":[],"uuid":"b1ef5e49-3485-482e-96b5-91826e7d4c85"}
--------------------------------------------------------------------------------
/test/mocha/workspaces/test-workspaces/global/Settings:
--------------------------------------------------------------------------------
1 | {"googleAnalyticsTracking":true,"cpuAndMemoryProfiling":false,"firstRun":false,"uuid":"8b56511c-135f-4842-9f6a-f656ad69aa3d"}
--------------------------------------------------------------------------------
/test/mocha/workspaces/test-workspaces/ui/workspaces/Test-1/Settings:
--------------------------------------------------------------------------------
1 | {"server":{"gasLimit":6721975,"gasPrice":20000000000,"hostname":"127.0.0.1","port":7545,"network_id":5777,"default_balance_ether":100,"total_accounts":10,"unlocked_accounts":[],"locked":false,"vmErrorsOnRPCResponse":true,"logger":null,"verbose":false,"db_path":"/home/mike/work/consensys/ganache/test/mocha/workspaces/test-workspaces/workspaces/Test-1/chaindata"},"name":"Test 1","isDefault":false,"verboseLogging":false,"randomizeMnemonicOnStart":false,"logsDirectory":null,"projects":[],"uuid":"b1ef5e49-3485-482e-96b5-91826e7d4c85"}
--------------------------------------------------------------------------------
/test/mocha/workspaces/test-workspaces/ui/workspaces/Test-2/Settings:
--------------------------------------------------------------------------------
1 | {"server":{"gasLimit":6721975,"gasPrice":20000000000,"hostname":"127.0.0.1","port":7546,"network_id":5777,"default_balance_ether":50,"total_accounts":5,"unlocked_accounts":[],"locked":false,"vmErrorsOnRPCResponse":true,"logger":null,"verbose":false,"db_path":"/home/mike/work/consensys/ganache/test/mocha/workspaces/test-workspaces/workspaces/Test-2/chaindata"},"name":"Test 2","isDefault":false,"verboseLogging":false,"randomizeMnemonicOnStart":false,"logsDirectory":null,"projects":[],"uuid":"b1ef5e49-3485-482e-96b5-91826e7d4c85"}
--------------------------------------------------------------------------------
/test/mocha/workspaces/workspaces.test.js:
--------------------------------------------------------------------------------
1 | describe("Workspaces", function() {
2 | require("./new-workspace.subtest");
3 | require("./workspace-manager.subtest");
4 | });
5 |
--------------------------------------------------------------------------------
/webpack/webpack.main.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | output: {
3 | hashFunction: "sha256",
4 | },
5 | resolve: {
6 | alias: {
7 | "scrypt": "js-scrypt"
8 | }
9 | },
10 | externals: ["@ganache/filecoin"]
11 | };
12 |
--------------------------------------------------------------------------------