pull/2668/head
filip mertens 2 years ago
parent 53e9650cca
commit 53cedb0dd8
  1. 97
      apps/remix-ide-e2e/src/tests/file_decorator.test.ts
  2. 7
      apps/remix-ide/src/app.js
  3. 42
      apps/remix-ide/src/app/plugins/file-decorator.ts
  4. 2
      libs/remix-ui/file-decorators/src/lib/components/filedecorationicons/file-decoration-custom-icon.tsx
  5. 2
      libs/remix-ui/file-decorators/src/lib/components/filedecorationicons/file-decoration-error-icon.tsx
  6. 2
      libs/remix-ui/file-decorators/src/lib/components/filedecorationicons/file-decoration-warning-icon.tsx
  7. 3
      nx.json
  8. 1
      tsconfig.base.json
  9. 15
      workspace.json

@ -0,0 +1,97 @@
'use strict'
import { NightwatchBrowser } from 'nightwatch'
import init from '../helpers/init'
module.exports = {
before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done)
},
'Test decorators with script': function (browser: NightwatchBrowser) {
browser
.openFile('contracts')
.openFile('contracts/2_Owner.sol')
.openFile('contracts/1_Storage.sol')
.openFile('contracts/3_Ballot.sol')
.addFile('scripts/decorators.ts', { content: testScript })
.pause(2000)
.executeScript('remix.exeCurrent()')
.pause(4000)
.useXpath()
.waitForElementContainsText('//*[@id="fileExplorerView"]//*[@data-id="file-decoration-error-contracts/2_Owner.sol"]', '2')
.waitForElementContainsText('//*[@class="mainview"]//*[@data-id="file-decoration-error-contracts/2_Owner.sol"]', '2')
.waitForElementContainsText('//*[@id="fileExplorerView"]//*[@data-id="file-decoration-custom-contracts/2_Owner.sol"]', 'U')
.waitForElementContainsText('//*[@class="mainview"]//*[@data-id="file-decoration-custom-contracts/2_Owner.sol"]', 'U')
.waitForElementContainsText('//*[@id="fileExplorerView"]//*[@data-id="file-decoration-warning-contracts/1_Storage.sol"]', '2')
.waitForElementContainsText('//*[@class="mainview"]//*[@data-id="file-decoration-warning-contracts/1_Storage.sol"]', '2')
.useCss()
.waitForElementNotPresent('[data-id="file-decoration-custom-contracts/3_Ballot.sol"]', 10000)
.useXpath()
.moveToElement('//*[@id="fileExplorerView"]//*[@data-id="file-decoration-error-contracts/2_Owner.sol"]', 0,0)
.waitForElementVisible('//*[@id="error-tooltip-contracts/2_Owner.sol"]')
.waitForElementContainsText('//*[@id="error-tooltip-contracts/2_Owner.sol"]', 'error on owner')
}
}
const testScript = `
(async () => {
remix.call('fileDecorator' as any, 'clearFileDecorators')
let decorator: any = {
path: 'contracts/2_Owner.sol',
isDirectory: false,
fileStateType: 'ERROR',
fileStateLabelClass: 'text-danger',
fileStateIconClass: '',
fileStateIcon: '',
text: '2',
owner: 'code-parser',
bubble: true,
commment: 'error on owner',
}
let decorator2: any = {
path: 'contracts/2_Owner.sol',
isDirectory: false,
fileStateType: 'CUSTOM',
fileStateLabelClass: 'text-success',
fileStateIconClass: 'text-success',
fileStateIcon: 'U',
text: '',
owner: 'code-parser',
bubble: true,
commment: 'modified',
}
remix.call('fileDecorator' as any, 'setFileDecorators', [decorator, decorator2])
decorator = {
path: 'contracts/1_Storage.sol',
isDirectory: false,
fileStateType: 'WARNING',
fileStateLabelClass: 'text-warning',
fileStateIconClass: '',
fileStateIcon: '',
text: '2',
owner: 'code-parser',
bubble: true,
commment: 'warning on storage',
}
remix.call('fileDecorator' as any, 'setFileDecorators', decorator)
decorator = {
path: 'contracts/3_Ballot.sol',
isDirectory: false,
fileStateType: 'CUSTOM',
fileStateLabelClass: '',
fileStateIconClass: '',
fileStateIcon: 'customtext',
text: 'w',
owner: 'dgit',
bubble: true,
commment: '',
}
remix.call('fileDecorator' as any, 'setFileDecorators', decorator)
remix.call('fileDecorator' as any, 'clearFileDecorators', 'dgit')
})()`

