diff --git a/apps/remix-ide-e2e/src/tests/homeTab.test.ts b/apps/remix-ide-e2e/src/tests/homeTab.test.ts index 46faaef303..810ae1d2cd 100644 --- a/apps/remix-ide-e2e/src/tests/homeTab.test.ts +++ b/apps/remix-ide-e2e/src/tests/homeTab.test.ts @@ -28,8 +28,8 @@ module.exports = { 'Should start with ERC20 workspace #group1': function (browser: NightwatchBrowser) { browser .click('*[data-path="home"') - .waitForElementVisible('*[data-id="homeTabGetStartedERC20"]') - .click('*[data-id="homeTabGetStartedERC20"') + .waitForElementVisible('*[data-id="homeTabGetStartedozerc20"]') + .click('*[data-id="homeTabGetStartedozerc20"') .waitForElementVisible('*[data-id="treeViewLitreeViewItemcontracts/MyToken.sol"]') .waitForElementVisible('*[data-id="treeViewDivtreeViewItemtests/MyToken_test.sol"]') .click('*[data-id="treeViewDivtreeViewItemtests/MyToken_test.sol"]') diff --git a/apps/remix-ide-e2e/src/tests/importFromGithub.test.ts b/apps/remix-ide-e2e/src/tests/importFromGithub.test.ts index 5799955a1e..d2dbe89f21 100644 --- a/apps/remix-ide-e2e/src/tests/importFromGithub.test.ts +++ b/apps/remix-ide-e2e/src/tests/importFromGithub.test.ts @@ -3,9 +3,9 @@ import { NightwatchBrowser } from 'nightwatch' import init from '../helpers/init' const testData = { - validURL: 'https://github.com/OpenZeppelin/openzeppelin-solidity/blob/67bca857eedf99bf44a4b6a0fc5b5ed553135316/contracts/access/Roles.sol', + validURL: 'https://github.com/remix-project-org/git-hometab-test.git', invalidURL: 'https://github.com/Oppelin/Roles.sol', - JSON: 'https://github.com/ethereum/remix-project/blob/master/package.json' + JSON: 'https://github.com/remix-project-org/git-hometab-test.git' } module.exports = { @@ -22,63 +22,53 @@ module.exports = { .waitForElementVisible('button[data-id="landingPageImportFromGitHubButton"]') .pause(1000) .click('button[data-id="landingPageImportFromGitHubButton"]') - .waitForElementVisible('*[data-id="homeTabModalDialogModalTitle-react"]') - .assert.containsText('*[data-id="homeTabModalDialogModalTitle-react"]', 'Import from GitHub') - .waitForElementVisible('*[data-id="homeTabModalDialogModalBody-react"]') - .assert.containsText('*[data-id="homeTabModalDialogModalBody-react"]', 'Enter the github URL you would like to load.') - .waitForElementVisible('input[data-id="homeTabModalDialogCustomPromptText"]') + .waitForElementVisible('*[data-id="fileSystemModalDialogModalTitle-react"]') + .assert.containsText('*[data-id="fileSystemModalDialogModalTitle-react"]', 'Clone Git Repository') + .waitForElementVisible('*[data-id="fileSystemModalDialogModalBody-react"]') + .waitForElementVisible('input[data-id="modalDialogCustomPromptTextClone"]') }, 'Display Error Message For Invalid GitHub URL Modal #group1': function (browser: NightwatchBrowser) { browser .execute(() => { - (document.querySelector('input[data-id="homeTabModalDialogCustomPromptText"]') as any).focus() + (document.querySelector('input[data-id="modalDialogCustomPromptTextClone"]') as any).focus() }, [], () => { }) - .setValue('input[data-id="homeTabModalDialogCustomPromptText"]', testData.invalidURL) - .waitForElementVisible('*[data-id="homeTab-modal-footer-ok-react"]') - .click('[data-id="homeTab-modal-footer-ok-react"]') // submitted + .setValue('input[data-id="modalDialogCustomPromptTextClone"]', testData.invalidURL) + .waitForElementVisible('*[data-id="fileSystemModalDialogModalFooter-react"]') + .click('[data-id="fileSystem-modal-footer-ok-react"]') // submitted //.waitForElementVisible('*[data-shared="tooltipPopup"]') //.waitForElementContainsText('*[data-shared="tooltipPopup"] span', 'not found ' + testData.invalidURL) }, - 'Import From GitHub For Valid URL #group2': function (browser: NightwatchBrowser) { + 'Clone From GitHub with Valid URL #group2': function (browser: NightwatchBrowser) { browser .waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000) .clickLaunchIcon('filePanel') .click('div[data-id="verticalIconsHomeIcon"]') .waitForElementVisible('button[data-id="landingPageImportFromGitHubButton"]').pause(1000) .click('button[data-id="landingPageImportFromGitHubButton"]') - .waitForElementVisible('input[data-id="homeTabModalDialogCustomPromptText"]') + .waitForElementVisible('input[data-id="modalDialogCustomPromptTextClone"]') .execute(() => { - (document.querySelector('input[data-id="homeTabModalDialogCustomPromptText"]') as any).focus() + (document.querySelector('input[data-id="modalDialogCustomPromptTextClone"]') as any).focus() }, [], () => { }) - .clearValue('input[data-id="homeTabModalDialogCustomPromptText"]').pause(1000) - .setValue('input[data-id="homeTabModalDialogCustomPromptText"]', testData.validURL) - .waitForElementVisible('*[data-id="homeTab-modal-footer-ok-react"]') - .click('[data-id="homeTab-modal-footer-ok-react"]') - .openFile('github/OpenZeppelin/openzeppelin-solidity/contracts/access/Roles.sol') + .clearValue('input[data-id="modalDialogCustomPromptTextClone"]').pause(1000) + .setValue('input[data-id="modalDialogCustomPromptTextClone"]', testData.validURL) + .waitForElementVisible('*[data-id="fileSystem-modal-footer-ok-react"]') + .click('[data-id="fileSystem-modal-footer-ok-react"]') + .openFile('Roles.sol') .waitForElementVisible({ - selector: `//*[@data-id='tab-active' and @data-path="default_workspace/github/OpenZeppelin/openzeppelin-solidity/contracts/access/Roles.sol"]`, + selector: `//*[@data-id='tab-active' and @data-path="git-hometab-test.git/Roles.sol"]`, locateStrategy: 'xpath' }) .getEditorValue((content) => { browser.assert.ok(content.indexOf('library Roles {') !== -1, 'content does contain "library Roles {"') }) }, - 'Import JSON From GitHub For Valid URL #group2': function (browser: NightwatchBrowser) { + 'Confirm JSON After Cloning From GitHub For Valid URL #group2': function (browser: NightwatchBrowser) { browser .click('div[data-id="verticalIconsHomeIcon"]') - .click('button[data-id="landingPageImportFromGitHubButton"]') - .waitForElementVisible('input[data-id="homeTabModalDialogCustomPromptText"]').pause(1000) - .execute(() => { - (document.querySelector('input[data-id="homeTabModalDialogCustomPromptText"]') as any).focus() - }, [], () => { }) - .clearValue('input[data-id="homeTabModalDialogCustomPromptText"]').pause(1000) - .setValue('input[data-id="homeTabModalDialogCustomPromptText"]', testData.JSON) - .waitForElementVisible('*[data-id="homeTab-modal-footer-ok-react"]') - .click('[data-id="homeTab-modal-footer-ok-react"]') - .openFile('github/ethereum/remix-project/package.json') - .waitForElementVisible("div[data-path='default_workspace/github/ethereum/remix-project/package.json'") + .openFile('package.json') + .waitForElementVisible("*[data-path='git-hometab-test.git/package.json'") .getEditorValue((content) => { browser.assert.ok(content.indexOf('"name": "remix-project",') !== -1, 'content does contain "name": "remix-project"') }) diff --git a/apps/remix-ide-e2e/src/tests/terminal.test.ts b/apps/remix-ide-e2e/src/tests/terminal.test.ts index fdbc8fb8b1..69e4cdc946 100644 --- a/apps/remix-ide-e2e/src/tests/terminal.test.ts +++ b/apps/remix-ide-e2e/src/tests/terminal.test.ts @@ -100,7 +100,7 @@ module.exports = { .switchEnvironment('vm-london') .click('*[data-id="terminalClearConsole"]') // clear the terminal .clickLaunchIcon('filePanel') - .click('*[data-id="treeViewDivMenu"]') // make sure we create the file at the root folder + .click('*[data-id="treeViewUltreeViewMenu"]') // make sure we create the file at the root folder .addFile('deployWithEthersJs.js', { content: deployWithEthersJs }) // .openFile('deployWithEthersJs.js') .pause(1000) diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index d767019df4..18ec31d8c2 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -389,7 +389,7 @@ class AppComponent { this.pinnedPanel = new PinnedPanel() const pluginManagerComponent = new PluginManagerComponent(appManager, this.engine) - const filePanel = new FilePanel(appManager) + const filePanel = new FilePanel(appManager, contentImport) this.statusBar = new StatusBar(filePanel, this.menuicons) const landingPage = new LandingPage(appManager, this.menuicons, fileManager, filePanel, contentImport) this.settings = new SettingsTab(Registry.getInstance().get('config').api, editor, appManager) @@ -516,7 +516,7 @@ class AppComponent { ) await this.appManager.activatePlugin(['solidity-script']) await this.appManager.activatePlugin(['solcoder']) - await this.appManager.activatePlugin(['filePanel']) + await this.appManager.activatePlugin(['filePanel']) // Set workspace after initial activation this.appManager.on('editor', 'editorMounted', () => { diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js index a709692452..02d233d5bb 100644 --- a/apps/remix-ide/src/app/panels/file-panel.js +++ b/apps/remix-ide/src/app/panels/file-panel.js @@ -59,7 +59,7 @@ const profile = { maintainedBy: 'Remix' } module.exports = class Filepanel extends ViewPlugin { - constructor(appManager) { + constructor(appManager, contentImport) { super(profile) this.registry = Registry.getInstance() this.fileProviders = this.registry.get('fileproviders').api @@ -73,6 +73,7 @@ module.exports = class Filepanel extends ViewPlugin { this.foundryHandle = new FoundryHandle() this.truffleHandle = new TruffleHandle() this.slitherHandle = new SlitherHandle() + this.contentImport = contentImport this.workspaces = [] this.appManager = appManager this.currentWorkspaceMetadata = null diff --git a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json index 5f033c3aad..8159675a7e 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/filePanel.json +++ b/apps/remix-ide/src/app/tabs/locales/en/filePanel.json @@ -68,7 +68,7 @@ "filePanel.createNewFolder": "Create new folder", "filePanel.publishToGist": "Publish to Gist", "filePanel.workspace.publishToGist": "Publish workspace to GitHub gist", - "filePanel.uploadFile": "Upload files", + "filePanel.uploadFile": "Open a File from your File System", "filePanel.uploadFolder": "Upload folder", "filePanel.updateGist": "Update Gist", "filePanel.workspace.updateGist": "Publish Gist update", diff --git a/apps/remix-ide/src/app/tabs/locales/en/home.json b/apps/remix-ide/src/app/tabs/locales/en/home.json index 9d78937c91..99389282e1 100644 --- a/apps/remix-ide/src/app/tabs/locales/en/home.json +++ b/apps/remix-ide/src/app/tabs/locales/en/home.json @@ -66,6 +66,9 @@ "home.resources": "Resources", "home.connectToLocalhost": "Connect to Localhost", "home.seeAllTutorials": "See all tutorials", - "home.maintainedByRemix": "Maintained by Remix" + "home.maintainedByRemix": "Maintained by Remix", + "home.gitCloneTooltip": "Clone a Github repo to a new workspace", + "home.gistTooltip": "Open Gist repo", + "home.newFileTooltip": "Add a new file to a workspace" } diff --git a/libs/remix-ui/home-tab/src/lib/components/homeTabFeatured.tsx b/libs/remix-ui/home-tab/src/lib/components/homeTabFeatured.tsx index 03e787e7ef..bc5fb49f62 100644 --- a/libs/remix-ui/home-tab/src/lib/components/homeTabFeatured.tsx +++ b/libs/remix-ui/home-tab/src/lib/components/homeTabFeatured.tsx @@ -12,7 +12,7 @@ function HomeTabFeatured() { const themeFilter = useContext(ThemeContext) return ( -
e.g ipfs://QmQQfBMkpDgmxKzYaoAtqfaybzfgGm9b2LWYyT56Chv6xH
+ ) +} + export default FileExplorer diff --git a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx index 85860d03a5..3546caa951 100644 --- a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx @@ -1,9 +1,10 @@ -import React, {useState, useEffect, useRef, useContext, ChangeEvent} from 'react' // eslint-disable-line +import React, {useState, useEffect, useRef, useContext, ChangeEvent, useReducer} from 'react' // eslint-disable-line import { FormattedMessage, useIntl } from 'react-intl' import { Dropdown } from 'react-bootstrap' import { CustomIconsToggle, CustomMenu, CustomToggle, CustomTooltip, extractNameFromKey, extractParentFromKey } from '@remix-ui/helper' import { CopyToClipboard } from '@remix-ui/clipboard' import {FileExplorer} from './components/file-explorer' // eslint-disable-line +import {ModalDialog, ValidationResult} from '@remix-ui/modal-dialog' // eslint-disable-line import { FileSystemContext } from './contexts' import './css/remix-ui-workspace.css' import { ROOT_PATH, TEMPLATE_NAMES } from './utils/constants' @@ -105,6 +106,136 @@ export function Workspace() { } }, [canPaste]) + const [modalState, setModalState] = useState<{ + searchInput: string + showModalDialog: boolean + // modalValidation?: ValidationResult + modalInfo: { + title: string + loadItem: string + examples: Array