From 8d7ebf9c1b39abb2ee34364e605f65ed2632a1f6 Mon Sep 17 00:00:00 2001 From: David Nicholson Date: Tue, 25 Feb 2020 21:28:44 +0000 Subject: [PATCH] Various UI improvements based on walk-through with Peng/John (#117) * improve layout of invocation panel * change a word * close dialogs after navigating to tracker * when doing a devtracker search, reuse an old panel if possible (preference to oldest panel) * fixes #105 * Make "Claim GAS" dialog capable of transferring NEO before claiming GAS. fixes #114 * claim will never work if RPC server does not support getting claimables --- src/claimPanel.ts | 102 ++++++++++++++++++- src/deployPanel.ts | 1 + src/neoTrackerPanel.ts | 65 ++++++++++-- src/panels/claim.html | 13 ++- src/panels/claim.main.ts | 16 ++- src/panels/claimSelectors.ts | 3 + src/panels/invoke.html | 184 +++++++++++++++++----------------- src/panels/invoke.scss | 69 +++++++++---- src/panels/invokeRenderers.ts | 7 +- src/panels/invokeSelectors.ts | 2 - src/transferPanel.ts | 1 + 11 files changed, 328 insertions(+), 135 deletions(-) diff --git a/src/claimPanel.ts b/src/claimPanel.ts index b97a43a..4ad0506 100644 --- a/src/claimPanel.ts +++ b/src/claimPanel.ts @@ -1,3 +1,4 @@ +import * as bignumber from 'bignumber.js'; import * as fs from 'fs'; import * as neon from '@cityofzion/neon-js'; import * as path from 'path'; @@ -6,6 +7,7 @@ import * as vscode from 'vscode'; import { claimEvents } from './panels/claimEvents'; import { INeoRpcConnection } from './neoRpcConnection'; +import { IWallet } from './iWallet'; import { NeoExpressConfig } from './neoExpressConfig'; import { NeoTrackerPanel } from './neoTrackerPanel'; import { WalletExplorer } from './walletExplorer'; @@ -15,6 +17,9 @@ const CssHrefPlaceholder : string = '[CSS_HREF]'; class ViewState { claimable: number = 0; + unavailable: number = 0; + doSelfTransfer: boolean = false; + doSelfTransferEnabled: boolean = true; getClaimableError: boolean = false; isValid: boolean = false; result: string = ''; @@ -63,6 +68,7 @@ export class ClaimPanel { walletExplorer, disposables, neoExpressConfig); + this.dispose(); // close the dialog after navigating to the tracker }; this.panel = vscode.window.createWebviewPanel( @@ -100,6 +106,9 @@ export class ClaimPanel { try { const walletConfig = this.viewState.wallets.filter(_ => _.address === this.viewState.walletAddress)[0]; if (await walletConfig.unlock()) { + if (this.viewState.doSelfTransfer) { + await this.doSelfTransfer(walletConfig); + } const api = new neon.api.neoCli.instance(this.rpcUri); const config: any = { api: api, @@ -129,6 +138,74 @@ export class ClaimPanel { } } + private async doSelfTransfer(walletConfig: IWallet) { + if (this.viewState.walletAddress) { + const walletAddress = this.viewState.walletAddress; + const getUnspentsResult = await this.rpcConnection.getUnspents(walletAddress, this); + if (getUnspentsResult.assets && getUnspentsResult.assets['NEO']) { + const neoUnspents = getUnspentsResult.assets['NEO'].unspent; + if (neoUnspents && neoUnspents.length) { + let sum = new bignumber.BigNumber(0); + for (let i = 0; i < neoUnspents.length; i++) { + sum = sum.plus(neoUnspents[i].value as bignumber.BigNumber); + } + const totalNeo = sum.toNumber(); + const api = new neon.api.neoCli.instance(this.rpcUri); + const config: any = { + api: api, + account: walletConfig.account, + signingFunction: walletConfig.signingFunction, + intents: neon.api.makeIntent({ 'NEO': totalNeo }, walletAddress), + }; + if (walletConfig.isMultiSig) { + // The neon.default.sendAsset function expects the config.account property to be present and + // a regular (non-multisig) account object (so we arbitrarily provide the fist account in + // the multisig group); however it also uses config.account.address when looking up the available + // balance. So we manually lookup the available balance (using the multisig address) and then + // pass it in (thus avoiding the balance lookup within sendAsset). + config.balance = await api.getBalance(walletAddress); + } + const result = await neon.default.sendAsset(config); + if (result.response && result.response.txid) { + return new Promise((resolve, reject) => { + const initialClaimable = this.viewState.claimable; + let attempts = 0; + const resolveWhenClaimableIncreases = async () => { + attempts++; + if (attempts > 15) { + console.error('ClaimPanel timed out waiting for self-transfer to confirm; continuing with claim'); + resolve(); + } else { + try { + const unclaimed = await this.rpcConnection.getUnclaimed(walletAddress, this); + if (!unclaimed.getUnclaimedSupport) { + reject('No longer able to determine unclaimed GAS'); + } else if (unclaimed.available > initialClaimable) { + resolve(); + } else { + setTimeout(resolveWhenClaimableIncreases, 2000); + } + } catch (e) { + reject('Error determining unclaimed GAS'); + } + } + }; + resolveWhenClaimableIncreases(); + }); + } else { + console.error('ClaimPanel self-transfer failed', result, getUnspentsResult, this.viewState); + } + } else { + console.error('ClaimPanel skipping self-transfer (no unspent NEO)', getUnspentsResult, this.viewState); + } + } else { + console.error('ClaimPanel skipping self-transfer (no unspents)', getUnspentsResult, this.viewState); + } + } else { + console.error('ClaimPanel skipping self-transfer (no wallet sleected)', this.viewState); + } + } + private onClose() { this.dispose(); } @@ -178,14 +255,30 @@ export class ClaimPanel { this.viewState.claimable = 0; const walletConfig = this.viewState.wallets.filter(_ => _.address === this.viewState.walletAddress)[0]; const walletAddress = walletConfig ? walletConfig.address : undefined; + this.viewState.doSelfTransferEnabled = false; if (walletAddress) { + this.viewState.doSelfTransferEnabled = true; try { - const claimable = await this.rpcConnection.getClaimable(walletAddress, this); - this.viewState.claimable = claimable.unclaimed || 0; - this.viewState.getClaimableError = !claimable.getClaimableSupport; + const unclaimed = await this.rpcConnection.getUnclaimed(walletAddress, this); + this.viewState.claimable = unclaimed.available || 0; + this.viewState.unavailable = unclaimed.unavailable || 0; + this.viewState.getClaimableError = !unclaimed.getUnclaimedSupport; + if (this.viewState.getClaimableError) { + this.viewState.doSelfTransfer = false; + this.viewState.doSelfTransferEnabled = false; + } else { + if ((this.viewState.claimable === 0) && (this.viewState.unavailable > 0)) { + this.viewState.doSelfTransfer = true; + this.viewState.doSelfTransferEnabled = false; + } else if (this.viewState.unavailable === 0) { + this.viewState.doSelfTransfer = false; + this.viewState.doSelfTransferEnabled = false; + } + } } catch (e) { console.error('ClaimPanel could not query claimable GAS', walletAddress, this.rpcUri, e); this.viewState.claimable = 0; + this.viewState.unavailable = 0; this.viewState.getClaimableError = true; } } @@ -198,7 +291,8 @@ export class ClaimPanel { this.viewState.isValid = !!this.viewState.walletAddress && - ((this.viewState.claimable > 0) || this.viewState.getClaimableError); + !this.viewState.getClaimableError && + ((this.viewState.claimable > 0) || (this.viewState.unavailable > 0)); this.initialized = true; } diff --git a/src/deployPanel.ts b/src/deployPanel.ts index ad589f8..3047f4d 100644 --- a/src/deployPanel.ts +++ b/src/deployPanel.ts @@ -70,6 +70,7 @@ export class DeployPanel { walletExplorer, disposables, neoExpressConfig); + this.dispose(); // close the dialog after navigating to the tracker }; this.panel = vscode.window.createWebviewPanel( diff --git a/src/neoTrackerPanel.ts b/src/neoTrackerPanel.ts index 1818478..d6f37fe 100644 --- a/src/neoTrackerPanel.ts +++ b/src/neoTrackerPanel.ts @@ -38,6 +38,41 @@ class ViewState { public searchCompletions: any[] = []; } +class PanelCache { + + private readonly cache: Map = new Map(); + + public add(panel: NeoTrackerPanel, rpcConnection: INeoRpcConnection, neoExpressConfig?: NeoExpressConfig) { + const key = PanelCache.makeKey(rpcConnection, neoExpressConfig); + let panels = this.cache.get(key); + if (!panels) { + panels = []; + this.cache.set(key, panels); + } + panels.push(panel); + } + + public remove(panel: NeoTrackerPanel, rpcConnection: INeoRpcConnection, neoExpressConfig?: NeoExpressConfig) { + const key = PanelCache.makeKey(rpcConnection, neoExpressConfig); + const panels = this.cache.get(key); + if (panels) { + this.cache.set(key, panels.filter(p => p !== panel)); + } + } + + public get(rpcConnection: INeoRpcConnection, neoExpressConfig?: NeoExpressConfig): NeoTrackerPanel | undefined { + const key = PanelCache.makeKey(rpcConnection, neoExpressConfig); + const panels = this.cache.get(key); + if (panels && panels.length) { + return panels[0]; + } + } + + private static makeKey(rpcConnection: INeoRpcConnection, neoExpressConfig?: NeoExpressConfig): string { + return rpcConnection.rpcUrl + ':' + (neoExpressConfig ? neoExpressConfig.neoExpressJsonFullPath : 'non-neo-express'); + } +} + export class NeoTrackerPanel implements INeoSubscription, INeoStatusReceiver { public readonly panel: vscode.WebviewPanel; public readonly ready: Promise; @@ -52,6 +87,8 @@ export class NeoTrackerPanel implements INeoSubscription, INeoStatusReceiver { private rpcConnection: INeoRpcConnection; private isPageLoading: boolean; + private static panelCache = new PanelCache(); + public static async newSearch( query: string, extensionPath: string, @@ -62,14 +99,18 @@ export class NeoTrackerPanel implements INeoSubscription, INeoStatusReceiver { disposables: vscode.Disposable[], neoExpressConfig?: NeoExpressConfig) { - const panel = new NeoTrackerPanel( - extensionPath, - rpcConnection, - historyId, - state, - walletExplorer, - disposables, - neoExpressConfig); + let panel = this.panelCache.get(rpcConnection, neoExpressConfig); + if (!panel) { + panel = new NeoTrackerPanel( + extensionPath, + rpcConnection, + historyId, + state, + walletExplorer, + disposables, + neoExpressConfig); + } + panel.focus(); await panel.search(query); } @@ -118,6 +159,8 @@ export class NeoTrackerPanel implements INeoSubscription, INeoStatusReceiver { this.panel.webview.html = htmlFileContents .replace(JavascriptHrefPlaceholder, javascriptHref) .replace(CssHrefPlaceholder, cssHref); + + NeoTrackerPanel.panelCache.add(this, this.rpcConnection, this.neoExpressConfig); } public async onNewBlock(blockchainInfo: BlockchainInfo) { @@ -134,6 +177,10 @@ export class NeoTrackerPanel implements INeoSubscription, INeoStatusReceiver { this.panel.webview.postMessage({ status: { message: status, isLoading: this.isPageLoading } }); } + public focus() { + this.panel.reveal(); + } + private async augmentSearchHistory(query: string) { query = (query + '').replace(/^0x/, ''); if (query.length) { @@ -193,7 +240,9 @@ export class NeoTrackerPanel implements INeoSubscription, INeoStatusReceiver { } private onClose() { + NeoTrackerPanel.panelCache.remove(this, this.rpcConnection, this.neoExpressConfig); this.rpcConnection.unsubscribe(this); + this.dispose(); } private async search(query: string) { diff --git a/src/panels/claim.html b/src/panels/claim.html index f914e09..4fa6e56 100644 --- a/src/panels/claim.html +++ b/src/panels/claim.html @@ -44,9 +44,7 @@

Claim GAS

- There was an error when checking claimable GAS for - . - Is Neo Express running? + There was an error when checking claimable GAS for this account.
The @@ -55,7 +53,14 @@

Claim GAS

The account - can claim GAS. + can immediately claim GAS. +
+
+
diff --git a/src/panels/claim.main.ts b/src/panels/claim.main.ts index 55590fe..02554c1 100644 --- a/src/panels/claim.main.ts +++ b/src/panels/claim.main.ts @@ -53,6 +53,7 @@ function populateWalletDropdown() { function render() { const claimButton = document.querySelector(claimSelectors.ClaimButton) as HTMLButtonElement; const walletDropdown = document.querySelector(claimSelectors.WalletDropdown) as HTMLSelectElement; + const doTransferCheckbox = document.querySelector(claimSelectors.DoSelfTransferCheckbox) as HTMLInputElement; populateWalletDropdown(); if (viewState.showSuccess) { const resultPlaceholder = document.querySelector(claimSelectors.SearchLinkPlaceholder) as HTMLElement; @@ -66,14 +67,18 @@ function render() { } htmlHelpers.setPlaceholder(claimSelectors.DisplayWallet, htmlHelpers.text(viewState.walletDescription || '(unknown)')); htmlHelpers.setPlaceholder(claimSelectors.DisplayClaimable, htmlHelpers.text(htmlHelpers.number(viewState.claimable || 0))); + htmlHelpers.setPlaceholder(claimSelectors.DisplayUnavailable, htmlHelpers.text(viewState.getClaimableError ? '' : htmlHelpers.number(viewState.unavailable || 0))); htmlHelpers.setPlaceholder(claimSelectors.ErrorMessage, htmlHelpers.text(viewState.result)); htmlHelpers.showHide(claimSelectors.ErrorClaimableRetrievalFailure, viewState.getClaimableError); - htmlHelpers.showHide(claimSelectors.ErrorWalletHasNoClaimableGas, viewState.walletAddress && !viewState.showError && !(viewState.getClaimableError || (viewState.claimable > 0))); - htmlHelpers.showHide(claimSelectors.ClaimableInfo, viewState.claimable > 0); + htmlHelpers.showHide(claimSelectors.ErrorWalletHasNoClaimableGas, viewState.walletAddress && !viewState.showError && !(viewState.getClaimableError || (viewState.claimable > 0) || (viewState.unavailable > 0))); + htmlHelpers.showHide(claimSelectors.ClaimableInfo, !!viewState.walletAddress && !viewState.getClaimableError); + htmlHelpers.showHide(claimSelectors.UnavailableInfo, !!viewState.walletAddress && !viewState.getClaimableError); htmlHelpers.showHide(claimSelectors.ErrorMessage, viewState.showError); htmlHelpers.showHide(claimSelectors.ViewResults, viewState.showSuccess); htmlHelpers.showHide(claimSelectors.ViewDataEntry, !viewState.showSuccess); htmlHelpers.showHide(claimSelectors.ErrorMessage, !!viewState.showError); + doTransferCheckbox.checked = viewState.doSelfTransfer; + doTransferCheckbox.disabled = !viewState.doSelfTransferEnabled; claimButton.disabled = !viewState.isValid; walletDropdown.disabled = false; } @@ -94,6 +99,7 @@ function initializePanel() { const closeButton = document.querySelector(claimSelectors.CloseButton) as HTMLButtonElement; const refreshLink = document.querySelector(claimSelectors.RefreshClaimableLink) as HTMLAnchorElement; const walletDropdown = document.querySelector(claimSelectors.WalletDropdown) as HTMLSelectElement; + const doTransferCheckbox = document.querySelector(claimSelectors.DoSelfTransferCheckbox) as HTMLInputElement; claimButton.addEventListener('click', _ => { enterLoadingState(); vscode.postMessage({ e: claimEvents.Claim }); @@ -118,6 +124,12 @@ function initializePanel() { } console.log('->', viewState); }); + doTransferCheckbox.addEventListener('change', _ => { + viewState.doSelfTransfer = doTransferCheckbox.checked; + enterLoadingState(); + vsCodePostMessage({ e: claimEvents.Update, c: viewState }); + console.log('->', viewState); + }); window.addEventListener('message', msg => handleMessage(msg.data)); enterLoadingState(); vscode.postMessage({ e: claimEvents.Init }); diff --git a/src/panels/claimSelectors.ts b/src/panels/claimSelectors.ts index bec060c..20b5b2c 100644 --- a/src/panels/claimSelectors.ts +++ b/src/panels/claimSelectors.ts @@ -4,8 +4,10 @@ const claimSelectors = { ClaimableInfo: '#claimableInfo', ClaimButton: '#claim', CloseButton: '#close', + DisplayUnavailable: '.display-unavailable', DisplayClaimable: '.display-claimable', DisplayWallet: '.display-wallet', + DoSelfTransferCheckbox: '#doSelfTransfer', ErrorClaimableRetrievalFailure: '#errorClaimableRetrievalFailure', ErrorMessage: '#error-message', ErrorWalletHasNoClaimableGas: '#errorWalletHasNoClaimableGas', @@ -13,6 +15,7 @@ const claimSelectors = { RefreshClaimableLink: '#refreshClaimableLink', ResultText: '.result-text', SearchLinkPlaceholder: '#searchLink', + UnavailableInfo: '#unavailableInfo', ViewDataEntry: '#data-entry-view', ViewResults: '#results-view', WalletDropdown: '#walletDropdown', diff --git a/src/panels/invoke.html b/src/panels/invoke.html index 8c588cf..b53c699 100644 --- a/src/panels/invoke.html +++ b/src/panels/invoke.html @@ -55,12 +55,78 @@

Error

-

- - Smart contracts -

+
+

+ + Smart contracts +

+
+
-
+
+
+
+
Smart Contract Tips:
+
+
Debug vs. Invoke vs. Broadcast:
+
+ Clicking Debug will run the contract locally within the Visual Studio Code + debugger, optionally using a previously saved Neo Express checkpoint. +
+
+ Clicking Invoke will evaluate the contract method on an actual blockchain node, + but will not publish a transaction to be persisted on the blockchain. +
+
+ Clicking Broadcast will create an InvocationTransaction and broadcast + it to a node for addition to the blockchain. +
+
Entering Parameters:
+
+
+ Parameters of type ByteArray: +
+
+ To provide a NEO address, enter the address prefixed with the '@' character, e.g. + @AJCtRExcE3BCGniuLQA9ZRh21heAc2Yf8R. +
+
+ To provide data as a hex string, enter the hex string prefixed with '0x', e.g. + 0x0123456789abcdef. +
+
+ To provide an arbitrary string, enter it as-is, e.g. HelloWorld. +
+
+ Parameters of type Integer: +
+
+ Enter an integer value as-is, e.g. 3422342349565424. +
+
+ Parameters of type String: +
+
+ Supply arbitrary text, as-is, e.g. HelloWorld. +
+
+ Parameters of type Array: +
+
+ Supply a JSON array containing any combination of numbers, text strings, hex strings and addresses, e.g. + [42, 'foo', '0x1234', '@AJCtRExcE3BCGniuLQA9ZRh21heAc2Yf8R']. +
+
+
Spending to a Contract:
+
+ In the spend field, optionally supply an asset symbol (e.g. NEO) and value (e.g. 50). + If a value greater than zero is entered, appropriate UTXOs will be assembled and spent to + the contract. +
+
+
+
+
@@ -87,7 +153,6 @@

-

Invoke contract method: ''

@@ -99,11 +164,12 @@

Invoke contract method: ''

-
-
- -
+
+
Launch contract in debugger
+
+ Run the contract method locally in the Visual Studio Code debugger: +
@@ -112,14 +178,25 @@

Invoke contract method: ''

-
Checkpoint: (Optional)
-
- + +
+ +
+
+
+
Invoke contract method
+
+ Evaluate the contract method using a blockchain node: +
+
+
-
-
+
Broadcast invocation transaction
+
+ Create an invocation transaction for the contract method and broadcast it for inclusion in the blockchain: +
@@ -135,12 +212,11 @@

Invoke contract method: ''

Spend: (Required)
-
- +
+
-
@@ -176,78 +252,6 @@

Invoke contract method: ''

No result was returned.
-
-
Tips:
-
Call vs. Invoke vs. Debug:
-
-
    -
  • - Calling a contract will invoke the method using the Neo Express - instance, but not broadcast a transaction. -
  • -
  • - Invoking a contract will create and broadcast an - InvocationTransaction using the Neo Express instance. -
  • -
  • - Debugging a contract will launch the contract in the Visual - Studio Code debugger, optionally using a previously saved Neo Express - checkpoint. -
  • -
-
-
Parameters of type ByteArray:
-
-
    -
  • - To supply a NEO address, enter the address prefixed with the '@' character, e.g. - @AJCtRExcE3BCGniuLQA9ZRh21heAc2Yf8R. -
  • -
  • - To supply a hex string, enter the string prefixed with '0x', e.g. - 0x0123456789abcdef. -
  • -
  • - To supply arbitrary text, enter as-is. -
  • -
-
-
Parameters of type Integer:
-
-
    -
  • - Enter an integer value as-is, e.g. 3422342349565424. -
  • -
-
-
Parameters of type String:
-
-
    -
  • - Supply arbitrary text, as-is. -
  • -
-
-
Parameters of type Array:
-
-
    -
  • - Supply a JSON array containing any combination of numbers, strings, hex strings and addresses, e.g. - [42, 'foo', '0x1234', '@AJCtRExcE3BCGniuLQA9ZRh21heAc2Yf8R']. -
  • -
-
-
Spend:
-
-
    -
  • - Optionally supply an asset symbol (e.g. NEO) and value (e.g. 50). If greater - than zero, appropriate UTXOs will be assembled and spent to the contract. -
  • -
-
-
-
diff --git a/src/panels/invoke.scss b/src/panels/invoke.scss index da56643..574a862 100644 --- a/src/panels/invoke.scss +++ b/src/panels/invoke.scss @@ -13,18 +13,16 @@ body { display: inline-block; } -.half { - width: 50%; - display: inline-block; +.actions { text-align: center; - padding-bottom: 20px; margin: 0; table { width: 98%; - margin-bottom: 5px; + margin-bottom: 10px; } button { - width: 98%; + margin-right: 10px; + width: 30%; } } @@ -85,19 +83,6 @@ h4 { } } } - .instructions { - background-color: var(--vscode-sideBar-background); - color: var(--vscode-sideBar-foreground); - border: 1px solid var(--vscode-sideBar-border); - box-shadow: 1px 1px 1px var(--vscode-widget-shadow); - margin: 12px 10px 10px 10px; - padding: 10px; - opacity: 0.75; - clear: both; - div:not(:first-child) { - margin-left: 20px; - } - } } input { @@ -169,7 +154,17 @@ table { background-color: var(--vscode-sideBar-background); border: 1px solid var(--vscode-sideBarSectionHeader-background); margin: 10px; - padding: 10px; + padding: 0px 0px 10px 0px; + h5 { + text-align: left; + margin: 0px 0px 10px 0px; + padding: 5px; + background-color: var(--vscode-sideBarSectionHeader-background); + } + .description { + text-align: left; + padding: 0px 0px 10px 10px; + } } ul { @@ -215,4 +210,38 @@ ul { word-break: break-all; } } +} + +#tipPane { + position: fixed; + top: 0px; + right: 0px; + bottom: 0px; + width: 30%; + margin: 0px; + overflow: auto; + overflow-wrap: break-word; + border: 1px solid var(--vscode-sideBarSectionHeader-background); + padding-top: 8px; + * > .indent { + padding-left: 8px; + margin: 5px; + } + div.strong { + margin-top: 15px; + font-size: 1.05em; + } + .example { + font-family: monospace; + } +} + +#mainPane { + position: fixed; + top: 0px; + left: 0px; + bottom: 0px; + width: 70%; + margin: 0px; + overflow: auto; } \ No newline at end of file diff --git a/src/panels/invokeRenderers.ts b/src/panels/invokeRenderers.ts index 4642a06..a766530 100644 --- a/src/panels/invokeRenderers.ts +++ b/src/panels/invokeRenderers.ts @@ -194,16 +194,14 @@ const invokeRenderers = { const placeholder = contractDetailElement.querySelector(invokeSelectors.MethodsPlaceholder); const methodTemplate = document.querySelector(invokeSelectors.MethodTemplate); - const instructionsTemplate = document.querySelector(invokeSelectors.InvokeInstructionsTemplate); - if (placeholder && methodTemplate && instructionsTemplate) { + if (placeholder && methodTemplate) { for (let i = 0; i < methods.length; i++) { const methodData = methods[i]; const methodId = contractHash + '.' + methodData.name; const thisMethod = document.createElement('div'); thisMethod.innerHTML = methodTemplate.innerHTML; const thisMethodDetail = thisMethod.querySelector(invokeSelectors.MethodDetail); - const instructionsPlaceholder = thisMethod.querySelector(invokeSelectors.InstructionsPlaceholder); - if (thisMethodDetail && instructionsPlaceholder) { + if (thisMethodDetail) { htmlHelpers.setInnerPlaceholder(thisMethod, invokeSelectors.MethodName, htmlHelpers.text(methodData.name)); (thisMethodDetail as any).style.display = selectedMethod === methodId ? 'block' : 'none'; if (selectedMethod === methodId) { @@ -249,7 +247,6 @@ const invokeRenderers = { checkpoints, methodData.selectedCheckpoint, (c: string) => { methods[i].selectedCheckpoint = c; updateViewState(); }); - instructionsPlaceholder.innerHTML = instructionsTemplate.innerHTML; placeholder.appendChild(thisMethod); } } diff --git a/src/panels/invokeSelectors.ts b/src/panels/invokeSelectors.ts index 95e501c..7391caa 100644 --- a/src/panels/invokeSelectors.ts +++ b/src/panels/invokeSelectors.ts @@ -14,7 +14,6 @@ const invokeSelectors = { MethodTemplate: '#methodTemplate', MethodName: '.methodName', MethodDetail: '.methodDetail', - InstructionsPlaceholder: '.instructions', ParametersInputArea: '.parametersInputArea', ParametersPlaceholder: '.parametersPlaceholder', ParameterTemplate: '#parameterTemplate', @@ -43,7 +42,6 @@ const invokeSelectors = { ParameterName: '.parameterName', ParameterInput: '.parameterInput', ParameterType: '.parameterType', - InvokeInstructionsTemplate: '#invokeInstructions', }; export { invokeSelectors }; \ No newline at end of file diff --git a/src/transferPanel.ts b/src/transferPanel.ts index 309a6a1..927c813 100644 --- a/src/transferPanel.ts +++ b/src/transferPanel.ts @@ -66,6 +66,7 @@ export class TransferPanel { walletExplorer, disposables, neoExpressConfig); + this.dispose(); // close the dialog after navigating to the tracker }; this.panel = vscode.window.createWebviewPanel(