@ -31,6 +31,7 @@ import { FoundryProvider } from './app/tabs/foundry-provider'
import { ExternalHttpProvider } from './app/tabs/external-http-provider'
import { Injected0ptimismProvider } from './app/tabs/injected-optimism-provider'
import { InjectedArbitrumOneProvider } from './app/tabs/injected-arbitrum-one-provider'
import { FileDecorator } from './app/plugins/file-decorator'
const isElectron = require('is-electron')
@ -156,6 +157,9 @@ class AppComponent {
// ----------------- Storage plugin ---------------------------------
const storagePlugin = new StoragePlugin()
// ------- FILE DECORATOR PLUGIN ------------------
const fileDecorator = new FileDecorator()
//----- search
const search = new SearchPlugin()
@ -239,6 +243,7 @@ class AppComponent {
fetchAndCompile,
dGitProvider,
storagePlugin,
fileDecorator,
hardhatProvider,
ganacheProvider,
foundryProvider,
@ -363,7 +368,7 @@ class AppComponent {
await this.appManager.activatePlugin(['sidePanel']) // activating host plugin separately
await this.appManager.activatePlugin(['home'])
await this.appManager.activatePlugin(['settings', 'config'])
await this.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'contextualListener', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport', 'gistHandler'])
await this.appManager.activatePlugin(['hiddenPanel', 'pluginManager', 'fileDecorator', 'contextualListener', 'terminal', 'blockchain', 'fetchAndCompile', 'contentImport', 'gistHandler'])
await this.appManager.activatePlugin(['settings'])
await this.appManager.activatePlugin(['walkthrough','storage', 'search','compileAndRun', 'recorder'])

@ -18,22 +18,14 @@ export class FileDecorator extends Plugin {
constructor() {
super(profile)
}
/**
*
* @param fileStates Array of file states
*/
async setFileDecorators(fileStates: fileDecoration[] | fileDecoration) {
const workspace = await this.call('filePanel', 'getCurrentWorkspace')
function sortByPath( a: fileDecoration, b: fileDecoration ) {
if ( a.path < b.path ){
return -1;
}
if ( a.path > b.path ){
return 1;
}
return 0;
}
const fileStatesPayload = Array.isArray(fileStates) ? fileStates : [fileStates]
// clear all file states in the previous state of this owner on the files called
fileStatesPayload.forEach((state) => {
@ -46,15 +38,37 @@ export class FileDecorator extends Plugin {
return index == -1
})
const newState = [...filteredState, ...fileStatesPayload].sort(sortByPath)
if (!deepequal(newState, this._fileStates)) {
this._fileStates = newState
this.emit('fileDecoratorsChanged', this._fileStates)
}
}
async clearFileDecorators() {
this._fileStates = []
this.emit('fileDecoratorsChanged', [])
async clearFileDecorators(owner? : string) {
if(!owner) {
this._fileStates = []
this.emit('fileDecoratorsChanged', [])
} else {
const filteredState = this._fileStates.filter((state) => {
return state.owner != owner
})
const newState = [...filteredState].sort(sortByPath)
if (!deepequal(newState, this._fileStates)) {
this._fileStates = newState
this.emit('fileDecoratorsChanged', this._fileStates)
}
}
}
}
const sortByPath = (a: fileDecoration, b: fileDecoration) => {
if (a.path < b.path) {
return -1;
}
if (a.path > b.path) {
return 1;
}
return 0;
}

@ -5,7 +5,7 @@ import { fileDecoration } from '../../types'
const FileDecorationCustomIcon = (props: {
fileDecoration: fileDecoration
}) => {
return <><span className={`${props.fileDecoration.fileStateIconClass}pr-2`}>
return <><span data-id={`file-decoration-custom-${props.fileDecoration.path}`} className={`${props.fileDecoration.fileStateIconClass} pr-2`}>
{props.fileDecoration.fileStateIcon}
</span></>
}

@ -7,7 +7,7 @@ const FileDecorationErrorIcon = (props: {
fileDecoration: fileDecoration
}) => {
return <>
<span className={`${props.fileDecoration.fileStateIconClass} text-danger pr-2`}>{props.fileDecoration.text}</span>
<span data-id={`file-decoration-error-${props.fileDecoration.path}`} className={`${props.fileDecoration.fileStateIconClass} text-danger pr-2`}>{props.fileDecoration.text}</span>
</>
}

@ -5,7 +5,7 @@ import { fileDecoration } from '../../types'
const FileDecorationWarningIcon = (props: {
fileDecoration: fileDecoration
}) => {
return <><span className={`${props.fileDecoration.fileStateIconClass} text-warning pr-2`}>{props.fileDecoration.text}</span></>
return <><span data-id={`file-decoration-warning-${props.fileDecoration.path}`} className={`${props.fileDecoration.fileStateIconClass} text-warning pr-2`}>{props.fileDecoration.text}</span></>
}
export default FileDecorationWarningIcon

@ -170,6 +170,9 @@
"remix-ui-permission-handler": {
"tags": []
},
"remix-ui-file-decorators": {
"tags": []
},
"remix-ui-tooltip-popup": {
"tags": []
}

@ -88,6 +88,7 @@
"@remix-ui/permission-handler": [
"libs/remix-ui/permission-handler/src/index.ts"
],
"@remix-ui/file-decorators": ["libs/remix-ui/file-decorators/src/index.ts"],
"@remix-ui/tooltip-popup": ["libs/remix-ui/tooltip-popup/src/index.ts"]
}
},

@ -1270,6 +1270,21 @@
}
}
}
},
"remix-ui-file-decorators": {
"root": "libs/remix-ui/file-decorators",
"sourceRoot": "libs/remix-ui/file-decorators/src",
"projectType": "library",
"architect": {
"lint": {
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": ["libs/remix-ui/file-decorators/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "!libs/remix-ui/file-decorators/**/*"]
}
}
}
}
},
"cli": {

Loading…
Cancel
Save