release 0.1.3
This commit is contained in:
Родитель
1e51606a2f
Коммит
ed54becea2
|
@ -13,3 +13,4 @@ max_line_length = 120
|
|||
[*.html]
|
||||
indent_size = 4
|
||||
tab_width = 4
|
||||
max_line_length = off
|
||||
|
|
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -2,15 +2,23 @@
|
|||
|
||||
All notable changes to the "azureblockchain" extension will be documented in this file.
|
||||
|
||||
## 0.1.0
|
||||
|
||||
- Initial release
|
||||
|
||||
## 0.1.1
|
||||
## 0.1.3
|
||||
|
||||
- Updated menu options
|
||||
- various bug fixes
|
||||
- moved logic app/function/flow generators out of Truffle build directory into their own directory
|
||||
- refactoring of Welcome/Requirements pages
|
||||
|
||||
## 0.1.2
|
||||
|
||||
- doc and bug fixes for contract code generation
|
||||
|
||||
## 0.1.1
|
||||
|
||||
- Updated menu options
|
||||
|
||||
## 0.1.0
|
||||
|
||||
- Initial release
|
||||
|
||||
|
|
23
package.json
23
package.json
|
@ -5,7 +5,7 @@
|
|||
"publisher": "AzBlockchain",
|
||||
"preview": true,
|
||||
"icon": "images/blockchain-service-logo.png",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.3",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Microsoft/vscode-azure-blockchain-ethereum"
|
||||
|
@ -51,7 +51,6 @@
|
|||
"onCommand:azureBlockchainService.connectConsortium",
|
||||
"onCommand:drizzle.generateSmartContractUI",
|
||||
"onCommand:azureBlockchainService.copyRPCEndpointAddress",
|
||||
"onCommand:azureBlockchainService.copyAccessKey",
|
||||
"onCommand:azureBlockchainService.createConsortium",
|
||||
"onCommand:azureBlockchainService.disconnectConsortium"
|
||||
],
|
||||
|
@ -166,11 +165,6 @@
|
|||
"title": "Copy RPC Endpoint Address",
|
||||
"category": "Azure Blockchain"
|
||||
},
|
||||
{
|
||||
"command": "azureBlockchainService.copyAccessKey",
|
||||
"title": "Copy Access Key",
|
||||
"category": "Azure Blockchain"
|
||||
},
|
||||
{
|
||||
"command": "azureBlockchainService.createConsortium",
|
||||
"title": "Create Azure Blockchain Service",
|
||||
|
@ -178,7 +172,7 @@
|
|||
},
|
||||
{
|
||||
"command": "azureBlockchainService.disconnectConsortium",
|
||||
"title": "Disconnect Consortium",
|
||||
"title": "Disconnect",
|
||||
"category": "Azure Blockchain"
|
||||
},
|
||||
{
|
||||
|
@ -238,10 +232,6 @@
|
|||
"when": "false",
|
||||
"command": "azureBlockchainService.copyRPCEndpointAddress"
|
||||
},
|
||||
{
|
||||
"when": "false",
|
||||
"command": "azureBlockchainService.copyAccessKey"
|
||||
},
|
||||
{
|
||||
"when": "false",
|
||||
"command": "azureBlockchainService.disconnectConsortium"
|
||||
|
@ -308,11 +298,6 @@
|
|||
"when": "view == AzureBlockchain && viewItem == consortium",
|
||||
"group": "azureBlockchain-0@0"
|
||||
},
|
||||
{
|
||||
"command": "azureBlockchainService.copyAccessKey",
|
||||
"when": "view == AzureBlockchain && viewItem == consortium",
|
||||
"group": "azureBlockchain-0@1"
|
||||
},
|
||||
{
|
||||
"command": "azureBlockchainService.startGanacheServer",
|
||||
"when": "view == AzureBlockchain && viewItem == localconsortium && azureBlockchainService:isGanacheRunning == false",
|
||||
|
@ -326,7 +311,7 @@
|
|||
{
|
||||
"command": "azureBlockchainService.disconnectConsortium",
|
||||
"when": "view == AzureBlockchain && viewItem == consortium",
|
||||
"group": "azureBlockchain-1@1"
|
||||
"group": "azureBlockchain-0@1"
|
||||
},
|
||||
{
|
||||
"command": "azureBlockchainService.copyRPCEndpointAddress",
|
||||
|
@ -336,7 +321,7 @@
|
|||
{
|
||||
"command": "azureBlockchainService.disconnectConsortium",
|
||||
"when": "view == AzureBlockchain && viewItem == localconsortium",
|
||||
"group": "azureBlockchain-1@1"
|
||||
"group": "azureBlockchain-0@1"
|
||||
}
|
||||
],
|
||||
"explorer/context": [
|
||||
|
|
|
@ -6,152 +6,157 @@
|
|||
</head>
|
||||
|
||||
<body class="vscode-dark">
|
||||
<header>
|
||||
<div id="title-area">
|
||||
<h1>Azure Blockchain Development Kit</h1>
|
||||
<p>Interact with your private, public, and local ledgers. Develop smart contracts, test and integrate with business back ends with Logic Apps and Flow.</p>
|
||||
</div>
|
||||
</header>
|
||||
<div id="content">
|
||||
<div id="main-content">
|
||||
<div>
|
||||
<div id="quickstarts">
|
||||
<h2>Quick Starts</h2>
|
||||
<div class="quick-starts-blocks">
|
||||
<div>
|
||||
<h3>Create a New Azure Blockchain Service</h3>
|
||||
<p class="description">Click below button to create an Azure Blockchain Service</p>
|
||||
<a href="command:azureBlockchainService.createConsortium">Create Azure Blockchain Service</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="quick-starts-blocks">
|
||||
<div>
|
||||
<h3>Connect to an Existing Consortium</h3>
|
||||
<p class="description">Click below button to connect to an Azure, public or local consortium.</p>
|
||||
<a href="command:azureBlockchainService.connectConsortium">Connect to Consortium</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tutorial">
|
||||
<h2>Say Hello to Azure Blockchain in 1 Minute</h2>
|
||||
<header>
|
||||
<div id="title-area">
|
||||
<h1>Azure Blockchain Development Kit</h1>
|
||||
<p>Interact with your private, public, and local ledgers. Develop smart contracts, test and integrate with business back ends with Logic Apps and Flow.</p>
|
||||
</div>
|
||||
</header>
|
||||
<div id="content">
|
||||
<div id="main-content">
|
||||
<div>
|
||||
<div id="quickstarts">
|
||||
<h2>Quick Starts</h2>
|
||||
<div class="quick-starts-blocks">
|
||||
<div>
|
||||
<div class="interactive">
|
||||
<div>
|
||||
<div class="arrow"></div>
|
||||
<h3>Create a New Azure Blockchain Service</h3>
|
||||
</div>
|
||||
<div class="detail">
|
||||
To create a new Azure Blockchain Service if you don't have one.
|
||||
<ol>
|
||||
<li>
|
||||
<div>From the Command Palette, or Azure Blockchain tab, click on "Create Azure Blockchain Service</div>
|
||||
<img src="https://raw.githubusercontent.com/Microsoft/vscode-azure-blockchain-ethereum/master/images/createService.gif">
|
||||
</li>
|
||||
</ol>
|
||||
If you have an existing Azure Blockchain Service, you may connect to it.
|
||||
<ol>
|
||||
<li>
|
||||
<div>From the Command Palette, or Azure Blockchain tab, click on "Connect to Consortium" and select Azure Blockchain Service</div>
|
||||
<img src="https://raw.githubusercontent.com/Microsoft/vscode-azure-blockchain-ethereum/master/images/connectService.gif">
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div class="interactive">
|
||||
<div>
|
||||
<div class="arrow"></div>
|
||||
<h3>Create a Smart Contract and Project Folder</h3>
|
||||
</div>
|
||||
<div class="detail">
|
||||
To create a basic smart contract folder structure and contract.
|
||||
<ol>
|
||||
<li>
|
||||
<div>From the Command Palette click on "New Solidity Project"</div>
|
||||
<img src="https://raw.githubusercontent.com/Microsoft/vscode-azure-blockchain-ethereum/master/images/createNewProject.gif">
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div class="interactive">
|
||||
<div>
|
||||
<div class="arrow"></div>
|
||||
<h3>Interact with your Smart Contract</h3>
|
||||
</div>
|
||||
<div class="detail">
|
||||
To interact with your contract
|
||||
<ol>
|
||||
<li>
|
||||
<div>Coming soon!</div>
|
||||
<img>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<h3>Create a New Azure Blockchain Service</h3>
|
||||
<p class="description">Click below button to create an Azure Blockchain Service</p>
|
||||
<a href="command:azureBlockchainService.createConsortium">Create Azure Blockchain Service</a>
|
||||
</div>
|
||||
<h2>Learn more about our partners</h2>
|
||||
<div class="partners">
|
||||
<a href="https://www.ethereum.org/">
|
||||
<div class="specific-partner">
|
||||
<div><img class="small-image-logo" src="{{root}}/images/EthereumLogo.png"></div>
|
||||
<div>Ethereum Foundation</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://solidity.readthedocs.io/en/v0.5.5/">
|
||||
<div class="specific-partner">
|
||||
<div><img class="small-image-logo" src="{{root}}/images/SolidityLogo.png"></div>
|
||||
<div>Solidity plugin</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://truffleframework.com/docs/truffle/reference/truffle-commands">
|
||||
<div class="specific-partner">
|
||||
<div><img class="small-image-logo" src="{{root}}/images/TruffleLogo.png"></div>
|
||||
<div>Truffle Suite</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
<div class="quick-starts-blocks">
|
||||
<div>
|
||||
<h3>Connect to an Existing Consortium</h3>
|
||||
<p class="description">Click below button to connect to an Azure, public or local consortium.</p>
|
||||
<a href="command:azureBlockchainService.connectConsortium">Connect to Consortium</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
<div id="tutorial">
|
||||
<h2>Say Hello to Azure Blockchain in 1 Minute</h2>
|
||||
<div>
|
||||
Having trouble with the extension? -
|
||||
<a href="https://aka.ms/vscodebcextensionwiki">Browse the documentation</a> -
|
||||
<a href="https://aka.ms/vscodevcextensiongitissues">Report an issue</a>
|
||||
<div class="interactive">
|
||||
<div>
|
||||
<div class="arrow"></div>
|
||||
<h3>Create a New Azure Blockchain Service</h3>
|
||||
</div>
|
||||
<div class="detail">
|
||||
To create a new Azure Blockchain Service if you don't have one.
|
||||
<ol>
|
||||
<li>
|
||||
<div>From the Command Palette, or Azure Blockchain tab, click on "Create Azure Blockchain Service"</div>
|
||||
<img src="https://raw.githubusercontent.com/Microsoft/vscode-azure-blockchain-ethereum/master/images/createService.gif">
|
||||
</li>
|
||||
</ol>
|
||||
If you have an existing Azure Blockchain Service, you may connect to it.
|
||||
<ol>
|
||||
<li>
|
||||
<div>From the Command Palette, or Azure Blockchain tab, click on "Connect to Consortium" and select Azure Blockchain Service</div>
|
||||
<img src="https://raw.githubusercontent.com/Microsoft/vscode-azure-blockchain-ethereum/master/images/connectService.gif">
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div class="interactive">
|
||||
<div>
|
||||
<div class="arrow"></div>
|
||||
<h3>Create a Smart Contract and Project Folder</h3>
|
||||
</div>
|
||||
<div class="detail">
|
||||
To create a basic smart contract folder structure and contract.
|
||||
<ol>
|
||||
<li>
|
||||
<div>From the Command Palette click on "New Solidity Project"</div>
|
||||
<img src="https://raw.githubusercontent.com/Microsoft/vscode-azure-blockchain-ethereum/master/images/createNewProject.gif">
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div class="interactive">
|
||||
<div>
|
||||
<div class="arrow"></div>
|
||||
<h3>Interact with your Smart Contract</h3>
|
||||
</div>
|
||||
<div class="detail">
|
||||
To interact with your contract
|
||||
<ol>
|
||||
<li>
|
||||
<div>Coming soon!</div>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<h2>Learn more about our partners</h2>
|
||||
<div class="partners">
|
||||
<a href="https://www.ethereum.org/">
|
||||
<div class="specific-partner">
|
||||
<div><img class="small-image-logo" src="{{root}}/images/EthereumLogo.png"></div>
|
||||
<div>Ethereum Foundation</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://solidity.readthedocs.io/en/v0.5.5/">
|
||||
<div class="specific-partner">
|
||||
<div><img class="small-image-logo" src="{{root}}/images/SolidityLogo.png"></div>
|
||||
<div>Solidity plugin</div>
|
||||
</div>
|
||||
</a>
|
||||
<a href="https://truffleframework.com/docs/truffle/reference/truffle-commands">
|
||||
<div class="specific-partner">
|
||||
<div><img class="small-image-logo" src="{{root}}/images/TruffleLogo.png"></div>
|
||||
<div>Truffle Suite</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="sidebar">
|
||||
|
||||
<p class="showOnStartup">
|
||||
<input type="checkbox" id="showOnStartup" class="checkbox" checked="checked">
|
||||
<label class="caption" for="showOnStartup">Show this page on startup</label>
|
||||
</p>
|
||||
|
||||
<footer>
|
||||
<div>
|
||||
<h3>Quick Links</h3>
|
||||
<div>
|
||||
<a href="https://aka.ms/vscodebcextension">Marketplace </a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://aka.ms/vscodebcextensiongitrepo">Repository</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://aka.ms/vscodevcextensiongitissues">Issues</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://aka.ms/vscodebcextensionchangelog">Changelog</a>
|
||||
</div>
|
||||
Having trouble with the extension? -
|
||||
<a href="https://aka.ms/vscodebcextensionwiki">Browse the documentation</a> -
|
||||
<a href="https://aka.ms/vscodevcextensiongitissues">Report an issue</a>
|
||||
</div>
|
||||
<div id="resources">
|
||||
<h3>Resources</h3>
|
||||
<div>
|
||||
<a href="https://aka.ms/vscodebcextensionch9">Channel 9 video: Walkthrough of Azure Blockchain Development Kit Extension</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://aka.ms/vscodebcextensionwiki">Azure Blockchain Development Kit User Guide</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://docs.microsoft.com/azure/blockchain/service">Azure Blockchain Service Documentation</a>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
<div id="sidebar">
|
||||
<div>
|
||||
<h3>Quick Links</h3>
|
||||
<div>
|
||||
<a href="https://aka.ms/vscodebcextension">Marketplace </a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://aka.ms/vscodebcextensiongitrepo">Repository</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://aka.ms/vscodevcextensiongitissues">Issues</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://aka.ms/vscodebcextensionchangelog">Changelog</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="resources">
|
||||
<h3>Resources</h3>
|
||||
<div>
|
||||
<a href="https://aka.ms/vscodebcextensionch9">Channel 9 video: Walkthrough of Azure Blockchain Development Kit Extension</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://aka.ms/vscodebcextensionwiki">Azure Blockchain Development Kit User Guide</a>
|
||||
</div>
|
||||
<div>
|
||||
<a href="https://docs.microsoft.com/azure/blockchain/service">Azure Blockchain Service Documentation</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#" id="back-to-top">↑</a>
|
||||
<script type="text/javascript" src="{{root}}/resources/welcome/jquery-3.3.1.min.js"></script>
|
||||
<script type="text/javascript" src="{{root}}/resources/welcome/main.js"></script>
|
||||
</div>
|
||||
<a href="#" id="back-to-top">↑</a>
|
||||
<script type="text/javascript" src="{{root}}/resources/welcome/jquery-3.3.1.min.js"></script>
|
||||
<script type="text/javascript" src="{{root}}/resources/welcome/main.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -74,13 +74,12 @@ header p {
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
align-content: stretch;
|
||||
min-width: 620px;
|
||||
min-width: 660px;
|
||||
}
|
||||
|
||||
#main-content {
|
||||
max-width: 740px;
|
||||
/* float: left; */
|
||||
padding-right: 40px;
|
||||
margin-right: 40px;
|
||||
min-width: 400px;
|
||||
}
|
||||
|
||||
|
@ -243,9 +242,12 @@ header p {
|
|||
width: 40px;
|
||||
}
|
||||
|
||||
.showOnStartup {
|
||||
margin: 40px 0;
|
||||
}
|
||||
|
||||
footer {
|
||||
padding-top: 60px;
|
||||
padding-bottom: 40px;
|
||||
margin: 40px 0;
|
||||
text-align: center
|
||||
}
|
||||
|
||||
|
@ -260,7 +262,6 @@ footer {
|
|||
align-items: stretch;
|
||||
align-content: center;
|
||||
min-width: 400px;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.required-app {
|
||||
|
@ -269,13 +270,18 @@ footer {
|
|||
text-align: center;
|
||||
align-items: center;
|
||||
align-content: space-between;
|
||||
flex: 0 1 185px;
|
||||
flex: 1;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.required-app:not(:last-child) {
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
.required-app img {
|
||||
flex: 1;
|
||||
width: 60px;
|
||||
max-width: 60px;
|
||||
max-height: 60px;
|
||||
}
|
||||
|
||||
.required-app div {
|
||||
|
@ -347,11 +353,14 @@ footer {
|
|||
align-items: stretch;
|
||||
align-content: center;
|
||||
min-width: 400px;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.partners > a {
|
||||
flex: 0 1 185px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.partners > a:not(:last-child) {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.specific-partner {
|
||||
|
@ -363,6 +372,10 @@ footer {
|
|||
flex: 1;
|
||||
}
|
||||
|
||||
.specific-partner > div:last-child {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.specific-partner > div {
|
||||
text-align: center;
|
||||
}
|
||||
|
|
|
@ -36,14 +36,18 @@ function main() {
|
|||
});
|
||||
|
||||
$(document).ready(() => {
|
||||
vscode.postMessage({ command: 'documentready'});
|
||||
vscode.postMessage({ command: 'documentReady'});
|
||||
});
|
||||
|
||||
$('#showOnStartup').change(function() {
|
||||
vscode.postMessage({ command: 'toggleShowPage', value: this.checked});
|
||||
});
|
||||
|
||||
window.addEventListener('message', (event) => {
|
||||
const message = event.data; // The JSON data our extension sent
|
||||
|
||||
if (message.versions) {
|
||||
const versions = message.versions;
|
||||
if (message.command === 'versions') {
|
||||
const versions = message.value;
|
||||
if (Array.isArray(versions)) {
|
||||
versions.forEach((version) => {
|
||||
const element = $(`#${version.app}`);
|
||||
|
@ -53,5 +57,8 @@ function main() {
|
|||
});
|
||||
}
|
||||
}
|
||||
if (message.command === 'showOnStartup') {
|
||||
$('#showOnStartup').attr('checked', !!message.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,60 +1,73 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="{{root}}/resources/welcome/main.css">
|
||||
</head>
|
||||
<body class ="vscode-dark">
|
||||
<div id="content">
|
||||
<div id="main-content">
|
||||
<div class="required-block">
|
||||
<div>
|
||||
<h2>Required apps</h2>
|
||||
<br>This extension requires your development machine have the following tools already installed. These cannot be installed directly by the extension.
|
||||
If you do not have these tools already installed, the links below will take you to the download page.
|
||||
<ul>
|
||||
<li>Node JS</li>
|
||||
<li>Git</li>
|
||||
<li>Python</li>
|
||||
</ul>
|
||||
<p><a href="https://aka.ms/vscodebcextensionwiki">Click here</a> to learn more about this extension, and view the users guide </p>
|
||||
<div class="required">
|
||||
<div id="node" class="required-app disabled">
|
||||
<img src="{{root}}/images/NodeLogo.png">
|
||||
<div class="description">Required version: <span class="version">10.15.0</span></div>
|
||||
<a class="spinner" href="https://nodejs.org"><span>Install Node.js</span></a>
|
||||
</div>
|
||||
<div id="git" class="required-app disabled">
|
||||
<img src="{{root}}/images/GitLogo.png">
|
||||
<div class="description">Required version: <span class="version">2.10.0</span> or higher</div>
|
||||
<a class="spinner" href="https://git-scm.com/downloads"><span>Install Git</span></a>
|
||||
</div>
|
||||
<div id="python" class="required-app disabled">
|
||||
<img src="{{root}}/images/PythonLogo.png">
|
||||
<div class="description">Required version: <span class="version">2.7.15</span></div>
|
||||
<a class="spinner" href="https://www.python.org/downloads/release/python-2715/"><span>Install Python</span></a>
|
||||
</div>
|
||||
<p>At this time, while the extension is still in public-preview, you will also need to install the Truffle Suite of developer tools. Click the links below to install the Truffle tools directly from this extension</p>
|
||||
<div id="npm" class="required-app disabled">
|
||||
<img src="{{root}}/images/NpmLogo.png">
|
||||
<div class="description">Required version: <span class="version">6.4.1</span></div>
|
||||
<a class="spinner action" href="command:azureBlockchainService.required.installNpm"><span>Install NPM</span></a>
|
||||
</div>
|
||||
<div id="truffle" class="required-app disabled">
|
||||
<img src="{{root}}/images/TruffleLogo.svg">
|
||||
<div class="description">Required version: <span class="version">5.0.0</span></div>
|
||||
<a class="spinner action" href="command:azureBlockchainService.required.installTruffle"><span>Install Truffle Suite</span></a>
|
||||
</div>
|
||||
<div id="ganache" class="required-app disabled">
|
||||
<img src="{{root}}/images/GanacheLogo.png">
|
||||
<div class="description">Required version: <span class="version">6.0.0</span></div>
|
||||
<a class="spinner action" href="command:azureBlockchainService.required.installGanache"><span>Install Ganache CLI</span></a>
|
||||
</div>
|
||||
<head>
|
||||
<link rel="stylesheet" href="{{root}}/resources/welcome/main.css">
|
||||
</head>
|
||||
<body class="vscode-dark">
|
||||
<div id="content">
|
||||
<div id="main-content">
|
||||
<div class="required-block">
|
||||
<div>
|
||||
<h2>Required apps</h2>
|
||||
<br>
|
||||
This extension requires your development machine have the following tools already installed. These cannot be installed directly by the extension.
|
||||
If you do not have these tools already installed, the links below will take you to the download page
|
||||
<ul>
|
||||
<li>Node JS</li>
|
||||
<li>Git</li>
|
||||
<li>Python</li>
|
||||
</ul>
|
||||
<p>
|
||||
<a href="https://aka.ms/vscodebcextensionwiki">Click here</a> to learn more about this extension, and view the users guide
|
||||
</p>
|
||||
<div class="required">
|
||||
<div id="node" class="required-app disabled">
|
||||
<img src="{{root}}/images/NodeLogo.png">
|
||||
<div class="description">Required version: <span class="version">10.15.0</span></div>
|
||||
<a class="spinner" href="https://nodejs.org"><span>Install Node.js</span></a>
|
||||
</div>
|
||||
<div id="git" class="required-app disabled">
|
||||
<img src="{{root}}/images/GitLogo.png">
|
||||
<div class="description">Required version: <span class="version">2.10.0</span></div>
|
||||
<a class="spinner" href="https://git-scm.com/downloads"><span>Install Git</span></a>
|
||||
</div>
|
||||
<div id="python" class="required-app disabled">
|
||||
<img src="{{root}}/images/PythonLogo.png">
|
||||
<div class="description">Required version: <span class="version">2.7.15</span></div>
|
||||
<a class="spinner" href="https://www.python.org/downloads/release/python-2715/"><span>Install Python</span></a>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
At this time, while the extension is still in public-preview, you will also need to install the Truffle Suite of developer tools.
|
||||
Click the links below to install the Truffle tools directly from this extension
|
||||
</p>
|
||||
<div class="required">
|
||||
<div id="npm" class="required-app disabled">
|
||||
<img src="{{root}}/images/NpmLogo.png">
|
||||
<div class="description">Required version: <span class="version">6.4.1</span></div>
|
||||
<a class="spinner action" href="command:azureBlockchainService.required.installNpm"><span>Install NPM</span></a>
|
||||
</div>
|
||||
<div id="truffle" class="required-app disabled">
|
||||
<img src="{{root}}/images/TruffleLogo.svg">
|
||||
<div class="description">Required version: <span class="version">5.0.0</span></div>
|
||||
<a class="spinner action" href="command:azureBlockchainService.required.installTruffle"><span>Install Truffle Suite</span></a>
|
||||
</div>
|
||||
<div id="ganache" class="required-app disabled">
|
||||
<img src="{{root}}/images/GanacheLogo.png">
|
||||
<div class="description">Required version: <span class="version">6.0.0</span></div>
|
||||
<a class="spinner action" href="command:azureBlockchainService.required.installGanache"><span>Install Ganache CLI</span></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="showOnStartup">
|
||||
<input type="checkbox" id="showOnStartup" class="checkbox" checked="checked">
|
||||
<label class="caption" for="showOnStartup">Show this page on startup</label>
|
||||
</p>
|
||||
</div>
|
||||
<script type="text/javascript" src="{{root}}/resources/welcome/jquery-3.3.1.min.js"></script>
|
||||
<script type="text/javascript" src="{{root}}/resources/welcome/main.js"></script>
|
||||
</div>
|
||||
<script type="text/javascript" src="{{root}}/resources/welcome/jquery-3.3.1.min.js"></script>
|
||||
<script type="text/javascript" src="{{root}}/resources/welcome/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
|
|
@ -53,7 +53,7 @@ export class AzureBlockchainServiceClient extends AzureServiceClient {
|
|||
Output.outputLine(Constants.outputChannel.azureBlockchainServiceClient, err.message);
|
||||
}
|
||||
|
||||
env.openExternal(Uri.parse(`${Constants.azurePortalBasUri}/resource/${urlDetailsOfConsortium}`));
|
||||
env.openExternal(Uri.parse(`${Constants.azureResourceExplorer.portalBasUri}/resource/${urlDetailsOfConsortium}`));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ export class AzureBlockchainServiceClient extends AzureServiceClient {
|
|||
callback: (error: Error | null, result?: any) => void,
|
||||
): Promise<void> {
|
||||
// @ts-ignore
|
||||
return await this.pipeline(httpRequest, (err: ServiceError, response: IncomingMessage, responseBody: string) => {
|
||||
return this.pipeline(httpRequest, (err: ServiceError, response: IncomingMessage, responseBody: string) => {
|
||||
if (err) {
|
||||
window.showErrorMessage(err.message);
|
||||
return callback(err);
|
||||
|
|
|
@ -11,11 +11,6 @@ export namespace AzureBlockchain {
|
|||
await AzureBlockchain.addDataInClipboard(Constants.rpcEndpointAddress, rpcEndpointAddress);
|
||||
}
|
||||
|
||||
export async function copyAccessKey(consortiumNode: ConsortiumView): Promise<void> {
|
||||
const accessKey = await consortiumNode.getAccessKey();
|
||||
await AzureBlockchain.addDataInClipboard(Constants.accessKey, accessKey);
|
||||
}
|
||||
|
||||
export async function addDataInClipboard(typeOfData: string, data?: string | null) {
|
||||
if (data) {
|
||||
await env.clipboard.writeText(data);
|
||||
|
|
|
@ -1,37 +1,23 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import { ResourceManagementClient, SubscriptionClient, SubscriptionModels } from 'azure-arm-resource';
|
||||
import { commands, extensions, ProgressLocation, QuickPickItem, window } from 'vscode';
|
||||
import { ProgressLocation, QuickPickItem, window } from 'vscode';
|
||||
import { AzureBlockchainServiceClient, IAzureMemberDto, ICreateQuorumMember } from './ARMBlockchain';
|
||||
import { AzureAccount } from './azure-account.api';
|
||||
import { Constants } from './Constants';
|
||||
import { showInputBox, showQuickPick } from './helpers';
|
||||
import { AzureConsortium, LocationItem, Member, ResourceGroupItem, SubscriptionItem, TransactionNode } from './Models';
|
||||
import { getAzureRegions } from './Regions';
|
||||
import { AzureConsortium, Member, ResourceGroupItem, SubscriptionItem, TransactionNode } from './Models';
|
||||
import { ConsortiumItem } from './Models/ConsortiumItem';
|
||||
import { ResourceExplorerAndGenerator } from './ResourceExplorerAndGenerator';
|
||||
import { WestlakeInputValidator } from './validators/WestlakeInputValidator';
|
||||
|
||||
export class ConsortiumResourceExplorer {
|
||||
private readonly _accountApi: AzureAccount;
|
||||
|
||||
constructor() {
|
||||
this._accountApi = extensions.getExtension<AzureAccount>('ms-vscode.azure-account')!.exports;
|
||||
}
|
||||
|
||||
public async selectConsortium(childrenFilters?: string[]): Promise<AzureConsortium> {
|
||||
export class ConsortiumResourceExplorer extends ResourceExplorerAndGenerator {
|
||||
public async selectOrCreateConsortium(childrenFilters?: string[]): Promise<AzureConsortium> {
|
||||
await this.waitForLogin();
|
||||
|
||||
const subscriptionItem = await this.getOrSelectSubscriptionItem();
|
||||
const resourceGroupItem = await this.getOrSelectResourceGroup(subscriptionItem);
|
||||
return await this.getOrSelectConsortiumItem(subscriptionItem, resourceGroupItem, childrenFilters);
|
||||
}
|
||||
const resourceGroupItem = await this.getOrCreateResourceGroupItem(subscriptionItem);
|
||||
|
||||
public async createConsortium(): Promise<AzureConsortium> {
|
||||
await this.waitForLogin();
|
||||
|
||||
const subscriptionItem = await this.getOrSelectSubscriptionItem();
|
||||
const resourceGroupItem = await this.getOrCreateResourceGroup(subscriptionItem);
|
||||
return await this.createConsortiumItem(subscriptionItem, resourceGroupItem);
|
||||
return this.getOrCreateConsortiumItem(subscriptionItem, resourceGroupItem, childrenFilters);
|
||||
}
|
||||
|
||||
public async getAccessKeys(consortium: AzureConsortium): Promise<string[]> {
|
||||
|
@ -64,10 +50,10 @@ export class ConsortiumResourceExplorer {
|
|||
subscriptionItem.session.credentials,
|
||||
subscriptionItem.subscriptionId,
|
||||
resourceGroupItem.label,
|
||||
Constants.requestBaseUri,
|
||||
Constants.requestApiVersion,
|
||||
Constants.azureResourceExplorer.requestBaseUri,
|
||||
Constants.azureResourceExplorer.requestApiVersion,
|
||||
{
|
||||
acceptLanguage: Constants.requestAcceptLanguage,
|
||||
acceptLanguage: Constants.azureResourceExplorer.requestAcceptLanguage,
|
||||
filters: [],
|
||||
generateClientRequestId: true,
|
||||
longRunningOperationRetryTimeout: 30,
|
||||
|
@ -80,175 +66,82 @@ export class ConsortiumResourceExplorer {
|
|||
);
|
||||
}
|
||||
|
||||
private async getResourceClient(subscriptionItem: SubscriptionItem)
|
||||
: Promise<ResourceManagementClient.ResourceManagementClient> {
|
||||
return new ResourceManagementClient.ResourceManagementClient(
|
||||
subscriptionItem.session.credentials,
|
||||
subscriptionItem.subscriptionId,
|
||||
subscriptionItem.session.environment.resourceManagerEndpointUrl,
|
||||
);
|
||||
}
|
||||
|
||||
private async getOrSelectSubscriptionItem(): Promise<SubscriptionItem> {
|
||||
return showQuickPick(
|
||||
await this.loadSubscriptionItems(),
|
||||
{ placeHolder: Constants.placeholders.selectSubscription, ignoreFocusOut: true },
|
||||
);
|
||||
}
|
||||
|
||||
private async loadSubscriptionItems(): Promise<SubscriptionItem[]> {
|
||||
await this._accountApi.waitForFilters();
|
||||
|
||||
const subscriptionItems = this._accountApi.filters
|
||||
.map((filter) => new SubscriptionItem(
|
||||
filter.subscription.displayName || '',
|
||||
filter.subscription.subscriptionId || '',
|
||||
filter.session,
|
||||
));
|
||||
|
||||
if (subscriptionItems.length === 0) {
|
||||
throw new Error(Constants.errorMessageStrings.NoSubscriptionFoundClick);
|
||||
}
|
||||
|
||||
return subscriptionItems;
|
||||
}
|
||||
|
||||
private async getOrSelectResourceGroup(subscriptionItem: SubscriptionItem): Promise<ResourceGroupItem> {
|
||||
return showQuickPick(
|
||||
this.getResourceGroupItems(subscriptionItem),
|
||||
{ placeHolder: Constants.placeholders.selectResourceGroup, ignoreFocusOut: true },
|
||||
);
|
||||
}
|
||||
|
||||
private async getOrCreateResourceGroup(subscriptionItem: SubscriptionItem): Promise<ResourceGroupItem> {
|
||||
const createGroupItem: QuickPickItem = {
|
||||
label: '$(plus) Create Resource Group',
|
||||
};
|
||||
const items: QuickPickItem[] = [];
|
||||
items.push(createGroupItem);
|
||||
items.push(...await this.getResourceGroupItems(subscriptionItem));
|
||||
private async getOrCreateConsortiumItem(
|
||||
subscriptionItem: SubscriptionItem,
|
||||
resourceGroupItem: ResourceGroupItem,
|
||||
excludedItems?: string[],
|
||||
): Promise<AzureConsortium> {
|
||||
const pick = await showQuickPick(
|
||||
items,
|
||||
{ placeHolder: Constants.placeholders.selectResourceGroup, ignoreFocusOut: true },
|
||||
);
|
||||
|
||||
if (pick instanceof (ResourceGroupItem)) {
|
||||
return pick;
|
||||
} else {
|
||||
return this.createResourceGroup(subscriptionItem);
|
||||
}
|
||||
}
|
||||
|
||||
private async createResourceGroup(subscriptionItem: SubscriptionItem): Promise<ResourceGroupItem> {
|
||||
const resourceGroupName = await showInputBox({
|
||||
ignoreFocusOut: true,
|
||||
placeHolder: 'Resource Group Name',
|
||||
prompt: 'Provide a resource group name',
|
||||
validateInput: WestlakeInputValidator.validateNames,
|
||||
});
|
||||
|
||||
const locationItem = await showQuickPick(
|
||||
this.getLocationItems(subscriptionItem),
|
||||
{ placeHolder: 'Select a location to create your Resource Group in...', ignoreFocusOut: true },
|
||||
);
|
||||
|
||||
return window.withProgress({
|
||||
location: ProgressLocation.Notification,
|
||||
title: `Creating resource group '${resourceGroupName}'`,
|
||||
}, async () => {
|
||||
if (subscriptionItem.subscriptionId === undefined) {
|
||||
throw new Error(Constants.errorMessageStrings.NoSubscriptionFound);
|
||||
} else {
|
||||
const resourceManagementClient = await this.getResourceClient(subscriptionItem);
|
||||
const resourceGroup = await resourceManagementClient.resourceGroups.createOrUpdate(
|
||||
resourceGroupName,
|
||||
{ location: locationItem.description },
|
||||
);
|
||||
return new ResourceGroupItem(resourceGroup.name, resourceGroup.location);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async getResourceGroupItems(subscriptionItem: SubscriptionItem): Promise<ResourceGroupItem[]> {
|
||||
const resourceManagementClient = await this.getResourceClient(subscriptionItem);
|
||||
const resourceGroups = await resourceManagementClient.resourceGroups.list();
|
||||
return resourceGroups.map((resourceGroup) => new ResourceGroupItem(resourceGroup.name, resourceGroup.location));
|
||||
}
|
||||
|
||||
private async getLocationItems(subscriptionItem: SubscriptionItem): Promise<LocationItem[]> {
|
||||
const subscriptionClient = new SubscriptionClient.SubscriptionClient(
|
||||
subscriptionItem.session.credentials,
|
||||
subscriptionItem.session.environment.resourceManagerEndpointUrl,
|
||||
);
|
||||
|
||||
const locations = await subscriptionClient.subscriptions.listLocations(subscriptionItem.subscriptionId);
|
||||
return locations.map((location: SubscriptionModels.Location) => new LocationItem(location));
|
||||
}
|
||||
|
||||
private async getOrSelectConsortiumItem(
|
||||
subscriptionItem: SubscriptionItem,
|
||||
resourceGroupItem: ResourceGroupItem,
|
||||
childrenFilters?: string[])
|
||||
: Promise<AzureConsortium> {
|
||||
const consortiumItems = this.getNewConsortiumItems(subscriptionItem, resourceGroupItem, childrenFilters);
|
||||
|
||||
return showQuickPick(consortiumItems,
|
||||
this.getConsortiumItems(subscriptionItem, resourceGroupItem, excludedItems),
|
||||
{ placeHolder: Constants.placeholders.selectConsortium, ignoreFocusOut: true });
|
||||
|
||||
if (pick instanceof ConsortiumItem) {
|
||||
return this.getAzureConsortium(pick, subscriptionItem, resourceGroupItem);
|
||||
} else {
|
||||
return this.createAzureConsortium(subscriptionItem, resourceGroupItem);
|
||||
}
|
||||
}
|
||||
|
||||
private async getNewConsortiumItems(
|
||||
private async getConsortiumItems(
|
||||
subscriptionItem: SubscriptionItem,
|
||||
resourceGroupItem: ResourceGroupItem,
|
||||
childrenFilters?: string[])
|
||||
: Promise<AzureConsortium[]> {
|
||||
const consortiumItems = await this.loadConsortiumItems(subscriptionItem, resourceGroupItem);
|
||||
excludedItems?: string[],
|
||||
): Promise<QuickPickItem[]> {
|
||||
const items: QuickPickItem[] = [];
|
||||
const createConsortiumItem: QuickPickItem = { label: '$(plus) Create Consortium' };
|
||||
const consortiumItems = await this.loadConsortiumItems(subscriptionItem, resourceGroupItem, excludedItems);
|
||||
|
||||
if (childrenFilters) {
|
||||
return consortiumItems.filter((item) => !childrenFilters.includes(item.label));
|
||||
}
|
||||
items.push(createConsortiumItem, ...consortiumItems);
|
||||
|
||||
return consortiumItems;
|
||||
return items;
|
||||
}
|
||||
|
||||
private async loadConsortiumItems(subscriptionItem: SubscriptionItem, resourceGroupItem: ResourceGroupItem)
|
||||
: Promise<AzureConsortium[]> {
|
||||
private async loadConsortiumItems(
|
||||
subscriptionItem: SubscriptionItem,
|
||||
resourceGroupItem: ResourceGroupItem,
|
||||
excludedItems: string[] = [],
|
||||
): Promise<ConsortiumItem[]> {
|
||||
const client = await this.getClient(subscriptionItem, resourceGroupItem);
|
||||
|
||||
const members: IAzureMemberDto[] = await client.memberResource.getListMember();
|
||||
if (!members.length) {
|
||||
throw new Error(`No members found in resource group ${resourceGroupItem.label}.`);
|
||||
}
|
||||
|
||||
const consortiumItems = members
|
||||
.map((member) => new AzureConsortium(
|
||||
return members
|
||||
.map((member) => new ConsortiumItem(
|
||||
member.properties.consortium,
|
||||
subscriptionItem.subscriptionId,
|
||||
resourceGroupItem.label,
|
||||
member.name,
|
||||
member.properties.dns,
|
||||
))
|
||||
.filter((item) => !excludedItems.includes(item.label))
|
||||
.sort((a, b) => a.label.localeCompare(b.label));
|
||||
|
||||
for (const consortium of consortiumItems) {
|
||||
const filterMembers = members.filter((x: IAzureMemberDto) => x.properties.consortium === consortium.label);
|
||||
|
||||
for (const member of filterMembers) {
|
||||
const transactionNodes = await client.transactionNodeResource.getListTransactionNode(member.name);
|
||||
const memberItem = new Member(member.name);
|
||||
|
||||
await consortium.setChildren([
|
||||
memberItem,
|
||||
...transactionNodes.map((transactionNode) => {
|
||||
return new TransactionNode(transactionNode.name, transactionNode.properties.dns);
|
||||
}),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return consortiumItems;
|
||||
}
|
||||
|
||||
private async createConsortiumItem(subscriptionItem: SubscriptionItem, resourceGroupItem: ResourceGroupItem)
|
||||
private async getAzureConsortium(
|
||||
consortiumItems: ConsortiumItem,
|
||||
subscriptionItem: SubscriptionItem,
|
||||
resourceGroupItem: ResourceGroupItem,
|
||||
): Promise<AzureConsortium> {
|
||||
const client = await this.getClient(subscriptionItem, resourceGroupItem);
|
||||
const transactionNodes = await client.transactionNodeResource.getListTransactionNode(consortiumItems.memberName);
|
||||
const memberItem = new Member(consortiumItems.memberName);
|
||||
|
||||
const azureConsortium = new AzureConsortium(
|
||||
consortiumItems.consortiumName,
|
||||
consortiumItems.subscriptionId,
|
||||
consortiumItems.resourcesGroup,
|
||||
consortiumItems.memberName,
|
||||
consortiumItems.url,
|
||||
);
|
||||
await azureConsortium.setChildren([
|
||||
memberItem,
|
||||
...transactionNodes.map((transactionNode) => {
|
||||
return new TransactionNode(transactionNode.name, transactionNode.properties.dns);
|
||||
}),
|
||||
]);
|
||||
|
||||
return azureConsortium;
|
||||
}
|
||||
|
||||
private async createAzureConsortium(subscriptionItem: SubscriptionItem, resourceGroupItem: ResourceGroupItem)
|
||||
: Promise<AzureConsortium> {
|
||||
const client = await this.getClient(subscriptionItem, resourceGroupItem);
|
||||
|
||||
|
@ -265,7 +158,7 @@ export class ConsortiumResourceExplorer {
|
|||
});
|
||||
|
||||
const protocol = await showQuickPick(
|
||||
[{label: 'Quorum'}],
|
||||
[{ label: 'Quorum' }],
|
||||
{
|
||||
ignoreFocusOut: true,
|
||||
placeHolder: Constants.paletteWestlakeLabels.selectConsortiumProtocol,
|
||||
|
@ -287,7 +180,7 @@ export class ConsortiumResourceExplorer {
|
|||
});
|
||||
|
||||
const region = await showQuickPick(
|
||||
getAzureRegions(),
|
||||
this.getLocationItems(subscriptionItem),
|
||||
{ placeHolder: Constants.paletteWestlakeLabels.selectConsortiumRegion, ignoreFocusOut: true },
|
||||
);
|
||||
|
||||
|
@ -296,24 +189,16 @@ export class ConsortiumResourceExplorer {
|
|||
consortiumName,
|
||||
consortiumPassword,
|
||||
protocol: protocol.label,
|
||||
region: region.key,
|
||||
region: region.description,
|
||||
};
|
||||
|
||||
await client.consortiumResource.createConsortium(memberName, bodyParams);
|
||||
return window.withProgress({
|
||||
location: ProgressLocation.Window,
|
||||
title: Constants.statusBarMessages.creatingConsortium,
|
||||
}, async () => {
|
||||
await client.consortiumResource.createConsortium(memberName, bodyParams);
|
||||
|
||||
return new AzureConsortium(consortiumName, subscriptionItem.subscriptionId, resourceGroupItem.label, memberName);
|
||||
}
|
||||
|
||||
private async waitForLogin(): Promise<boolean> {
|
||||
let result = await this._accountApi.waitForLogin();
|
||||
if (!result) {
|
||||
await commands.executeCommand('azure-account.askForLogin');
|
||||
result = await this._accountApi.waitForLogin();
|
||||
if (!result) {
|
||||
throw new Error(Constants.errorMessageStrings.WaitForLogin);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return new AzureConsortium(consortiumName, subscriptionItem.subscriptionId, resourceGroupItem.label, memberName);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,9 @@ import { ExtensionContext } from 'vscode';
|
|||
export class Constants {
|
||||
public static extensionContext: ExtensionContext;
|
||||
public static temporaryDirectory = '';
|
||||
public static logicAppOutputDir = 'generatedLogicApp';
|
||||
public static flowAppOutputDir = 'generatedFlowApp';
|
||||
public static azureFunctionOutputDir = 'generatedAzureFunction';
|
||||
|
||||
public static extensionId = '';
|
||||
public static extensionVersion = '';
|
||||
|
@ -23,7 +26,8 @@ export class Constants {
|
|||
telemetryClient: 'Telemetry Client',
|
||||
};
|
||||
|
||||
public static isWelcomePageShown = 'isWelcomePageShown';
|
||||
public static showOnStartupWelcomePage = 'showOnStartupWelcomePage';
|
||||
public static showOnStartupRequirementsPage = 'showOnStartupRequirementsPage';
|
||||
|
||||
public static defaultTruffleBox = 'Azure-Samples/Blockchain-Ethereum-Template';
|
||||
public static tempPath = 'tempPath';
|
||||
|
@ -45,6 +49,11 @@ export class Constants {
|
|||
truffle: '5.0.0',
|
||||
};
|
||||
|
||||
public static webViewPages = {
|
||||
requirements: 'Azure Blockchain Development Kit - Preview',
|
||||
welcome: 'Welcome to Azure Blockchain',
|
||||
};
|
||||
|
||||
public static contractExtension = {
|
||||
json: '.json',
|
||||
sol: '.sol',
|
||||
|
@ -82,8 +91,6 @@ export class Constants {
|
|||
gasPrice: 100000000000,
|
||||
};
|
||||
|
||||
public static telemetry = 'Telemetry';
|
||||
|
||||
public static networkName = {
|
||||
azure: 'Azure Blockchain Service',
|
||||
local: 'Local Network',
|
||||
|
@ -110,6 +117,7 @@ export class Constants {
|
|||
enterTruffleBoxName: 'Enter pre-built Truffle project',
|
||||
enterWestlakeUrl: 'Enter Westlake url',
|
||||
enterYourGanacheUrl: 'Enter your Ganache url',
|
||||
provideResourceGroupName: 'Provide a resource group name',
|
||||
selectConsortiumProtocol: 'Select protocol',
|
||||
selectConsortiumRegion: 'Select region',
|
||||
selectResourceGroup: 'Select resource group',
|
||||
|
@ -138,11 +146,13 @@ export class Constants {
|
|||
deployedUrlStructure: 'host:port',
|
||||
generateMnemonic: 'Generate mnemonic',
|
||||
pasteMnemonic: 'Paste mnemonic',
|
||||
resourceGroupName: 'Resource Group Name',
|
||||
selectConsortium: 'Select consortium',
|
||||
selectDeployDestination: 'Select deploy destination',
|
||||
selectLedgerEventsDestination: 'Select ledger events destination',
|
||||
selectNewProjectPath: 'Select new project path',
|
||||
selectResourceGroup: 'Select a resource group to select or create your consortium in...',
|
||||
selectResourceGroup: 'Select a resource group',
|
||||
selectRgLocation: 'Select a location to create your Resource Group in...',
|
||||
selectSubscription: 'Select subscription',
|
||||
selectTypeOfMnemonic: 'Select type of mnemonic',
|
||||
selectTypeOfSolidityProject: 'Select type of solidity project',
|
||||
|
@ -170,22 +180,6 @@ export class Constants {
|
|||
runningCommand: 'Running command',
|
||||
};
|
||||
|
||||
public static mnemonicMessages = {
|
||||
invalidStorageTypeSelected: 'Invalid storage type selected',
|
||||
whereStored: 'Where are your mnemonics stored?',
|
||||
};
|
||||
|
||||
public static mnemonicTypeQuickPick = {
|
||||
text: {
|
||||
local: 'In local file',
|
||||
truffle: 'In truffle-config',
|
||||
},
|
||||
types: {
|
||||
local: 'local',
|
||||
truffle: 'truffle',
|
||||
},
|
||||
};
|
||||
|
||||
public static typeOfSolidityProject = {
|
||||
action: {
|
||||
emptyProject: 'createEmptyProject',
|
||||
|
@ -210,10 +204,15 @@ export class Constants {
|
|||
},
|
||||
};
|
||||
|
||||
public static requestApiVersion = '2018-06-01-preview';
|
||||
public static requestAcceptLanguage = 'en-US';
|
||||
public static requestBaseUri = 'https://management.azure.com';
|
||||
public static azurePortalBasUri = 'https://portal.azure.com/#@microsoft.onmicrosoft.com';
|
||||
public static statusBarMessages = {
|
||||
buildingContracts: 'Building contracts',
|
||||
checkingRequirementDependencies: 'Checking requirement dependencies version',
|
||||
creatingConsortium: 'Creating new consortium',
|
||||
creatingProject: 'Creating new project',
|
||||
deployingContracts: (destination: string) => {
|
||||
return `Deploying contracts to '${destination}'`;
|
||||
},
|
||||
};
|
||||
|
||||
public static welcomePagePath = '';
|
||||
public static requirementsPagePath = '';
|
||||
|
@ -221,11 +220,6 @@ export class Constants {
|
|||
|
||||
public static dataCopied = ' copied to clipboard';
|
||||
public static rpcEndpointAddress = 'RPCEndpointAddress';
|
||||
public static accessKey = 'AccessKey';
|
||||
|
||||
public static folderStrings = {
|
||||
folderNotSelected: 'Folder not selected',
|
||||
};
|
||||
|
||||
public static ganacheCommandStrings = {
|
||||
serverAlreadyRunning: 'Ganache server already running',
|
||||
|
@ -249,6 +243,7 @@ export class Constants {
|
|||
public static errorMessageStrings = {
|
||||
ActionAborted: 'Action aborted',
|
||||
GitIsNotInstalled: 'Git is not installed',
|
||||
NewProjectCreationFailed: 'Command createProject has failed.',
|
||||
NoSubscriptionFound: 'No subscription found.',
|
||||
NoSubscriptionFoundClick: 'No subscription found, click an Azure account ' +
|
||||
'at the bottom left corner and choose Select All',
|
||||
|
@ -263,10 +258,32 @@ export class Constants {
|
|||
newProjectCreationFinished: 'New project was created successfully',
|
||||
newProjectCreationStarted: 'New project creation is started',
|
||||
seeDetailsRequirementsPage: 'Please see details on the Requirements Page',
|
||||
seeDetailsWelcomePage: 'Please see details on Welcome Page',
|
||||
};
|
||||
|
||||
public static microservicesWorkflows = {
|
||||
Data: 'Data',
|
||||
Messaging: 'Messaging',
|
||||
Reporting: 'Reporting',
|
||||
Service: 'Service',
|
||||
};
|
||||
|
||||
public static logicApp = {
|
||||
AzureFunction: 'Azure Function',
|
||||
FlowApp: 'Flow App',
|
||||
LogicApp: 'Logic App',
|
||||
};
|
||||
|
||||
public static gitCommand = 'git';
|
||||
public static truffleCommand = 'truffle';
|
||||
|
||||
public static azureResourceExplorer = {
|
||||
portalBasUri: 'https://portal.azure.com/#@microsoft.onmicrosoft.com',
|
||||
providerName: 'Microsoft.Blockchain',
|
||||
requestAcceptLanguage: 'en-US',
|
||||
requestApiVersion: '2018-06-01-preview',
|
||||
requestBaseUri: 'https://management.azure.com',
|
||||
resourceType: 'blockchainMembers',
|
||||
};
|
||||
|
||||
public static initialize(context: ExtensionContext) {
|
||||
this.extensionContext = context;
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
import './Nethereum.Generators.DuoCode';
|
||||
|
||||
function buildConstructor(item: any): Nethereum.Generators.Model.ConstructorABI {
|
||||
var constructorItem = new Nethereum.Generators.Model.ConstructorABI();
|
||||
const constructorItem = new Nethereum.Generators.Model.ConstructorABI();
|
||||
constructorItem.set_InputParameters(buildFunctionParameters(item.inputs));
|
||||
return constructorItem;
|
||||
}
|
||||
|
||||
function buildFunction(item: any): Nethereum.Generators.Model.FunctionABI {
|
||||
var functionItem = new Nethereum.Generators.Model.FunctionABI(item.name, item.constant, false);
|
||||
const functionItem = new Nethereum.Generators.Model.FunctionABI(item.name, item.constant, false);
|
||||
functionItem.set_InputParameters(buildFunctionParameters(item.inputs));
|
||||
functionItem.set_OutputParameters(buildFunctionParameters(item.outputs));
|
||||
return functionItem;
|
||||
}
|
||||
|
||||
function buildEvent(item: any): Nethereum.Generators.Model.EventABI {
|
||||
var eventItem = new Nethereum.Generators.Model.EventABI (item.name);
|
||||
const eventItem = new Nethereum.Generators.Model.EventABI (item.name);
|
||||
eventItem.set_InputParameters(buildEventParameters(item.inputs));
|
||||
return eventItem;
|
||||
}
|
||||
|
||||
function buildFunctionParameters(items: any): Nethereum.Generators.Model.ParameterABI[] {
|
||||
var parameterOrder = 0;
|
||||
var parameters = [];
|
||||
for (var i = 0, len = items.length; i < len; i++) {
|
||||
let parameterOrder = 0;
|
||||
const parameters = [];
|
||||
for (let i = 0, len = items.length; i < len; i++) {
|
||||
parameterOrder = parameterOrder + 1;
|
||||
var parameter = new Nethereum.Generators.Model.ParameterABI
|
||||
const parameter = new Nethereum.Generators.Model.ParameterABI
|
||||
.ctor$1(items[i].type, items[i].name, parameterOrder);
|
||||
parameters.push(parameter);
|
||||
}
|
||||
|
@ -32,11 +32,11 @@ function buildFunctionParameters(items: any): Nethereum.Generators.Model.Paramet
|
|||
}
|
||||
|
||||
function buildEventParameters(items: any): Nethereum.Generators.Model.ParameterABI[] {
|
||||
var parameterOrder = 0;
|
||||
var parameters = [];
|
||||
for (var i = 0, len = items.length; i < len; i++) {
|
||||
let parameterOrder = 0;
|
||||
const parameters = [];
|
||||
for (let i = 0, len = items.length; i < len; i++) {
|
||||
parameterOrder = parameterOrder + 1;
|
||||
var parameter = new Nethereum.Generators.Model.ParameterABI
|
||||
const parameter = new Nethereum.Generators.Model.ParameterABI
|
||||
.ctor$1(items[i].type, items[i].name, parameterOrder);
|
||||
parameter.set_Indexed(items[i].indexed);
|
||||
parameters.push(parameter);
|
||||
|
@ -46,25 +46,25 @@ function buildEventParameters(items: any): Nethereum.Generators.Model.ParameterA
|
|||
|
||||
export function buildContract(abiStr: string): Nethereum.Generators.Model.ContractABI {
|
||||
const abi = JSON.parse(abiStr);
|
||||
let functions = [];
|
||||
let events = [];
|
||||
const functions = [];
|
||||
const events = [];
|
||||
let constructor = new Nethereum.Generators.Model.ConstructorABI();
|
||||
|
||||
for (var i = 0, len = abi.length; i < len; i++) {
|
||||
if (abi[i].type === "function") {
|
||||
for (let i = 0, len = abi.length; i < len; i++) {
|
||||
if (abi[i].type === 'function') {
|
||||
functions.push(buildFunction(abi[i]));
|
||||
}
|
||||
|
||||
if (abi[i].type === "event") {
|
||||
if (abi[i].type === 'event') {
|
||||
events.push(buildEvent(abi[i]));
|
||||
}
|
||||
|
||||
if (abi[i].type === "constructor") {
|
||||
if (abi[i].type === 'constructor') {
|
||||
constructor = buildConstructor(abi[i]);
|
||||
}
|
||||
}
|
||||
|
||||
let contract = new Nethereum.Generators.Model.ContractABI();
|
||||
const contract = new Nethereum.Generators.Model.ContractABI();
|
||||
contract.set_Constructor(constructor);
|
||||
contract.set_Functions(functions);
|
||||
contract.set_Events(events);
|
||||
|
|
|
@ -1,61 +1,43 @@
|
|||
import { ResourceManagementClient, ResourceModels } from 'azure-arm-resource';
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import { mkdirp, readdir, readJson, writeFile } from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import { commands, extensions, QuickPickItem, Uri, window } from 'vscode';
|
||||
import { AzureAccount } from '../azure-account.api';
|
||||
import { QuickPickItem, Uri, window } from 'vscode';
|
||||
import { Constants } from '../Constants';
|
||||
import { getWorkspaceRoot } from '../helpers';
|
||||
import { showInputBox, showQuickPick } from '../helpers/userInteraction';
|
||||
import { ResourceGroupItem, SubscriptionItem } from '../Models';
|
||||
import { Output } from '../Output';
|
||||
import { ResourceExplorerAndGenerator } from '../ResourceExplorerAndGenerator';
|
||||
import { buildContract } from './AbiDeserialiser';
|
||||
import './Nethereum.Generators.DuoCode';
|
||||
|
||||
export class LogicAppGenerator {
|
||||
private readonly _accountApi: AzureAccount;
|
||||
|
||||
constructor() {
|
||||
this._accountApi = extensions.getExtension<AzureAccount>('ms-vscode.azure-account')!.exports;
|
||||
}
|
||||
|
||||
export class LogicAppGenerator extends ResourceExplorerAndGenerator {
|
||||
public async generateMicroservicesWorkflows(filePath: Uri | undefined): Promise<void> {
|
||||
return this.generateWorkflows('Service', filePath);
|
||||
return this.generateWorkflows(Constants.microservicesWorkflows.Service, filePath);
|
||||
}
|
||||
|
||||
public async generateDataPublishingWorkflows(filePath: Uri | undefined): Promise<void> {
|
||||
return this.generateWorkflows('Data', filePath);
|
||||
return this.generateWorkflows(Constants.microservicesWorkflows.Data, filePath);
|
||||
}
|
||||
|
||||
public async generateEventPublishingWorkflows(filePath: Uri | undefined): Promise<void> {
|
||||
return this.generateWorkflows('Messaging', filePath);
|
||||
return this.generateWorkflows(Constants.microservicesWorkflows.Messaging, filePath);
|
||||
}
|
||||
|
||||
public async generateReportPublishingWorkflows(filePath: Uri | undefined): Promise<void> {
|
||||
return this.generateWorkflows('Reporting', filePath);
|
||||
return this.generateWorkflows(Constants.microservicesWorkflows.Reporting, filePath);
|
||||
}
|
||||
|
||||
private async generateWorkflows(workflowType: string, filePath: Uri | undefined): Promise<void> {
|
||||
const workspaceDir: Uri = Uri.parse(getWorkspaceRoot());
|
||||
const dirPath: string = workspaceDir.fsPath + '/build/contracts/';
|
||||
const dirPath: string = path.join(getWorkspaceRoot(), 'build/contracts');
|
||||
|
||||
if (filePath) {
|
||||
const fileName = path.basename(filePath.fsPath);
|
||||
const contractName = fileName.Remove(fileName.length - 4);
|
||||
const compiledContractPath = dirPath + contractName + '.json';
|
||||
let picks: QuickPickItem[];
|
||||
|
||||
if (workflowType === 'Service') {
|
||||
picks = [
|
||||
{ label: 'Logic App' },
|
||||
{ label: 'Flow App' },
|
||||
{ label: 'Azure Function' },
|
||||
];
|
||||
} else {
|
||||
picks = [
|
||||
{ label: 'Logic App' },
|
||||
{ label: 'Flow App' },
|
||||
];
|
||||
}
|
||||
|
||||
const compiledContractPath = path.join(dirPath, `${contractName}.json`);
|
||||
const picks = this.getLogicAppItems(workflowType);
|
||||
const serviceTypeSelection: string = (await showQuickPick(picks, { })).label;
|
||||
const serviceType: int = this.getServiceTypeFromString(serviceTypeSelection);
|
||||
const contractAddress: string = await showInputBox({ value: 'contract address' });
|
||||
|
@ -64,7 +46,6 @@ export class LogicAppGenerator {
|
|||
async (err2: Error, contents: any) => await this.handleContractJsonFile(
|
||||
err2,
|
||||
contents,
|
||||
dirPath,
|
||||
contractAddress,
|
||||
subscriptionItem,
|
||||
resourceGroupItem,
|
||||
|
@ -83,20 +64,7 @@ export class LogicAppGenerator {
|
|||
return;
|
||||
}
|
||||
|
||||
let picks: QuickPickItem[];
|
||||
if (workflowType === 'Service') {
|
||||
picks = [
|
||||
{ label: 'Logic App' },
|
||||
{ label: 'Flow App' },
|
||||
{ label: 'Azure Function' },
|
||||
];
|
||||
} else {
|
||||
picks = [
|
||||
{ label: 'Logic App' },
|
||||
{ label: 'Flow App' },
|
||||
];
|
||||
}
|
||||
|
||||
const picks = this.getLogicAppItems(workflowType);
|
||||
const serviceTypeSelection: string = (await showQuickPick(picks, { })).label;
|
||||
const serviceType: int = this.getServiceTypeFromString(serviceTypeSelection);
|
||||
const contractAddress: string = await showInputBox({ value: 'contract address' });
|
||||
|
@ -106,7 +74,6 @@ export class LogicAppGenerator {
|
|||
async (err2: Error, contents: any) => await this.handleContractJsonFile(
|
||||
err2,
|
||||
contents,
|
||||
dirPath,
|
||||
contractAddress,
|
||||
subscriptionItem,
|
||||
resourceGroupItem,
|
||||
|
@ -118,12 +85,27 @@ export class LogicAppGenerator {
|
|||
window.showInformationMessage('Generated the logic app!');
|
||||
}
|
||||
|
||||
private getLogicAppItems(workflowType: string): QuickPickItem[] {
|
||||
if (workflowType === Constants.microservicesWorkflows.Service) {
|
||||
return [
|
||||
{ label: Constants.logicApp.LogicApp },
|
||||
{ label: Constants.logicApp.FlowApp },
|
||||
{ label: Constants.logicApp.AzureFunction },
|
||||
];
|
||||
} else {
|
||||
return [
|
||||
{ label: Constants.logicApp.LogicApp },
|
||||
{ label: Constants.logicApp.FlowApp },
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
private getServiceTypeFromString(serviceTypeSelection: string): int {
|
||||
if (serviceTypeSelection === 'Logic App') {
|
||||
if (serviceTypeSelection === Constants.logicApp.LogicApp) {
|
||||
return 1;
|
||||
} else if (serviceTypeSelection === 'Flow App') {
|
||||
} else if (serviceTypeSelection === Constants.logicApp.FlowApp) {
|
||||
return 0;
|
||||
} else if (serviceTypeSelection === 'Azure Function') {
|
||||
} else if (serviceTypeSelection === Constants.logicApp.AzureFunction) {
|
||||
return 2;
|
||||
} else {
|
||||
throw new Error('Service type string not valid');
|
||||
|
@ -133,7 +115,6 @@ export class LogicAppGenerator {
|
|||
private async handleContractJsonFile(
|
||||
err: Error,
|
||||
contents: any,
|
||||
dirPath: string,
|
||||
contractAddress: string,
|
||||
subscriptionItem: SubscriptionItem,
|
||||
resourceGroupItem: ResourceGroupItem,
|
||||
|
@ -144,7 +125,7 @@ export class LogicAppGenerator {
|
|||
return;
|
||||
}
|
||||
await this.createLogicAppFromAbi(contents,
|
||||
dirPath,
|
||||
this.getOutputDir(serviceType),
|
||||
contractAddress,
|
||||
subscriptionItem,
|
||||
resourceGroupItem.description,
|
||||
|
@ -162,13 +143,13 @@ export class LogicAppGenerator {
|
|||
serviceType: int) {
|
||||
|
||||
let generator;
|
||||
if (workflowType === 'Service') {
|
||||
if (workflowType === Constants.microservicesWorkflows.Service) {
|
||||
generator = new Nethereum.Generators.ServiceWorkflow.ServiceWorkflowProjectGenerator(
|
||||
buildContract(JSON.stringify(contract.abi)),
|
||||
contract.contractName,
|
||||
contract.bytecode,
|
||||
contract.contractName,
|
||||
contract.contractName + '.Service',
|
||||
contract.contractName + `.${workflowType}`,
|
||||
dirPath,
|
||||
'/',
|
||||
serviceType,
|
||||
|
@ -179,13 +160,13 @@ export class LogicAppGenerator {
|
|||
location,
|
||||
'',
|
||||
);
|
||||
} else if (workflowType === 'Data') {
|
||||
} else if (workflowType === Constants.microservicesWorkflows.Data) {
|
||||
generator = new Nethereum.Generators.DataWorkflow.DataWorkflowProjectGenerator(
|
||||
buildContract(JSON.stringify(contract.abi)),
|
||||
contract.contractName,
|
||||
contract.bytecode,
|
||||
contract.contractName,
|
||||
contract.contractName + '.Data',
|
||||
contract.contractName + `.${workflowType}`,
|
||||
dirPath,
|
||||
'/',
|
||||
serviceType,
|
||||
|
@ -195,7 +176,7 @@ export class LogicAppGenerator {
|
|||
location,
|
||||
JSON.stringify(contract.abi),
|
||||
);
|
||||
} else if (workflowType === 'Messaging') {
|
||||
} else if (workflowType === Constants.microservicesWorkflows.Messaging) {
|
||||
const topicName: string = await showInputBox({ value: 'topic name' });
|
||||
const picks: QuickPickItem[] = [
|
||||
{ label: 'Service Bus' },
|
||||
|
@ -208,7 +189,7 @@ export class LogicAppGenerator {
|
|||
contract.contractName,
|
||||
contract.bytecode,
|
||||
contract.contractName,
|
||||
contract.contractName + '.Messaging',
|
||||
contract.contractName + `.${workflowType}`,
|
||||
dirPath,
|
||||
'/',
|
||||
serviceType,
|
||||
|
@ -220,13 +201,13 @@ export class LogicAppGenerator {
|
|||
topicName,
|
||||
this.getMessagingType(messagingType),
|
||||
);
|
||||
} else if (workflowType === 'Reporting') {
|
||||
} else if (workflowType === Constants.microservicesWorkflows.Reporting) {
|
||||
generator = new Nethereum.Generators.ReportingWorkflow.ReportingWorkflowProjectGenerator(
|
||||
buildContract(JSON.stringify(contract.abi)),
|
||||
contract.contractName,
|
||||
contract.bytecode,
|
||||
contract.contractName,
|
||||
contract.contractName + '.Reporting',
|
||||
contract.contractName + `.${workflowType}`,
|
||||
dirPath,
|
||||
'/',
|
||||
serviceType,
|
||||
|
@ -268,65 +249,25 @@ export class LogicAppGenerator {
|
|||
});
|
||||
}
|
||||
|
||||
private getOutputDir(serviceType: int): string {
|
||||
switch (serviceType) {
|
||||
case 0:
|
||||
return path.join(getWorkspaceRoot(), Constants.flowAppOutputDir);
|
||||
case 1:
|
||||
return path.join(getWorkspaceRoot(), Constants.logicAppOutputDir);
|
||||
case 2:
|
||||
return path.join(getWorkspaceRoot(), Constants.azureFunctionOutputDir);
|
||||
default:
|
||||
throw new Error('Invalid service type.');
|
||||
}
|
||||
}
|
||||
|
||||
private async selectSubscriptionAndResourceGroup(): Promise<[SubscriptionItem, ResourceGroupItem]> {
|
||||
await this.waitForLogin();
|
||||
|
||||
const subscriptionItem = await this.getOrSelectSubscriptionItem();
|
||||
const resourceGroupItem = await this.getOrCreateResourceGroup(subscriptionItem);
|
||||
const resourceGroupItem = await this.getOrCreateResourceGroupItem(subscriptionItem);
|
||||
|
||||
return [subscriptionItem, resourceGroupItem];
|
||||
}
|
||||
|
||||
private async getOrSelectSubscriptionItem(): Promise<SubscriptionItem> {
|
||||
return await showQuickPick(
|
||||
await this.loadSubscriptionItems(),
|
||||
{ placeHolder: Constants.placeholders.selectSubscription, ignoreFocusOut: true },
|
||||
);
|
||||
}
|
||||
|
||||
private async loadSubscriptionItems(): Promise<SubscriptionItem[]> {
|
||||
await this._accountApi.waitForFilters();
|
||||
|
||||
const subscriptionItems = this._accountApi.filters
|
||||
.map((filter: any) => new SubscriptionItem(filter.subscription.displayName,
|
||||
filter.subscription.subscriptionId, filter.session));
|
||||
|
||||
if (subscriptionItems.length === 0) {
|
||||
throw new Error('No subscription found, click an Azure account at the \
|
||||
bottom left corner and choose Select All.');
|
||||
}
|
||||
|
||||
return subscriptionItems;
|
||||
}
|
||||
|
||||
private async getOrCreateResourceGroup(subscriptionItem: SubscriptionItem): Promise<ResourceGroupItem> {
|
||||
return await showQuickPick(
|
||||
this.getResourceGroupItems(subscriptionItem),
|
||||
{ placeHolder: Constants.placeholders.selectResourceGroup, ignoreFocusOut: true },
|
||||
);
|
||||
}
|
||||
|
||||
private async getResourceGroupItems(subscriptionItem: SubscriptionItem): Promise<ResourceGroupItem[]> {
|
||||
// @ts-ignore
|
||||
const resourceManagementClient = new ResourceManagementClient(
|
||||
subscriptionItem.session.credentials,
|
||||
subscriptionItem.subscriptionId,
|
||||
subscriptionItem.session.environment.resourceManagerEndpointUrl,
|
||||
);
|
||||
const resourceGroups = await resourceManagementClient.resourceGroups.list();
|
||||
return resourceGroups.map((resourceGroup: ResourceModels.ResourceGroup) =>
|
||||
new ResourceGroupItem(resourceGroup.name, resourceGroup.location));
|
||||
}
|
||||
private async waitForLogin(): Promise<boolean> {
|
||||
let result = await this._accountApi.waitForLogin();
|
||||
if (!result) {
|
||||
await commands.executeCommand('azure-account.askForLogin');
|
||||
result = await this._accountApi.waitForLogin();
|
||||
if (!result) {
|
||||
throw new Error(Constants.errorMessageStrings.WaitForLogin);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,13 +61,9 @@ export class AzureConsortium extends ProtectedConsortium {
|
|||
url.port = `${Constants.defaultAzureBSPort}`;
|
||||
}
|
||||
|
||||
return url.origin;
|
||||
}
|
||||
|
||||
public async getAccessKey(): Promise<string> {
|
||||
const consortiumResourceExplorer = new ConsortiumResourceExplorer();
|
||||
const keys = await consortiumResourceExplorer.getAccessKeys(this);
|
||||
return keys ? keys[0] : '';
|
||||
return keys ? `${url.origin}/${keys[0]}` : url.origin;
|
||||
}
|
||||
|
||||
public toJSON(): { [p: string]: any } {
|
||||
|
|
|
@ -56,16 +56,12 @@ export abstract class Consortium extends ExtensionItem {
|
|||
}
|
||||
|
||||
public async getRPCAddress(): Promise<string> {
|
||||
return this.urls.length === 0 ? '' : this.urls[0].origin;
|
||||
}
|
||||
|
||||
public async getAccessKey(): Promise<string> {
|
||||
if (this.urls.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const url = this.urls[0];
|
||||
return url.pathname === '/' ? '' : url.pathname || '';
|
||||
return url.pathname === '/' ? url.origin : `${url.origin}/${url.pathname}`;
|
||||
}
|
||||
|
||||
public getConsortiumId(): number {
|
||||
|
|
|
@ -1,15 +1,14 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import { SubscriptionModels } from 'azure-arm-resource';
|
||||
import { QuickPickItem } from 'vscode';
|
||||
|
||||
export class LocationItem implements QuickPickItem {
|
||||
public readonly label: string;
|
||||
public readonly description: string;
|
||||
|
||||
constructor(public readonly location: SubscriptionModels.Location) {
|
||||
this.label = location.displayName || '';
|
||||
this.description = location.name || '';
|
||||
constructor(label?: string, description?: string) {
|
||||
this.label = label || '';
|
||||
this.description = description || '';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,13 +20,12 @@ export abstract class ProtectedConsortium extends Consortium {
|
|||
const network = await super.getTruffleNetwork();
|
||||
|
||||
const targetURL = await this.getRPCAddress();
|
||||
const accessKey = await this.getAccessKey();
|
||||
const mnemonic = await this.getMnemonic();
|
||||
await config.importFs();
|
||||
|
||||
network.options.provider = {
|
||||
mnemonic: mnemonic.path,
|
||||
url: `${targetURL}/${accessKey}`,
|
||||
url: `${targetURL}`,
|
||||
};
|
||||
|
||||
return network;
|
||||
|
|
|
@ -12,8 +12,4 @@ export class ConsortiumView extends ExtensionView<Consortium> {
|
|||
public async getRPCAddress(): Promise<string> {
|
||||
return this.extensionItem.getRPCAddress();
|
||||
}
|
||||
|
||||
public async getAccessKey(): Promise<string> {
|
||||
return this.extensionItem.getAccessKey();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import { GanacheCommands } from '../commands/GanacheCommands';
|
||||
import { ConsortiumResourceExplorer } from '../ConsortiumResourceExplorer';
|
||||
import { Constants } from '../Constants';
|
||||
import { showInputBox, showQuickPick } from '../helpers';
|
||||
import {
|
||||
AzureConsortium,
|
||||
Consortium,
|
||||
ItemType,
|
||||
LocalNetworkConsortium,
|
||||
|
@ -15,26 +16,29 @@ import {
|
|||
import { ConsortiumTreeManager } from '../treeService/ConsortiumTreeManager';
|
||||
import { UrlValidator } from '../validators/UrlValidator';
|
||||
import { ConsortiumView } from '../ViewItems';
|
||||
import { WestlakeCommands } from './WestlakeCommands';
|
||||
import { GanacheCommands } from './GanacheCommands';
|
||||
|
||||
interface IConsortiumDestination {
|
||||
cmd: (childrenFilters?: string[]) => Promise<Consortium>;
|
||||
cmd: (excludedItems?: string[]) => Promise<Consortium>;
|
||||
itemType: ItemType;
|
||||
label: string;
|
||||
}
|
||||
|
||||
export namespace ConsortiumCommands {
|
||||
export async function createConsortium(): Promise<Consortium> {
|
||||
export async function createConsortium(consortiumTreeManager: ConsortiumTreeManager): Promise<Consortium> {
|
||||
const createConsortiumDestination: IConsortiumDestination[] = [
|
||||
{
|
||||
cmd: WestlakeCommands.createWestlakeConsortium,
|
||||
cmd: selectOrCreateConsortium,
|
||||
itemType: ItemType.AZURE_BLOCKCHAIN,
|
||||
label: Constants.uiCommandStrings.CreateConsortiumAzureBlockchainService,
|
||||
},
|
||||
];
|
||||
|
||||
const destination = await selectDestination(createConsortiumDestination);
|
||||
return await destination.cmd();
|
||||
const networkItem = await getNetwork(consortiumTreeManager, destination.itemType);
|
||||
const childrenFilters = await getChildrenFilters(networkItem);
|
||||
|
||||
return destination.cmd(childrenFilters);
|
||||
}
|
||||
|
||||
export async function connectConsortium(consortiumTreeManager: ConsortiumTreeManager): Promise<Consortium> {
|
||||
|
@ -45,7 +49,7 @@ export namespace ConsortiumCommands {
|
|||
label: Constants.uiCommandStrings.ConnectConsortiumLocalGanache,
|
||||
},
|
||||
{
|
||||
cmd: WestlakeCommands.selectWestlakeConsortium,
|
||||
cmd: selectOrCreateConsortium,
|
||||
itemType: ItemType.AZURE_BLOCKCHAIN,
|
||||
label: Constants.uiCommandStrings.ConnectConsortiumAzureBlockchainService,
|
||||
},
|
||||
|
@ -67,7 +71,7 @@ export namespace ConsortiumCommands {
|
|||
export async function disconnectConsortium(consortiumTreeManager: ConsortiumTreeManager, viewItem: ConsortiumView)
|
||||
: Promise<void> {
|
||||
if (viewItem.extensionItem instanceof LocalNetworkConsortium) {
|
||||
GanacheCommands.stopGanacheServer();
|
||||
await GanacheCommands.stopGanacheServer();
|
||||
}
|
||||
return consortiumTreeManager.removeItem(viewItem.extensionItem);
|
||||
}
|
||||
|
@ -114,6 +118,11 @@ async function getNetwork(consortiumTreeManager: ConsortiumTreeManager, itemType
|
|||
return networkItem;
|
||||
}
|
||||
|
||||
async function selectOrCreateConsortium(excludedItems?: string[]): Promise<AzureConsortium> {
|
||||
const azureResourceExplorer = new ConsortiumResourceExplorer();
|
||||
return azureResourceExplorer.selectOrCreateConsortium(excludedItems);
|
||||
}
|
||||
|
||||
async function connectLocalNetwork(): Promise<LocalNetworkConsortium> {
|
||||
await GanacheCommands.startGanacheServer();
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Licensed under the MIT license.
|
||||
|
||||
import * as fs from 'fs-extra';
|
||||
import { Uri, window, workspace } from 'vscode';
|
||||
import { ProgressLocation, Uri, window, workspace } from 'vscode';
|
||||
import { Constants } from '../Constants';
|
||||
import {
|
||||
createTemporaryDir,
|
||||
|
@ -50,7 +50,12 @@ export namespace ProjectCommands {
|
|||
}
|
||||
|
||||
async function createNewEmptyProject(projectPath: string): Promise<void> {
|
||||
await createProject(projectPath, Constants.defaultTruffleBox);
|
||||
return window.withProgress({
|
||||
location: ProgressLocation.Window,
|
||||
title: Constants.statusBarMessages.creatingProject,
|
||||
}, async () => {
|
||||
return createProject(projectPath, Constants.defaultTruffleBox);
|
||||
});
|
||||
}
|
||||
|
||||
async function createProjectFromTruffleBox(projectPath: string): Promise<void> {
|
||||
|
@ -65,9 +70,8 @@ async function createProject(projectPath: string, truffleBoxName: string): Promi
|
|||
const path = (arrayFiles.length) ? createTemporaryDir(projectPath) : projectPath;
|
||||
|
||||
try {
|
||||
window.showInformationMessage(Constants.informationMessage.newProjectCreationStarted);
|
||||
Output.show();
|
||||
await outputCommandHelper.executeCommand(path, 'npx', 'truffle', 'unbox', truffleBoxName);
|
||||
await outputCommandHelper.executeCommand(path, 'npx', Constants.truffleCommand, 'unbox', truffleBoxName);
|
||||
if (arrayFiles.length) {
|
||||
fs.moveSync(path, projectPath);
|
||||
}
|
||||
|
@ -75,10 +79,9 @@ async function createProject(projectPath: string, truffleBoxName: string): Promi
|
|||
0,
|
||||
workspace.workspaceFolders ? workspace.workspaceFolders.length : null,
|
||||
{uri: Uri.file(projectPath)});
|
||||
window.showInformationMessage(Constants.informationMessage.newProjectCreationFinished);
|
||||
} catch (error) {
|
||||
// TODO: cleanup files after failed truffle unbox
|
||||
throw Error(error);
|
||||
arrayFiles.length ? fs.removeSync(path) : fs.emptyDirSync(path);
|
||||
throw Error([Constants.errorMessageStrings.NewProjectCreationFailed, error.message].join(' '));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
import * as fs from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import { format } from 'url';
|
||||
import { env, Uri } from 'vscode';
|
||||
import { env, ProgressLocation, Uri, window } from 'vscode';
|
||||
import { Constants } from '../Constants';
|
||||
import {
|
||||
getWorkspaceRoot,
|
||||
|
@ -35,16 +35,21 @@ const localGanacheRegexp = new RegExp(`127\.0\.0\.1\:${Constants.defaultLocalhos
|
|||
|
||||
export namespace TruffleCommands {
|
||||
export async function buildContracts(): Promise<void> {
|
||||
if (!await required.checkRequiredApps()) {
|
||||
return;
|
||||
}
|
||||
await window.withProgress({
|
||||
location: ProgressLocation.Window,
|
||||
title: Constants.statusBarMessages.buildingContracts,
|
||||
}, async () => {
|
||||
if (!await required.checkRequiredApps()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Output.show();
|
||||
await outputCommandHelper.executeCommand(getWorkspaceRoot(), 'npx', 'truffle', 'compile');
|
||||
} catch (error) {
|
||||
throw Error(error);
|
||||
}
|
||||
try {
|
||||
Output.show();
|
||||
await outputCommandHelper.executeCommand(getWorkspaceRoot(), 'npx', 'truffle', 'compile');
|
||||
} catch (error) {
|
||||
throw Error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function deployContracts(consortiumTreeManager: ConsortiumTreeManager): Promise<void> {
|
||||
|
@ -197,7 +202,8 @@ async function execute(deployDestination: IDeployDestination[]): Promise<void> {
|
|||
async function createNewDeploymentNetwork(consortiumTreeManager: ConsortiumTreeManager, truffleConfigPath: string)
|
||||
: Promise<void> {
|
||||
const consortium = await ConsortiumCommands.connectConsortium(consortiumTreeManager);
|
||||
return createNetwork(consortium, truffleConfigPath);
|
||||
|
||||
await createNetwork(consortium, truffleConfigPath);
|
||||
}
|
||||
|
||||
async function createNetwork(consortium: Consortium, truffleConfigPath: string): Promise<void> {
|
||||
|
@ -206,29 +212,28 @@ async function createNetwork(consortium: Consortium, truffleConfigPath: string):
|
|||
await truffleConfig.setNetworks(network);
|
||||
|
||||
await deployToNetwork(network.name, truffleConfigPath);
|
||||
|
||||
if (network.options.provider) {
|
||||
network.options.provider.mnemonic = undefined;
|
||||
}
|
||||
|
||||
return await truffleConfig.setNetworks(network);
|
||||
}
|
||||
|
||||
async function createMainNetwork(consortium: Consortium, truffleConfigPath: string): Promise<void> {
|
||||
await showConfirmPaidOperationDialog();
|
||||
|
||||
return await createNetwork(consortium, truffleConfigPath);
|
||||
await createNetwork(consortium, truffleConfigPath);
|
||||
}
|
||||
|
||||
async function deployToNetwork(networkName: string, truffleConfigPath: string): Promise<void> {
|
||||
const workspaceRoot = path.dirname(truffleConfigPath);
|
||||
return window.withProgress({
|
||||
location: ProgressLocation.Window,
|
||||
title: Constants.statusBarMessages.deployingContracts(networkName),
|
||||
}, async () => {
|
||||
const workspaceRoot = path.dirname(truffleConfigPath);
|
||||
|
||||
await fs.ensureDir(workspaceRoot);
|
||||
await outputCommandHelper.executeCommand(
|
||||
workspaceRoot,
|
||||
'npx',
|
||||
'truffle', 'migrate', '--reset', '--network', networkName,
|
||||
);
|
||||
await fs.ensureDir(workspaceRoot);
|
||||
await outputCommandHelper.executeCommand(
|
||||
workspaceRoot,
|
||||
'npx',
|
||||
'truffle', 'migrate', '--reset', '--network', networkName,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
async function createLocalGanacheNetwork(consortium: Consortium, truffleConfigPath: string): Promise<void> {
|
||||
|
|
|
@ -2,23 +2,10 @@
|
|||
// Licensed under the MIT license.
|
||||
|
||||
import { Uri, window } from 'vscode';
|
||||
import { ConsortiumResourceExplorer } from '../ConsortiumResourceExplorer';
|
||||
import { Constants } from '../Constants';
|
||||
import { AzureConsortium } from '../Models';
|
||||
import { TruffleCommands } from './TruffleCommands';
|
||||
|
||||
export namespace WestlakeCommands {
|
||||
|
||||
export async function createWestlakeConsortium(): Promise<AzureConsortium> {
|
||||
const azureResourceExplorer = new ConsortiumResourceExplorer();
|
||||
return azureResourceExplorer.createConsortium();
|
||||
}
|
||||
|
||||
export async function selectWestlakeConsortium(childrenFilters?: string[]): Promise<AzureConsortium> {
|
||||
const azureResourceExplorer = new ConsortiumResourceExplorer();
|
||||
return azureResourceExplorer.selectConsortium(childrenFilters);
|
||||
}
|
||||
|
||||
export async function showLedgerEventsDialog(uri: Uri): Promise<void> {
|
||||
const ledgerEventsDestination = [
|
||||
{
|
||||
|
@ -44,7 +31,7 @@ export namespace WestlakeCommands {
|
|||
throw new Error('Action aborted');
|
||||
}
|
||||
|
||||
return await target.cmd(uri);
|
||||
return target.cmd(uri);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,12 +15,11 @@ import { CommandContext, isWorkspaceOpen, required, setCommandContext } from './
|
|||
import { MnemonicRepository } from './MnemonicService/MnemonicRepository';
|
||||
import { CancellationEvent } from './Models';
|
||||
import { Output } from './Output';
|
||||
import { RequirementsPage } from './RequirementsPage';
|
||||
import { RequirementsPage, WelcomePage } from './pages';
|
||||
import { TelemetryClient } from './TelemetryClient';
|
||||
import { ConsortiumTree } from './treeService/ConsortiumTree';
|
||||
import { ConsortiumTreeManager } from './treeService/ConsortiumTreeManager';
|
||||
import { ConsortiumView } from './ViewItems';
|
||||
import { WelcomePage } from './WelcomePage';
|
||||
|
||||
export async function activate(context: ExtensionContext) {
|
||||
Constants.initialize(context);
|
||||
|
@ -35,27 +34,24 @@ export async function activate(context: ExtensionContext) {
|
|||
const consortiumTreeManager = new ConsortiumTreeManager(context);
|
||||
const consortiumTree = new ConsortiumTree(consortiumTreeManager);
|
||||
|
||||
welcomePage.checkAndShow();
|
||||
await welcomePage.checkAndShow();
|
||||
window.registerTreeDataProvider('AzureBlockchain', consortiumTree);
|
||||
|
||||
//#region azureBlockchain extension commands
|
||||
const refresh = commands.registerCommand('azureBlockchainService.refresh', (element) => {
|
||||
consortiumTree.refresh(element);
|
||||
});
|
||||
const showWelcomePage = commands.registerCommand('azureBlockchainService.showWelcomePage', () => {
|
||||
welcomePage.show();
|
||||
const showWelcomePage = commands.registerCommand('azureBlockchainService.showWelcomePage', async () => {
|
||||
return welcomePage.show();
|
||||
});
|
||||
const showRequirementsPage = commands.registerCommand('azureBlockchainService.showRequirementsPage', () => {
|
||||
requirementsPage.show();
|
||||
const showRequirementsPage = commands.registerCommand('azureBlockchainService.showRequirementsPage',
|
||||
async (checkShowOnStartup: boolean) => {
|
||||
return checkShowOnStartup ? requirementsPage.checkAndShow() : requirementsPage.show();
|
||||
});
|
||||
const copyRPCEndpointAddress = commands.registerCommand('azureBlockchainService.copyRPCEndpointAddress',
|
||||
async (viewItem: ConsortiumView) => {
|
||||
await tryExecute(() => AzureBlockchain.copyRPCEndpointAddress(viewItem));
|
||||
});
|
||||
const copyAccessKey = commands.registerCommand('azureBlockchainService.copyAccessKey',
|
||||
async (viewItem: ConsortiumView) => {
|
||||
await tryExecute(() => AzureBlockchain.copyAccessKey(viewItem));
|
||||
});
|
||||
const installNpm = commands.registerCommand('azureBlockchainService.required.installNpm', async () => {
|
||||
await tryExecute(() => required.installNpm());
|
||||
});
|
||||
|
@ -102,7 +98,7 @@ export async function activate(context: ExtensionContext) {
|
|||
|
||||
//#region commands with dialog
|
||||
const createConsortium = commands.registerCommand('azureBlockchainService.createConsortium', async () => {
|
||||
await tryExecute(() => ConsortiumCommands.createConsortium());
|
||||
await tryExecute(() => ConsortiumCommands.createConsortium(consortiumTreeManager));
|
||||
});
|
||||
const connectConsortium = commands.registerCommand('azureBlockchainService.connectConsortium', async () => {
|
||||
await tryExecute(() => ConsortiumCommands.connectConsortium(consortiumTreeManager));
|
||||
|
@ -175,7 +171,6 @@ export async function activate(context: ExtensionContext) {
|
|||
context.subscriptions.push(copyByteCode);
|
||||
context.subscriptions.push(copyABI);
|
||||
context.subscriptions.push(copyRPCEndpointAddress);
|
||||
context.subscriptions.push(copyAccessKey);
|
||||
context.subscriptions.push(startGanacheServer);
|
||||
context.subscriptions.push(stopGanacheServer);
|
||||
context.subscriptions.push(generateMicroservicesWorkflows);
|
||||
|
|
|
@ -4,9 +4,6 @@ import { Constants } from '../Constants';
|
|||
import { Output } from '../Output';
|
||||
import { executeCommand, tryExecuteCommand } from './command';
|
||||
import { CommandContext, setCommandContext } from './commandContext';
|
||||
import Timeout = NodeJS.Timeout;
|
||||
|
||||
let timeoutID: NodeJS.Timeout;
|
||||
|
||||
export namespace required {
|
||||
export interface IRequiredVersion {
|
||||
|
@ -18,7 +15,6 @@ export namespace required {
|
|||
|
||||
const currentState: {[key: string]: IRequiredVersion} = {};
|
||||
const requiredApps = [ 'node', 'npm', 'git' ];
|
||||
// const auxiliaryApps = [ 'python', 'truffle', 'ganache' ];
|
||||
|
||||
export function isValid(version: string, minVersion: string, maxVersion?: string): boolean {
|
||||
return !!semver.valid(version) &&
|
||||
|
@ -27,37 +23,47 @@ export namespace required {
|
|||
}
|
||||
|
||||
/**
|
||||
* Function check all apps:
|
||||
* Node.js, npm, git, truffle, ganache, python
|
||||
* Function check all apps: Node.js, npm, git, truffle, ganache, python
|
||||
* Show Requirements Page with checking showOnStartup flag
|
||||
*/
|
||||
export async function checkAllApps(): Promise<boolean> {
|
||||
const versions = await getAllVersions();
|
||||
const invalid = versions.some((version) => !version.isValid);
|
||||
|
||||
if (invalid) {
|
||||
showRequiredAppsMessage();
|
||||
return false;
|
||||
const message = Constants.informationMessage.invalidRequiredVersion;
|
||||
const details = Constants.informationMessage.seeDetailsRequirementsPage;
|
||||
window
|
||||
.showErrorMessage(`${message}. ${details}`, Constants.informationMessage.detailsButton)
|
||||
.then((answer) => {
|
||||
if (answer) {
|
||||
commands.executeCommand('azureBlockchainService.showRequirementsPage');
|
||||
}
|
||||
});
|
||||
commands.executeCommand('azureBlockchainService.showRequirementsPage', true);
|
||||
}
|
||||
|
||||
return true;
|
||||
return !invalid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function check only required apps:
|
||||
* Node.js, npm, git
|
||||
* Function check only required apps: Node.js, npm, git
|
||||
* Show Requirements Page
|
||||
*/
|
||||
export async function checkRequiredApps(message?: string): Promise<boolean> {
|
||||
export async function checkRequiredApps(): Promise<boolean> {
|
||||
const versions = await getAllVersions();
|
||||
const invalid = versions
|
||||
.filter((version) => requiredApps.includes(version.app))
|
||||
.some((version) => !version.isValid);
|
||||
|
||||
if (invalid) {
|
||||
showRequiredAppsMessage(message || Constants.errorMessageStrings.RequiredAppsAreNotInstalled);
|
||||
return false;
|
||||
const message = Constants.errorMessageStrings.RequiredAppsAreNotInstalled;
|
||||
const details = Constants.informationMessage.seeDetailsRequirementsPage;
|
||||
window.showErrorMessage(`${message}. ${details}`);
|
||||
commands.executeCommand('azureBlockchainService.showRequirementsPage');
|
||||
}
|
||||
|
||||
return true;
|
||||
return !invalid;
|
||||
}
|
||||
|
||||
export async function getAllVersions(): Promise<IRequiredVersion[]> {
|
||||
|
@ -79,21 +85,6 @@ export namespace required {
|
|||
return Object.values(currentState);
|
||||
}
|
||||
|
||||
export function showRequiredAppsMessage(message?: string): void {
|
||||
commands.executeCommand('azureBlockchainService.showRequirementsPage');
|
||||
|
||||
clearTimeout(timeoutID as Timeout);
|
||||
timeoutID = setTimeout(async () => {
|
||||
try {
|
||||
message = message || Constants.informationMessage.invalidRequiredVersion;
|
||||
|
||||
window.showErrorMessage(`${message} ${Constants.informationMessage.seeDetailsRequirementsPage}`);
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
export async function getNodeVersion(): Promise<string> {
|
||||
return getVersion('node', '--version', /v(\d+.\d+.\d+)/);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче