fix statusChanged handling bug

pull/1671/head
Joseph Izang 3 years ago
parent 74854070d5
commit 10998817ba
  1. 2
      apps/remix-ide/src/app/components/side-panel.js
  2. 134
      apps/remix-ide/src/app/components/vertical-icons.js
  3. 2
      libs/remix-ui/solidity-compiler/src/lib/compiler-container.tsx
  4. 2
      libs/remix-ui/solidity-compiler/src/lib/css/style.css
  5. 57
      libs/remix-ui/vertical-icons-panel/src/lib/components/Badge.tsx
  6. 2
      libs/remix-ui/vertical-icons-panel/src/lib/components/Home.tsx
  7. 102
      libs/remix-ui/vertical-icons-panel/src/lib/components/Icon.tsx
  8. 2
      libs/remix-ui/vertical-icons-panel/src/lib/components/Settings.tsx
  9. 60
      libs/remix-ui/vertical-icons-panel/src/lib/reducers/iconBadgeReducer.ts
  10. 49
      libs/remix-ui/vertical-icons-panel/src/lib/reducers/iconReducers.ts
  11. 16
      libs/remix-ui/vertical-icons-panel/src/lib/remix-ui-vertical-icons-panel.css
  12. 4
      libs/remix-ui/vertical-icons-panel/src/lib/remix-ui-vertical-icons-panel.tsx

@ -103,7 +103,7 @@ export class SidePanel extends AbstractPanel {
addView (profile, view) { addView (profile, view) {
super.addView(profile, view) super.addView(profile, view)
setTimeout(() => this.verticalIcons.linkContent(profile), 60000) setTimeout(() => this.verticalIcons.linkContent(profile), 150)
} }
/** /**

@ -5,7 +5,7 @@ import ReactDOM from 'react-dom'
import React from 'react' // eslint-disable-line import React from 'react' // eslint-disable-line
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
import { RemixUiVerticalIconsPanel } from '@remix-ui/vertical-icons-panel' import { RemixUiVerticalIconsPanel } from '@remix-ui/vertical-icons-panel'
var helper = require('../../lib/helper') // var helper = require('../../lib/helper')
const globalRegistry = require('../../global/registry') const globalRegistry = require('../../global/registry')
const { Plugin } = require('@remixproject/engine') const { Plugin } = require('@remixproject/engine')
const EventEmitter = require('events') const EventEmitter = require('events')
@ -66,19 +66,19 @@ export class VerticalIcons extends Plugin {
// the list of supported keys. 'none' will remove the status // the list of supported keys. 'none' will remove the status
// const keys = ['edited', 'succeed', 'none', 'loading', 'failed'] // const keys = ['edited', 'succeed', 'none', 'loading', 'failed']
// const types = ['error', 'warning', 'success', 'info', ''] // const types = ['error', 'warning', 'success', 'info', '']
const fn = (status) => { // const fn = (status) => {
if (!this.types.includes(status.type) && status.type) throw new Error(`type should be ${this.keys.join()}`) // if (!this.types.includes(status.type) && status.type) throw new Error(`type should be ${this.keys.join()}`)
if (status.key === undefined) throw new Error('status key should be defined') // if (status.key === undefined) throw new Error('status key should be defined')
if (typeof status.key === 'string' && (!this.keys.includes(status.key))) { // if (typeof status.key === 'string' && (!this.keys.includes(status.key))) {
throw new Error('key should contain either number or ' + this.keys.join()) // throw new Error('key should contain either number or ' + this.keys.join())
} // }
this.setIconStatus(profile.name, status) // this.setIconStatus(profile.name, status)
} // }
this.iconStatus[profile.name] = fn // this.iconStatus[profile.name] = fn
this.on(profile.name, 'statusChanged', () => { // this.on(profile.name, 'statusChanged', () => {
console.log('caught statusChanged in react!') // console.log('caught statusChanged in react!')
}) // })
} }
/** /**
@ -86,66 +86,66 @@ export class VerticalIcons extends Plugin {
* @param {Object} key * @param {Object} key
* @param {Object} type * @param {Object} type
*/ */
resolveClasses (key, type) { // resolveClasses (key, type) {
let classes = 'remixui_status' // let classes = 'remixui_status'
switch (key) { // switch (key) {
case 'succeed': // case 'succeed':
classes += ' fas fa-check-circle text-' + type + ' ' + 'remixui_statusCheck' // classes += ' fas fa-check-circle text-' + type + ' ' + 'remixui_statusCheck'
break // break
case 'edited': // case 'edited':
classes += ' fas fa-sync text-' + type + ' ' + 'remixui_statusCheck' // classes += ' fas fa-sync text-' + type + ' ' + 'remixui_statusCheck'
break // break
case 'loading': // case 'loading':
classes += ' fas fa-spinner text-' + type + ' ' + 'remixui_statusCheck' // classes += ' fas fa-spinner text-' + type + ' ' + 'remixui_statusCheck'
break // break
case 'failed': // case 'failed':
classes += ' fas fa-exclamation-triangle text-' + type + ' ' + 'remixui_statusCheck' // classes += ' fas fa-exclamation-triangle text-' + type + ' ' + 'remixui_statusCheck'
break // break
default: { // default: {
classes += ' badge badge-pill badge-' + type // classes += ' badge badge-pill badge-' + type
} // }
} // }
return classes // return classes
} // }
/** /**
* Set a new status for the @arg name * Set a new status for the @arg name
* @param {String} name * @param {String} name
* @param {Object} status * @param {Object} status
*/ */
setIconStatus (name, status) { // setIconStatus (name, status) {
const el = this.icons[name] // const el = this.icons[name]
if (!el) return // if (!el) return
const statusEl = el.querySelector('i') // const statusEl = el.querySelector('i')
if (statusEl) { // if (statusEl) {
el.removeChild(statusEl) // el.removeChild(statusEl)
} // }
if (status.key === 'none') return // remove status // if (status.key === 'none') return // remove status
let text = '' // let text = ''
let key = '' // let key = ''
if (typeof status.key === 'number') { // if (typeof status.key === 'number') {
key = status.key.toString() // key = status.key.toString()
text = key // text = key
} else key = helper.checkSpecialChars(status.key) ? '' : status.key // } else key = helper.checkSpecialChars(status.key) ? '' : status.key
let type = '' // let type = ''
if (status.type === 'error') { // if (status.type === 'error') {
type = 'danger' // to use with bootstrap // type = 'danger' // to use with bootstrap
} else type = helper.checkSpecialChars(status.type) ? '' : status.type // } else type = helper.checkSpecialChars(status.type) ? '' : status.type
const title = helper.checkSpecialChars(status.title) ? '' : status.title // const title = helper.checkSpecialChars(status.title) ? '' : status.title
el.appendChild(`<i // el.appendChild(`<i
title="${title}" // title="${title}"
class="${this.resolveClasses(key, type)}" // class="${this.resolveClasses(key, type)}"
aria-hidden="true" // aria-hidden="true"
> // >
${text} // ${text}
</i>`) // </i>`)
el.classList.add('remixui_icon') // el.classList.add('remixui_icon')
} // }
/** /**
* Remove an icon from the map * Remove an icon from the map

@ -596,7 +596,7 @@ export const CompilerContainer = (props: CompilerContainerProps) => {
} }
<button id="compileBtn" data-id="compilerContainerCompileBtn" className="btn btn-primary btn-block remixui_disabled mt-3" title="Compile" onClick={compile} disabled={disableCompileButton}> <button id="compileBtn" data-id="compilerContainerCompileBtn" className="btn btn-primary btn-block remixui_disabled mt-3" title="Compile" onClick={compile} disabled={disableCompileButton}>
<span> <span>
{ <i ref={compileIcon} className="fas fa-sync remixui_icon" aria-hidden="true"></i> } { <i ref={compileIcon} className="fas fa-sync remixui_iconbtn" aria-hidden="true"></i> }
Compile { typeof state.compiledFileName === 'string' ? helper.extractNameFromKey(state.compiledFileName) || '<no file selected>' : '<no file selected>' } Compile { typeof state.compiledFileName === 'string' ? helper.extractNameFromKey(state.compiledFileName) || '<no file selected>' : '<no file selected>' }
</span> </span>
</button> </button>

@ -151,7 +151,7 @@
padding: 8px 0; padding: 8px 0;
border: none; border: none;
} }
.remixui_icon { .remixui_iconbtn {
margin-right: 0.3em; margin-right: 0.3em;
} }
.remixui_errorBlobs { .remixui_errorBlobs {

@ -0,0 +1,57 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
// eslint-disable-next-line no-use-before-define
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel'
// eslint-disable-next-line no-use-before-define
import React, { Fragment, useEffect, useReducer } from 'react'
import { iconBadgeReducer, IconBadgeReducerAction } from '../reducers/iconBadgeReducer'
import { BadgeStatus, IconProfile, IconStatus } from './Icon'
interface BadgeProps {
verticalIconPlugin: VerticalIcons
iconRef: React.MutableRefObject<any>
profile: IconProfile,
badgeStatus: BadgeStatus
}
// eslint-disable-next-line no-undef
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function Badge ({ iconRef, verticalIconPlugin, profile, badgeStatus }: BadgeProps) {
/**
* resolve a classes list for @arg key
* @param {Object} key
* @param {Object} type
*/
function resolveClasses (key: string, type: string) {
let classes = 'remixui_status'
switch (key) {
case 'succeed':
classes += ' fas fa-check-circle text-' + type + ' ' + 'remixui_statusCheck'
break
case 'edited':
classes += ' fas fa-sync text-' + type + ' ' + 'remixui_statusCheck'
break
case 'loading':
classes += ' fas fa-spinner text-' + type + ' ' + 'remixui_statusCheck'
break
case 'failed':
classes += ' fas fa-exclamation-triangle text-' + type + ' ' + 'remixui_statusCheck'
break
default: {
classes += ' badge badge-pill badge-' + type
}
}
return classes
}
return (
<i
title={badgeStatus.title}
className={`${resolveClasses(badgeStatus.key, badgeStatus.type!)} remixui_status`}
aria-hidden="true"
>
{badgeStatus.text}
</i>
)
}
export default Badge

@ -10,7 +10,7 @@ interface HomeProps {
function Home ({ verticalIconPlugin }: HomeProps) { function Home ({ verticalIconPlugin }: HomeProps) {
return ( return (
<div <div
className="m-1 mt-2 remixui_homeIcon" className="pl-1 mt-2 remixui_homeIcon"
onClick={async () => verticalIconPlugin.activateHome()} onClick={async () => verticalIconPlugin.activateHome()}
// @ts-ignore // @ts-ignore
plugin="home" plugin="home"

@ -6,16 +6,48 @@ import VerticalIconsContextMenu from '../vertical-icons-context-menu'
import React, { Fragment, SyntheticEvent, useEffect, useReducer, useRef, useState } from 'react' import React, { Fragment, SyntheticEvent, useEffect, useReducer, useRef, useState } from 'react'
import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel' import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel'
// import * as helper from '../../../../../../apps/remix-ide/src/lib/helper' // import * as helper from '../../../../../../apps/remix-ide/src/lib/helper'
import { defaultState, iconStatusReducer } from '../reducers/iconReducers' import Badge from './Badge'
import { iconBadgeReducer, IconBadgeReducerAction } from '../reducers/iconBadgeReducer'
interface IconProps { interface IconProps {
verticalIconPlugin: VerticalIcons verticalIconPlugin: VerticalIcons
profile: any profile: IconProfile
contextMenuAction: (evt: any, profileName: string, documentation: string) => void contextMenuAction: (evt: any, profileName: string, documentation: string) => void
addActive: (profileName: string) => void addActive: (profileName: string) => void
removeActive: () => void removeActive: () => void
} }
export interface IconStatus {
key: string
title: string
type: string
}
export interface BadgeStatus extends IconStatus {
text: string
}
export interface IconProfile {
description: string
displayName: string
documentation: string
events: any[]
icon: string
kind: string
location: string
methods: string[]
name: string
version: string
tooltip?: string
}
const initialState = {
text: '',
key: '',
title: '',
type: ''
}
function Icon ({ function Icon ({
profile, profile,
verticalIconPlugin, verticalIconPlugin,
@ -39,8 +71,8 @@ function Icon ({
const [showContext, setShowContext] = useState(false) const [showContext, setShowContext] = useState(false)
const [canDeactivate] = useState(false) const [canDeactivate] = useState(false)
const iconRef = useRef<any>(null) const iconRef = useRef<any>(null)
const [badgeStatus, dispatchStatusUpdate] = useReducer(iconBadgeReducer, initialState)
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const [status, dispatchIconStatus] = useReducer(iconStatusReducer, defaultState)
const handleContextMenu = (e: SyntheticEvent & PointerEvent) => { const handleContextMenu = (e: SyntheticEvent & PointerEvent) => {
const deactivationState = verticalIconPlugin.appManager const deactivationState = verticalIconPlugin.appManager
@ -59,49 +91,10 @@ function Icon ({
setShowContext(false) setShowContext(false)
} }
/**
* Set a new status for the @arg name
* keys = ['succeed', 'edited', 'none', 'loading', 'failed']
* types = ['error', 'warning', 'success', 'info', '']
* @param {String} name
* @param {Object} status
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
// function setIconStatus (name: string, status: any) {
// if (!iconRef.current) return
// const statusEl = iconRef.current.querySelector('i')
// if (statusEl) {
// iconRef.current.removeChild(statusEl) // need to eject component instead of removing?
// }
// if (status.key === 'none') return // remove status
// let text = ''
// let key = ''
// if (typeof status.key === 'number') {
// key = status.key.toString()
// text = key
// } else key = helper.checkSpecialChars(status.key) ? '' : status.key
// let type = ''
// if (status.type === 'error') {
// type = 'danger' // to use with bootstrap
// } else type = helper.checkSpecialChars(status.type) ? '' : status.type
// const title = helper.checkSpecialChars(status.title) ? '' : status.title
// const icon = document.createElement('i')
// icon.title = title
// // icon.className = resolveClasses(key, type)
// icon.ariaHidden = 'true'
// const innerText = document.createTextNode(text)
// icon.appendChild(innerText)
// iconRef.current!.appendChild(icon)
// iconRef.current.classList.add('remixui_icon')
// }
useEffect(() => { useEffect(() => {
console.log('profile.name: ', profile.name) verticalIconPlugin.on(profile.name, 'statusChanged', (iconStatus: IconStatus) => {
verticalIconPlugin.on(profile.name, 'statusChanged', () => { const action: IconBadgeReducerAction = { type: profile.name, payload: { status: iconStatus, ref: iconRef } }
console.log('caught statusChanged in react! icon.tsx') dispatchStatusUpdate(action)
}) })
}, []) }, [])
@ -134,15 +127,16 @@ function Icon ({
> >
<img className="remixui_image" src={icon} alt={name} /> <img className="remixui_image" src={icon} alt={name} />
</div> </div>
{/* { status && status.profileName.length {
? <i verticalIconPlugin.keys.includes(badgeStatus.key) ? (
title={status.title} <Badge
className={resolveClasses(status.key as string, status.type)} iconRef={iconRef}
aria-hidden="true" verticalIconPlugin={verticalIconPlugin}
> profile={profile}
{status.text} badgeStatus={badgeStatus}
</i> : null />
} */} ) : null
}
{showContext ? ( {showContext ? (
<VerticalIconsContextMenu <VerticalIconsContextMenu
pageX={pageX} pageX={pageX}

@ -33,7 +33,7 @@ function Settings ({ scrollableRef, verticalIconsPlugin, itemContextAction, addA
}) })
}, []) }, [])
return ( return (
<div id="settingsIcons" data-id="vertialIconsSettingsIcons" ref={settingsRef}> <div id="settingsIcons" className="remixui_settings flex-grow-0" data-id="vertialIconsSettingsIcons" ref={settingsRef}>
<Chevron <Chevron
divElementRef={scrollableRef} divElementRef={scrollableRef}
cssRule={'fa fa-chevron-down remixui_icon-chevron mt-0 mb-0 ml-1 pl-3'} cssRule={'fa fa-chevron-down remixui_icon-chevron mt-0 mb-0 ml-1 pl-3'}

@ -0,0 +1,60 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import helper from 'apps/remix-ide/src/lib/helper'
import { BadgeStatus, IconStatus } from '../components/Icon'
import React from 'react'
export type IconBadgeReducerAction = {
readonly type: string
readonly payload: any
}
// const fn = (status: IconStatus) => {
// if (!verticalIconPlugin.types.includes(status.type) && status.type) throw new Error(`type should be ${verticalIconPlugin.keys.join()}`)
// if (status.key === undefined) throw new Error('status key should be defined')
// if (typeof status.key === 'string' && (!verticalIconPlugin.keys.includes(status.key))) {
// throw new Error('key should contain either number or ' + verticalIconPlugin.keys.join())
// }
// }
/**
* Set a new status for the @arg name
* @param {String} name
* @param {Object} status
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
// if (!ref.current) return
function setIconStatus (name: string, status: IconStatus, ref: React.MutableRefObject<any>) {
const statusEl = ref.current.querySelector('i')
if (statusEl) {
ref.current.removeChild(statusEl) // need to eject component instead of removing?
}
if (status.key === 'none') return { ...status, text: '' } // remove status
let text = ''
let key = ''
if (typeof status.key === 'number') {
key = status.key
// eslint-disable-next-line @typescript-eslint/no-unused-vars
text = key
} else key = helper.checkSpecialChars(status.key) ? '' : status.key
let thisType = ''
if (status.type === 'error') {
thisType = 'danger' // to use with bootstrap
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} else thisType = helper.checkSpecialChars(status.type) ? '' : status.type!
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const title = helper.checkSpecialChars(status.title) ? '' : status.title
// ref.current.classList.add('remixui_icon')
return { title, type: thisType, key, text }
}
export function iconBadgeReducer (state: BadgeStatus, action: IconBadgeReducerAction) {
const status = setIconStatus(action.type, action.payload.status, action.payload.ref)
if (action.type.length > 0) {
console.log(`from reducer of ${action.type} :`, { status })
return status
}
return state
}

@ -1,49 +0,0 @@
export const defaultState: {
key: string | number
title: string
type: string
text: string
profileName: string
errorStatus: () => void
} = { key: '', title: '', type: '', text: '', profileName: '', errorStatus: () => {} }
export type IconStatusActionType = {
type: 'success' | 'warning' | 'error' | 'info' | ''
payload?: any
}
/** status: { key: string | number, title: string, type: string }
* resolve a classes list for @arg key
* @param {String} key
* @param {String} type
*/
export function resolveClasses (key: string, type: string) {
let classes = 'remixui_status'
switch (key) {
case 'succeed':
classes += ' fas fa-check-circle text-' + type + ' ' + 'remixui_statusCheck'
break
case 'edited':
classes += ' fas fa-sync text-' + type + ' ' + 'remixui_statusCheck'
break
case 'loading':
classes += ' fas fa-spinner text-' + type + ' ' + 'remixui_statusCheck'
break
case 'failed':
classes += ' fas fa-exclamation-triangle text-' + type + ' ' + 'remixui_statusCheck'
break
default: {
classes += ' badge badge-pill badge-' + type
}
}
return classes
}
export function iconStatusReducer (state, action: IconStatusActionType) {
const { type, payload } = action
if (type === 'success') {
}
return defaultState
}

@ -1,8 +1,7 @@
.remixui_homeIcon { .remixui_homeIcon {
display: block; /* display: block; */
width: 42px; width: 42px;
height: 42px; height: 42px;
margin-bottom: 20px;
cursor: pointer; cursor: pointer;
} }
.remixui_homeIcon svg path { .remixui_homeIcon svg path {
@ -40,9 +39,9 @@
bottom: 0; bottom: 0;
} }
.remixui_status { .remixui_status {
position: absolute; /* position: relative;
bottom: 0; bottom: 0;
right: 0; right: 0; */
} }
.remixui_statusCheck { .remixui_statusCheck {
font-size: 1.2em; font-size: 1.2em;
@ -83,7 +82,8 @@
-ms-overflow-style: none; -ms-overflow-style: none;
} }
.remixui_scrollable-container { .remixui_scrollable-container {
height: 550px; flex-basis: 510px;
flex-grow: 2;
/* border-bottom: 3px solid #3f4455; */ /* border-bottom: 3px solid #3f4455; */
} }
.remixui_scrollbar::-webkit-scrollbar { /* Chrome, Safari and other Webkit browsers*/ .remixui_scrollbar::-webkit-scrollbar { /* Chrome, Safari and other Webkit browsers*/
@ -100,12 +100,12 @@
} }
.remixui_settings { .remixui_settings {
height: 30px; flex-basis: 50px;
} }
.remixui_requiredSection { .remixui_requiredSection {
min-height: 180px; flex-basis: 180px;
max-height: 330px; flex-grow: 1;
} }
#menuitems { #menuitems {

@ -95,10 +95,10 @@ export function RemixUiVerticalIconsPanel ({
return ( return (
<div id="iconsP" className="h-100"> <div id="iconsP" className="h-100">
<div className="remixui_icons" ref={iconPanelRef}> <div className="remixui_icons d-flex flex-column vh-100" ref={iconPanelRef}>
<Home verticalIconPlugin={verticalIconsPlugin} />
<div className={scrollableRef.current && scrollableRef.current.scrollHeight > scrollableRef.current.clientHeight <div className={scrollableRef.current && scrollableRef.current.scrollHeight > scrollableRef.current.clientHeight
? 'remixui_default-icons-container remixui_requiredSection' : 'remixui_requiredSection'}> ? 'remixui_default-icons-container remixui_requiredSection' : 'remixui_requiredSection'}>
<Home verticalIconPlugin={verticalIconsPlugin} />
<RequiredSection <RequiredSection
verticalIconsPlugin={verticalIconsPlugin} verticalIconsPlugin={verticalIconsPlugin}
addActive={addActive} addActive={addActive}

Loading…
Cancel
Save