diff --git a/packages/composer-playground-api/routes/npm.js b/packages/composer-playground-api/routes/npm.js
index de3f401f60..2b15bc6840 100644
--- a/packages/composer-playground-api/routes/npm.js
+++ b/packages/composer-playground-api/routes/npm.js
@@ -158,10 +158,12 @@ module.exports = (app) => {
name : metadata.name,
description : metadata.description,
version : metadata.version,
+ //TODO update this after release
+ networkImage : 'https://hyperledger.github.io/composer-sample-networks/packages/' + metadata.name + '/networkimage.svg',
+ networkImageanimated: 'https://hyperledger.github.io/composer-sample-networks/packages/' + metadata.name + '/networkimageanimated.svg',
tarball : metadata.dist.tarball
});
}
-
});
LOG.exit(method, options);
diff --git a/packages/composer-playground-api/test/npm.js b/packages/composer-playground-api/test/npm.js
index 6afa81c734..aa92000432 100644
--- a/packages/composer-playground-api/test/npm.js
+++ b/packages/composer-playground-api/test/npm.js
@@ -248,8 +248,8 @@ describe('npm routes', () => {
beforeEach(() => {
mock = {
- 'composer-common/package.json': {
- version: composerVersion
+ 'composer-common/package.json' : {
+ version : composerVersion
},
'npm-registry-client' : RegClient
};
@@ -276,6 +276,8 @@ describe('npm routes', () => {
name : 'bob',
description : 'bob package',
version : '1.0',
+ networkImage : 'https://hyperledger.github.io/composer-sample-networks/packages/bob/networkimage.svg',
+ networkImageanimated: 'https://hyperledger.github.io/composer-sample-networks/packages/bob/networkimageanimated.svg',
tarball : 'my tar'
}]);
});
@@ -293,17 +295,23 @@ describe('npm routes', () => {
name : 'ant',
description : 'ant package',
version : '1.0',
- tarball : 'my tar'
+ tarball : 'my tar',
+ networkImage : 'https://hyperledger.github.io/composer-sample-networks/packages/ant/networkimage.svg',
+ networkImageanimated: 'https://hyperledger.github.io/composer-sample-networks/packages/ant/networkimageanimated.svg',
}, {
name : 'bat',
description : 'bat package',
version : '1.0',
- tarball : 'my tar'
+ tarball : 'my tar',
+ networkImage : 'https://hyperledger.github.io/composer-sample-networks/packages/bat/networkimage.svg',
+ networkImageanimated: 'https://hyperledger.github.io/composer-sample-networks/packages/bat/networkimageanimated.svg',
}, {
name : 'cat',
description : 'cat package',
version : '1.0',
- tarball : 'my tar'
+ tarball : 'my tar',
+ networkImage : 'https://hyperledger.github.io/composer-sample-networks/packages/cat/networkimage.svg',
+ networkImageanimated: 'https://hyperledger.github.io/composer-sample-networks/packages/cat/networkimageanimated.svg',
}]);
});
});
@@ -362,9 +370,6 @@ describe('npm routes', () => {
});
});
});
-
});
-
});
-
});
diff --git a/packages/composer-playground/src/app/app.component.html b/packages/composer-playground/src/app/app.component.html
index 633d329cfa..5db312f432 100644
--- a/packages/composer-playground/src/app/app.component.html
+++ b/packages/composer-playground/src/app/app.component.html
@@ -46,7 +46,7 @@
-
-
+
+
{{ v1FormErrors.orderers.cert }}
-
+
-
-
+
+
+
@@ -266,26 +266,26 @@
(click)="openAddCertificateModal(i,'peers');">
+
-
+
-
+
-
-
+
+
@@ -310,8 +310,7 @@
-
-
+
Advanced
diff --git a/packages/composer-playground/src/app/editor/editor.component.spec.ts b/packages/composer-playground/src/app/editor/editor.component.spec.ts
index 8738176417..dd1b6679fb 100644
--- a/packages/composer-playground/src/app/editor/editor.component.spec.ts
+++ b/packages/composer-playground/src/app/editor/editor.component.spec.ts
@@ -14,14 +14,16 @@ import { ClientService } from '../services/client.service';
import { EditorService } from './editor.service';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
import { AlertService } from '../basic-modals/alert.service';
-import { ModelFile, Script, AclManager, AclFile, QueryFile } from 'composer-common';
+import { ModelFile, Script, AclFile, QueryFile } from 'composer-common';
import { ScrollToElementDirective } from '../directives/scroll/scroll-to-element.directive';
+import { BehaviorSubject } from 'rxjs/Rx';
import * as sinon from 'sinon';
import * as chai from 'chai';
import 'rxjs/add/operator/takeWhile';
import * as fileSaver from 'file-saver';
+import { DrawerService } from '../common/drawer/drawer.service';
let should = chai.should();
@@ -60,6 +62,7 @@ describe('EditorComponent', () => {
let mockAlertService;
let mockClientService;
let mockModal;
+ let mockDrawer;
let mockModelFile;
let mockScriptFile;
let mockRuleFile;
@@ -71,6 +74,7 @@ describe('EditorComponent', () => {
mockAlertService = sinon.createStubInstance(AlertService);
mockClientService = sinon.createStubInstance(ClientService);
mockModal = sinon.createStubInstance(NgbModal);
+ mockDrawer = sinon.createStubInstance(DrawerService);
mockModelFile = sinon.createStubInstance(ModelFile);
mockScriptFile = sinon.createStubInstance(Script);
mockRuleFile = sinon.createStubInstance(AclFile);
@@ -91,7 +95,8 @@ describe('EditorComponent', () => {
{provide: ClientService, useValue: mockClientService},
{provide: NgbModal, useValue: mockModal},
{provide: AlertService, useValue: mockAlertService},
- {provide: EditorService, useValue: editorService}]
+ {provide: EditorService, useValue: editorService},
+ {provide: DrawerService, useValue: mockDrawer}]
});
fixture = TestBed.createComponent(EditorComponent);
@@ -1013,13 +1018,19 @@ describe('EditorComponent', () => {
let mockUpdatePackage = sinon.stub(component, 'updatePackageInfo');
let mockUpdateFiles = sinon.stub(component, 'updateFiles');
- mockModal.open = sinon.stub().returns({
- componentInstance: {},
- result: Promise.resolve()
+ let finishedImport = new BehaviorSubject
(true);
+
+ mockDrawer.open = sinon.stub().returns({
+ componentInstance: {
+ finishedSampleImport: finishedImport
+ },
+ close: sinon.stub()
});
component.openImportModal();
+ finishedImport.next({deployed: true});
+
tick();
mockUpdatePackage.should.have.been.called;
@@ -1033,13 +1044,19 @@ describe('EditorComponent', () => {
component['files'] = [{readme: true}, {model: true}];
- mockModal.open = sinon.stub().returns({
- componentInstance: {},
- result: Promise.resolve()
+ let finishedImport = new BehaviorSubject(true);
+
+ mockDrawer.open = sinon.stub().returns({
+ componentInstance: {
+ finishedSampleImport: finishedImport
+ },
+ close: sinon.stub()
});
component.openImportModal();
+ finishedImport.next({deployed: true});
+
tick();
mockUpdatePackage.should.have.been.called;
@@ -1055,13 +1072,19 @@ describe('EditorComponent', () => {
component['files'] = [{model: true}, {script: true}];
- mockModal.open = sinon.stub().returns({
- componentInstance: {},
- result: Promise.resolve()
+ let finishedImport = new BehaviorSubject(true);
+
+ mockDrawer.open = sinon.stub().returns({
+ componentInstance: {
+ finishedSampleImport: finishedImport
+ },
+ close: sinon.stub()
});
component.openImportModal();
+ finishedImport.next({deployed: true});
+
tick();
mockUpdatePackage.should.have.been.called;
@@ -1074,13 +1097,19 @@ describe('EditorComponent', () => {
let mockUpdatePackage = sinon.stub(component, 'updatePackageInfo');
let mockUpdateFiles = sinon.stub(component, 'updateFiles');
- mockModal.open = sinon.stub().returns({
- componentInstance: {},
- result: Promise.reject('some error')
+ let finishedImport = new BehaviorSubject(true);
+
+ mockDrawer.open = sinon.stub().returns({
+ componentInstance: {
+ finishedSampleImport: finishedImport
+ },
+ close: sinon.stub()
});
component.openImportModal();
+ finishedImport.next({deployed: false, error: 'some error'});
+
tick();
mockUpdatePackage.should.not.have.been.called;
@@ -1093,13 +1122,19 @@ describe('EditorComponent', () => {
let mockUpdatePackage = sinon.stub(component, 'updatePackageInfo');
let mockUpdateFiles = sinon.stub(component, 'updateFiles');
- mockModal.open = sinon.stub().returns({
- componentInstance: {},
- result: Promise.reject(1)
+ let finishedImport = new BehaviorSubject(true);
+
+ mockDrawer.open = sinon.stub().returns({
+ componentInstance: {
+ finishedSampleImport: finishedImport
+ },
+ close: sinon.stub()
});
component.openImportModal();
+ finishedImport.next({deployed: false});
+
tick();
mockUpdatePackage.should.not.have.been.called;
diff --git a/packages/composer-playground/src/app/editor/editor.component.ts b/packages/composer-playground/src/app/editor/editor.component.ts
index cef73bc63b..eb45a60dc8 100644
--- a/packages/composer-playground/src/app/editor/editor.component.ts
+++ b/packages/composer-playground/src/app/editor/editor.component.ts
@@ -1,17 +1,27 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
-import { ImportComponent } from './import/import.component';
+import { ImportComponent } from '../import/import.component';
import { AddFileComponent } from './add-file/add-file.component';
import { DeleteComponent } from '../basic-modals/delete-confirm/delete-confirm.component';
import { ReplaceComponent } from '../basic-modals/replace-confirm';
+import { DrawerService } from '../common/drawer/drawer.service';
import { AdminService } from '../services/admin.service';
import { ClientService } from '../services/client.service';
import { AlertService } from '../basic-modals/alert.service';
import { EditorService } from './editor.service';
-import { ModelFile, Script, ScriptManager, ModelManager, AclManager, AclFile, QueryFile, QueryManager } from 'composer-common';
+import {
+ ModelFile,
+ Script,
+ ScriptManager,
+ ModelManager,
+ AclManager,
+ AclFile,
+ QueryFile,
+ QueryManager
+} from 'composer-common';
import 'rxjs/add/operator/takeWhile';
import { saveAs } from 'file-saver';
@@ -60,7 +70,8 @@ export class EditorComponent implements OnInit, OnDestroy {
private clientService: ClientService,
private modalService: NgbModal,
private alertService: AlertService,
- private editorService: EditorService) {
+ private editorService: EditorService,
+ private drawerService: DrawerService) {
}
@@ -375,29 +386,35 @@ export class EditorComponent implements OnInit, OnDestroy {
}
openImportModal() {
- const importModalRef = this.modalService.open(ImportComponent);
+ const importModalRef = this.drawerService.open(ImportComponent);
// only want to update here not deploy
importModalRef.componentInstance.deployNetwork = false;
- importModalRef.result.then((result) => {
- this.updatePackageInfo();
- this.updateFiles();
- if (this.files.length) {
- let currentFile = this.files.find((file) => {
- return file.readme;
- });
- if (!currentFile) {
- currentFile = this.files[0];
+
+ importModalRef.componentInstance.finishedSampleImport.subscribe((result) => {
+
+ importModalRef.close();
+
+ if (result.deployed) {
+ this.updatePackageInfo();
+ this.updateFiles();
+ if (this.files.length) {
+ let currentFile = this.files.find((file) => {
+ return file.readme;
+ });
+ if (!currentFile) {
+ currentFile = this.files[0];
+ }
+ this.setCurrentFile(currentFile);
+ this.alertService.successStatus$.next({
+ title: 'Deploy Successful',
+ text: 'Business network imported deployed successfully',
+ icon: '#icon-deploy_24'
+ });
}
- this.setCurrentFile(currentFile);
- this.alertService.successStatus$.next({
- title: 'Deploy Successful',
- text: 'Business network imported deployed successfully',
- icon: '#icon-deploy_24'
- });
- }
- }, (reason) => {
- if (reason && reason !== 1) {
- this.alertService.errorStatus$.next(reason);
+ } else {
+ if (result.error) {
+ this.alertService.errorStatus$.next(result.error);
+ }
}
});
}
@@ -670,13 +687,13 @@ export class EditorComponent implements OnInit, OnDestroy {
file.invalid = false;
}
} else if (file.query) {
- let query = this.clientService.getQueryFile();
- if (this.clientService.validateFile(file.id, query.getDefinitions(), 'query') !== null) {
- allValid = false;
- file.invalid = true;
- } else {
- file.invalid = false;
- }
+ let query = this.clientService.getQueryFile();
+ if (this.clientService.validateFile(file.id, query.getDefinitions(), 'query') !== null) {
+ allValid = false;
+ file.invalid = true;
+ } else {
+ file.invalid = false;
+ }
}
}
return allValid;
diff --git a/packages/composer-playground/src/app/editor/editor.module.ts b/packages/composer-playground/src/app/editor/editor.module.ts
index bbdff5e87a..6a145ea05f 100644
--- a/packages/composer-playground/src/app/editor/editor.module.ts
+++ b/packages/composer-playground/src/app/editor/editor.module.ts
@@ -10,15 +10,15 @@ import { EditorFileComponent } from './editor-file/editor-file.component';
import { EditorService } from './editor.service';
import { EditorRoutingModule } from './editor-routing.module';
import { AddFileComponent } from './add-file/add-file.component';
-import { ImportComponent } from './import/import.component';
import { FileImporterModule } from '../common/file-importer/file-importer.module';
import { DirectivesModule } from '../directives/directives.module';
+import { ImportModule } from '../import/import.module';
import { FooterModule } from '../footer/footer.module';
@NgModule({
- imports: [CommonModule, FormsModule, NgbModule, PerfectScrollbarModule, CodemirrorModule, DirectivesModule, FileImporterModule, EditorRoutingModule, FooterModule],
- entryComponents: [AddFileComponent, ImportComponent],
- declarations: [EditorComponent, EditorFileComponent, AddFileComponent, ImportComponent],
+ imports: [CommonModule, FormsModule, NgbModule, PerfectScrollbarModule, CodemirrorModule, DirectivesModule, FileImporterModule, ImportModule, EditorRoutingModule, FooterModule],
+ entryComponents: [AddFileComponent],
+ declarations: [EditorComponent, EditorFileComponent, AddFileComponent],
providers: [EditorService]
})
diff --git a/packages/composer-playground/src/app/editor/import/import.component.html b/packages/composer-playground/src/app/editor/import/import.component.html
deleted file mode 100644
index 2ba38edb08..0000000000
--- a/packages/composer-playground/src/app/editor/import/import.component.html
+++ /dev/null
@@ -1,114 +0,0 @@
-
-
-
- Upload a Business Network Archive from your computer
-
-
-
-
-
-
-
{{currentBusinessNetwork.getName()}}
-
- {{currentAssets.length}} Assets
- {{currentParticipants.length}} Participants
- {{currentTransactions.length}} Transactions
-
-
-
-
-
-
-
-
-
-
Files:
-
- -
- {{modelFile.getName()}}
-
- -
- {{scriptFile.getIdentifier()}}
-
- -
- {{currentBusinessNetwork.getAclManager().getAclFile().getIdentifier()}}
-
- -
- {{currentBusinessNetwork.getQueryManager().getQueryFile().getIdentifier()}}
-
- - README.md
-
-
-
-
0" class="network-part">
- Assets:
- {{asset.getName()}}{{i === 1 || lastOne ? '' : ', ' }}
- 2">+ {{currentAssets.length -2}} more
-
-
0"
- class="network-part">
- Participants:
- {{participant.getName()}}{{i === 1 || lastOne ? '' : ', ' }}
- 2">+ {{currentParticipants.length -2}} more
-
-
0" class="network-part">
- Transactions:
- {{transaction.getName()}}{{i === 1 || lastOne ? '' : ', ' }}
- 2">+ {{currentTransactions.length -2}} more
-
-
-
-
-
-
Select a sample to deploy into Hyperledger Composer Playground
-
-
-
-
-
-
{{sampleNetwork.description}}
-
-
-
-
-
-
diff --git a/packages/composer-playground/src/app/editor/import/import.component.scss b/packages/composer-playground/src/app/editor/import/import.component.scss
deleted file mode 100644
index 600b7cac67..0000000000
--- a/packages/composer-playground/src/app/editor/import/import.component.scss
+++ /dev/null
@@ -1,129 +0,0 @@
-@import '../../../assets/styles/base/colors';
-@import '../../../assets/styles/base/variables';
-
-import-modal {
- .import {
- width: 700px;
- height: 525px;
-
- display: flex;
- flex-direction: column;
-
- section {
- font-size: 0.9em;
-
- file-importer {
- margin-top: $space-medium;
- }
-
- span {
- color: $secondary-text;
- }
-
- .chosen-file {
- flex: 1;
- display: flex;
- flex-direction: column;
- background-color: $third-highlight;
- padding: $space-medium;
-
- .title {
- font-weight: bold;
- }
-
- .file-info {
- display: flex;
- justify-content: space-between;
- border-bottom: 1px solid $fifth-highlight;
- padding-bottom: $space-medium;
- align-items: center;
-
- svg {
- fill: $first-highlight;
- width: 76px;
- height: 76px;
- margin-right: $space-medium;
- }
-
- .file-title {
- display: flex;
- flex-direction: column;
- justify-content: center;
-
- span {
- color: $primary-text;
- font-style: italic;
- }
- }
- }
-
- .file-content {
- margin-top: $space-medium;
- flex: 1;
- display: flex;
- justify-content: space-between;
-
- .network-part {
- margin-bottom: $space-smedium;
- }
- }
- }
-
- .github-spinner {
- height: 200px;
- width: 100%;
- display: flex;
- align-items: center;
- justify-content: center;
-
- .circle-path {
- stroke: $first-highlight;
- }
- }
-
- .sample-network-list-container {
- max-height: 200px;
- overflow-y: scroll;
- margin-top: $space-medium;
- }
-
- .sample-network-list {
- background-color: $third-highlight;
- padding: $space-medium;
- &:nth-child(even) {
- background-color: $white;
- }
-
- .description {
- font-style: italic;
- padding-left: 2em;
- }
-
- label.radio-label {
- font-weight: bold;
-
- &::before {
- top: 8px;
- }
-
- &::after {
- top: 13px;
- }
- }
- }
- }
-
- footer {
- .circle-path {
- stroke: $white;
- }
-
- width: 100%;
- }
- }
-
- .ps.ps--active-x>.ps__scrollbar-x-rail,
- .ps.ps--active-y>.ps__scrollbar-y-rail{
- opacity: 0.6;
- }
-}
diff --git a/packages/composer-playground/src/app/editor/import/import.component.ts b/packages/composer-playground/src/app/editor/import/import.component.ts
index d6c8817267..e69de29bb2 100644
--- a/packages/composer-playground/src/app/editor/import/import.component.ts
+++ b/packages/composer-playground/src/app/editor/import/import.component.ts
@@ -1,235 +0,0 @@
-import { Component, OnInit, Input } from '@angular/core';
-import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap';
-
-import { AdminService } from '../../services/admin.service';
-import { ClientService } from '../../services/client.service';
-import { SampleBusinessNetworkService } from '../../services/samplebusinessnetwork.service';
-import { AlertService } from '../../basic-modals/alert.service';
-import { ReplaceComponent } from '../../basic-modals/replace-confirm';
-
-import { BusinessNetworkDefinition } from 'composer-common';
-import { ErrorComponent } from '../../basic-modals/error';
-
-const fabricComposerOwner = 'hyperledger';
-const fabricComposerRepository = 'composer-sample-networks';
-
-@Component({
- selector: 'import-modal',
- templateUrl: './import.component.html',
- styleUrls: ['./import.component.scss'.toString()]
-})
-export class ImportComponent implements OnInit {
-
- // choose whether to deploy or update the business network
- @Input() deployNetwork: boolean;
-
- private deployInProgress: boolean = false;
- private gitHubInProgress: boolean = false;
- private sampleNetworks = [];
- private primaryNetworkNames = ['basic-sample-network'];
- private chosenNetwork = null;
- private expandInput: boolean = false;
-
- private maxFileSize: number = 5242880;
- private supportedFileTypes: string[] = ['.bna'];
-
- private _currentBusinessNetwork = null;
-
- set currentBusinessNetwork(businessNetwork) {
- this._currentBusinessNetwork = businessNetwork;
- if (businessNetwork instanceof BusinessNetworkDefinition) {
- this.currentAssets = businessNetwork.getModelManager().getAssetDeclarations().filter((d) => !d.isAbstract() && !d.isSystemType());
- this.currentParticipants = businessNetwork.getModelManager().getParticipantDeclarations().filter((d) => !d.isAbstract() && !d.isSystemType());
- this.currentTransactions = businessNetwork.getModelManager().getTransactionDeclarations().filter((d) => !d.isAbstract() && !d.isSystemType());
- }
- }
-
- get currentBusinessNetwork() {
- return this._currentBusinessNetwork;
- }
-
- private currentAssets = [];
- private currentParticipants = [];
- private currentTransactions = [];
-
- private NAME = 'Empty Business Network';
- private DESC = 'Start from scratch with a blank business network';
- private EMPTY_BIZNET = {name: this.NAME, description: this.DESC};
-
- constructor(private clientService: ClientService,
- public activeModal: NgbActiveModal,
- public modalService: NgbModal,
- private sampleBusinessNetworkService: SampleBusinessNetworkService,
- private alertService: AlertService,
- private adminService: AdminService) {
-
- }
-
- ngOnInit(): Promise {
- this.currentBusinessNetwork = null;
-
- return this.adminService.connectWithoutNetwork(false)
- .then(() => {
- this.onShow();
- });
- }
-
- onShow() {
- this.gitHubInProgress = true;
- this.sampleBusinessNetworkService.getSampleList()
- .then((sampleNetworkList) => {
- this.sampleNetworks = this.addEmptyNetworkOption(sampleNetworkList);
- this.gitHubInProgress = false;
-
- })
- .catch((error) => {
- this.gitHubInProgress = false;
- this.alertService.errorStatus$.next(error);
- });
- }
-
- addEmptyNetworkOption(networks: any[]): any[] {
-
- let newOrder = [];
-
- // Append new network option to the list.
- newOrder.push(this.EMPTY_BIZNET);
-
- for (let i = 0; i < networks.length; i++) {
- newOrder.push(networks[i]);
- }
-
- return newOrder;
- }
-
- removeFile() {
- this.expandInput = false;
- this.currentBusinessNetwork = null;
- }
-
- deploy() {
- const confirmModalRef = this.modalService.open(ReplaceComponent);
- confirmModalRef.componentInstance.mainMessage = 'Your Business Network Definition currently in the Playground will be removed & replaced.';
- confirmModalRef.componentInstance.supplementaryMessage = 'Please ensure that you have exported any current model files in the Playground.';
- confirmModalRef.result.then((result) => {
- if (result === true) {
- this.deployInProgress = true;
- let deployPromise;
- if (this.currentBusinessNetwork) {
- deployPromise = this.sampleBusinessNetworkService.deployBusinessNetwork(this.currentBusinessNetwork, this.deployNetwork);
- } else {
- deployPromise = this.deployFromNpm();
- }
-
- deployPromise.then(() => {
- this.deployInProgress = false;
- let deployedBusinessNetwork = this.currentBusinessNetwork ? this.currentBusinessNetwork.getName() : this.chosenNetwork;
- this.activeModal.close(deployedBusinessNetwork);
- })
- .catch((error) => {
- this.deployInProgress = false;
- this.alertService.busyStatus$.next(null);
- this.alertService.errorStatus$.next(error);
- });
-
- return deployPromise;
- }
- })
- .catch((error) => {
- this.deployInProgress = false;
- if (error && error !== 1) {
- this.alertService.errorStatus$.next(error);
- }
- });
- }
-
- deployFromNpm(): Promise {
-
- if (this.chosenNetwork === this.NAME
- ) {
- let readme = 'This is the readme file for the Business Network Definition created in Playground';
- let packageJson = {
- name: 'unnamed-network',
- author: 'author',
- description: 'Empty Business Network',
- version: '0.0.1',
- devDependencies: {
- 'browserfs': '^1.2.0',
- 'chai': '^3.5.0',
- 'composer-admin': 'latest',
- 'composer-cli': 'latest',
- 'composer-client': 'latest',
- 'composer-connector-embedded': 'latest',
- 'eslint': '^3.6.1',
- 'istanbul': '^0.4.5',
- 'jsdoc': '^3.4.1',
- 'mkdirp': '^0.5.1',
- 'mocha': '^3.2.0',
- 'moment': '^2.17.1'
- },
- keywords: [],
- license: 'Apache 2.0',
- repository: {
- type: 'e.g. git',
- url: 'URL'
- },
- scripts: {
- deploy: './scripts/deploy.sh',
- doc: 'jsdoc --pedantic --recurse -c jsdoc.conf',
- lint: 'eslint .',
- postlicchk: 'npm run doc',
- postlint: 'npm run licchk',
- prepublish: 'mkdirp ./dist && composer archive create --sourceType dir --sourceName . -a ./dist/unnamed-network.bna',
- pretest: 'npm run lint',
- test: 'mocha --recursive'
- }
- };
- let emptyBizNetDef = new BusinessNetworkDefinition('', '', packageJson, readme);
- this.currentBusinessNetwork = emptyBizNetDef;
- return this.sampleBusinessNetworkService.deployBusinessNetwork(this.currentBusinessNetwork, this.deployNetwork);
-
- } else {
-
- let chosenSampleNetwork = this.sampleNetworks.find((sampleNetwork) => {
- return sampleNetwork.name === this.chosenNetwork;
- });
-
- return this.sampleBusinessNetworkService.deployChosenSample(chosenSampleNetwork, this.deployNetwork);
-
- }
- }
-
- private fileDetected() {
- this.expandInput = true;
- }
-
- private fileLeft() {
- this.expandInput = false;
-
- }
-
- private fileAccepted(file: File) {
- let fileReader = new FileReader();
- fileReader.onload = () => {
- let dataBuffer = Buffer.from(fileReader.result);
- this.clientService.getBusinessNetworkFromArchive(dataBuffer)
- .then((businessNetwork) => {
- this.currentBusinessNetwork = businessNetwork;
- // needed for if browse file
- this.expandInput = true;
- })
- .catch((error) => {
- let failMessage = 'Cannot import an invalid Business Network Definition. Found ' + error.toString();
- this.alertService.errorStatus$.next(failMessage);
- this.expandInput = false;
- });
- };
-
- fileReader.readAsArrayBuffer(file);
- }
-
- private fileRejected(reason: string) {
- this.alertService.errorStatus$.next(reason);
- this.expandInput = false;
- }
-}
diff --git a/packages/composer-playground/src/app/import/import.component.html b/packages/composer-playground/src/app/import/import.component.html
new file mode 100644
index 0000000000..0ae0f98a7c
--- /dev/null
+++ b/packages/composer-playground/src/app/import/import.component.html
@@ -0,0 +1,152 @@
+
+
{{deployNetwork ? 'Deploy New Business Network' : 'Import/Replace Network'}}
+
+ 1. Basic Information
+
+
+
+ 2. Model Network Starter Template
+
+
Choose a Business Network Definition to {{deployNetwork ? 'start with:' : 'replace
+ your current
+ one:'}}
+
+
Choose a sample to play with, start a new project, or import your previous work
+
+
+
+
+
+

+
{{sampleNetworks[1].name}}
+
+
+
+
{{sampleNetworks[0].name}}
+
+
+
+

+
+
{{chosenNetwork.name}}
+
+
+
+
+
Samples on npm
+
+
+
+

+
+
{{sampleNetwork.name}}
+
+
+
+
+
+
+
+
+ The files in the {{clientService.getBusinessNetworkName()}} will be replace with files from:
+
+
+
+

+
+
+
+
+ {{networkName ? networkName : 'Business Network Name'}}
+ {{networkDescription ? networkDescription : 'Business network description will be previewed here when
+ entered in the basic information section.'}}
+
+
+
+ connection profile
+
+ {{currentConnectionProfile}}
+
+
+
+
+
+ based on
+
+
{{chosenNetwork.name}}
+
{{chosenNetwork.description}}
+
+
+
+
+ Contains:
+ {{bn.getModelManager().getParticipantDeclarations().length}} Participant Types,
+ {{bn.getModelManager().getAssetDeclarations().length}} Asset Types, and
+ {{bn.getModelManager().getTransactionDeclarations().length}} Transaction Types
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/composer-playground/src/app/import/import.component.scss b/packages/composer-playground/src/app/import/import.component.scss
new file mode 100644
index 0000000000..c706c80c0c
--- /dev/null
+++ b/packages/composer-playground/src/app/import/import.component.scss
@@ -0,0 +1,247 @@
+@import '../../assets/styles/base/colors';
+@import '../../assets/styles/base/variables';
+
+import-business-network {
+
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ overflow-y: auto;
+
+ &.deploy {
+ flex-direction: row;
+ height: inherit;
+ overflow-y: inherit;
+
+ div.choose-network {
+ margin-right: $space-large;
+
+ section {
+ & > div {
+ flex-basis: 70%;
+ padding: $space-large;
+ }
+
+ h3.title {
+ padding: $space-large;
+ }
+
+ h3.sub-title {
+ padding: 0 $space-large;
+ }
+
+ .information {
+ padding: $space-medium $space-large;
+ }
+ }
+
+ .sample-network-list-container {
+ background-color: $white;
+ padding: 0 $space-large;
+ }
+ }
+
+ div.chosen-network {
+ .image {
+ margin: 0 auto;
+ width: 50%;
+ padding-top: $space-large;
+ }
+
+ div.chosen-network-info {
+ box-shadow: 3px 6px 15px 0 rgba(0, 0, 0, 0.20);
+ width: 275px;
+ display: block;
+ padding: 0;
+ border-bottom: none;
+ }
+
+ div.deploy {
+ width: 50%;
+ margin: 0 auto;
+ display: block;
+ }
+ }
+ }
+
+ div.choose-network {
+ background-color: $white;
+ margin-right: 0;
+ flex: 1;
+
+ h2 {
+ padding: $space-large $space-large 0;
+ }
+
+ section {
+ display: flex;
+ border-bottom: 1px solid $fourth-highlight;
+
+ h3.title {
+ flex-basis: 30%;
+ text-transform: uppercase;
+ color: $second-highlight;
+ }
+
+ h3.sub-title {
+ padding: $space-medium $space-large;
+ }
+
+ p {
+ padding: 0 $space-large;
+ }
+
+ & > div {
+ flex-basis: initial;
+ }
+
+ .information {
+
+ & > * {
+ display: flex;
+ align-items: baseline;
+
+ & > * {
+ flex-basis: 50%;
+ }
+
+ & > *:last-child {
+ width: inherit;
+ }
+ }
+
+ // description property
+ & > *:last-child {
+ margin-top: $space-medium;
+
+ & > * {
+ vertical-align: middle;
+ height: 100%;
+ }
+ }
+ }
+
+ .sample-network-list-container {
+
+ background-color: $fourth-highlight;
+ padding: $space-large;
+
+ .sample-network-list {
+ display: flex;
+ flex-wrap: wrap;
+ margin: $space-medium 0;
+
+ file-importer.sample-network-list-item {
+ &:hover {
+ border: 1px dashed $second-highlight;
+ }
+ }
+
+ .sample-network-list-item {
+ background-color: $white;
+ border: 1px solid $fourth-highlight;
+ padding: $space-smedium;
+ text-align: center;
+ margin-right: $space-smedium;
+ margin-bottom: $space-smedium;
+ width: 150px;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-end;
+ position: relative;
+
+ &.file-importer {
+ svg.ibm-icon {
+ width: 100px;
+ height: 100px;
+ margin-bottom: $space-large;
+ }
+ }
+
+ &.selected-network {
+ border-color: $second-highlight;
+ }
+
+ &:hover {
+ border-color: $second-highlight;
+ }
+
+ &.drag {
+ border: 1px dashed $second-highlight;
+ }
+
+ .sample-network-name {
+ margin-top: $space-medium;
+ flex-basis: 20%;
+ }
+
+ button.close-dropped {
+ position: absolute;
+ top: -18px;
+ right: -9px;
+
+ svg {
+ fill: $first-highlight;
+ width: $space-medium;
+ height: $space-medium;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ div.chosen-network {
+ .replace-message {
+ padding: $space-large;
+ }
+
+ div.chosen-network-info {
+ display: flex;
+ background-color: $white;
+ margin-bottom: $space-large;
+ padding: $space-large $space-large 0 $space-large;
+ border-bottom: 1px solid $fourth-highlight;
+
+ .animated-image {
+ width: 125px;
+ height: 125px;
+ }
+
+ section {
+ &:first-child {
+ padding-top: $space-large
+ }
+
+ &:last-child {
+ padding-bottom: $space-large;
+ }
+
+ padding: $space-medium $space-large;
+ text-align: center;
+
+ .title {
+ color: $secondary-text;
+ text-transform: uppercase;
+ }
+
+ .network-info {
+ color: $secondary-text;
+
+ span {
+ display: inline-block;
+ }
+ }
+
+ }
+ }
+
+ div.deploy {
+ display: flex;
+ justify-content: flex-end;
+ margin-bottom: $space-large;
+ margin-right: $space-large;
+ }
+ }
+}
diff --git a/packages/composer-playground/src/app/editor/import/import.component.spec.ts b/packages/composer-playground/src/app/import/import.component.spec.ts
similarity index 61%
rename from packages/composer-playground/src/app/editor/import/import.component.spec.ts
rename to packages/composer-playground/src/app/import/import.component.spec.ts
index 71100b41d5..362bd0fd6f 100644
--- a/packages/composer-playground/src/app/editor/import/import.component.spec.ts
+++ b/packages/composer-playground/src/app/import/import.component.spec.ts
@@ -9,15 +9,16 @@ import { By } from '@angular/platform-browser';
import { ImportComponent } from './import.component';
-import { AdminService } from '../../services/admin.service';
-import { ClientService } from '../../services/client.service';
-import { SampleBusinessNetworkService } from '../../services/samplebusinessnetwork.service';
+import { AdminService } from '../services/admin.service';
+import { ClientService } from '../services/client.service';
+import { SampleBusinessNetworkService } from '../services/samplebusinessnetwork.service';
import { NgbActiveModal, NgbModal } from '@ng-bootstrap/ng-bootstrap';
-import { AlertService } from '../../basic-modals/alert.service';
+import { AlertService } from '../basic-modals/alert.service';
import { BusinessNetworkDefinition, ClassDeclaration } from 'composer-common';
import * as sinon from 'sinon';
import * as chai from 'chai';
+import { ConnectionProfileService } from '../services/connectionprofile.service';
let should = chai.should();
@@ -80,21 +81,16 @@ describe('ImportComponent', () => {
let mockAdminService;
let mockAlertService;
let mockClientService;
- let mockActiveModal;
let mockNgbModal;
-
- const EMPTY_NETWORK = {
- name: 'Empty Business Network',
- description: 'Start from scratch with a blank business network'
- };
+ let mockConnectionProfileService;
beforeEach(() => {
mockBusinessNetworkService = sinon.createStubInstance(SampleBusinessNetworkService);
mockAdminService = sinon.createStubInstance(AdminService);
mockAlertService = sinon.createStubInstance(AlertService);
mockClientService = sinon.createStubInstance(ClientService);
- mockActiveModal = sinon.createStubInstance(NgbActiveModal);
mockNgbModal = sinon.createStubInstance(NgbModal);
+ mockConnectionProfileService = sinon.createStubInstance(ConnectionProfileService);
mockAlertService.errorStatus$ = {
next: sinon.stub()
@@ -111,9 +107,9 @@ describe('ImportComponent', () => {
{provide: SampleBusinessNetworkService, useValue: mockBusinessNetworkService},
{provide: AdminService, useValue: mockAdminService},
{provide: ClientService, useValue: mockClientService},
- {provide: NgbActiveModal, useValue: mockActiveModal},
{provide: AlertService, useValue: mockAlertService},
- {provide: NgbModal, useValue: mockNgbModal}]
+ {provide: NgbModal, useValue: mockNgbModal},
+ {provide: ConnectionProfileService, useValue: mockConnectionProfileService}],
});
sandbox = sinon.sandbox.create();
@@ -131,33 +127,6 @@ describe('ImportComponent', () => {
sandbox.restore();
});
- describe('currentBusinessNetwork', () => {
- let mockBusinessNetworkDefinition;
- let stub1 = sinon.createStubInstance(ClassDeclaration);
- beforeEach(() => {
- stub1.isAbstract.returns(true);
- stub1.isSystemType.returns(false);
-
- mockBusinessNetworkDefinition = sinon.createStubInstance(BusinessNetworkDefinition);
- mockBusinessNetworkDefinition.getModelManager.returns({
- getAssetDeclarations: () => {
- return [stub1];
- },
- getParticipantDeclarations: () => {
- return [stub1];
- },
- getTransactionDeclarations: () => {
- return [stub1];
- }
- });
- });
-
- it('should set the correct values for _currentBusinessNetwork', () => {
- component['currentBusinessNetwork'] = mockBusinessNetworkDefinition;
- component['currentAssets'].should.deep.equal([]);
- });
- });
-
describe('ngInit', () => {
let onShowMock;
@@ -182,14 +151,18 @@ describe('ImportComponent', () => {
describe('onShow', () => {
it('should get the list of sample networks', fakeAsync(() => {
- mockBusinessNetworkService.getSampleList.returns(Promise.resolve([{name: 'modelOne'}]));
+ let selectNetworkStub = sinon.stub(component, 'selectNetwork');
+ let addEmptyNetworkOption = sinon.stub(component, 'addEmptyNetworkOption').returns([{name: 'empty'}, {name: 'modelOne'}, {name: 'modelTwo'}]);
+ mockBusinessNetworkService.getSampleList.returns(Promise.resolve([{name: 'modelTwo'}, {name: 'modelOne'}]));
component.onShow();
- component['gitHubInProgress'].should.equal(true);
+ component['npmInProgress'].should.equal(true);
tick();
- component['gitHubInProgress'].should.equal(false);
- component['sampleNetworks'].should.deep.equal([EMPTY_NETWORK, {name: 'modelOne'}]);
+ addEmptyNetworkOption.should.have.been.calledWith([{name: 'modelTwo'}, {name: 'modelOne'}]);
+ selectNetworkStub.should.have.been.calledWith({name: 'modelOne'});
+ component['npmInProgress'].should.equal(false);
+ component['sampleNetworks'].should.deep.equal([{name: 'empty'}, {name: 'modelOne'}, {name: 'modelTwo'}]);
}));
it('should handle error', fakeAsync(() => {
@@ -197,10 +170,10 @@ describe('ImportComponent', () => {
component.onShow();
- component['gitHubInProgress'].should.equal(true);
+ component['npmInProgress'].should.equal(true);
tick();
- component['gitHubInProgress'].should.equal(false);
+ component['npmInProgress'].should.equal(false);
mockAlertService.errorStatus$.next.should.have.been.called;
}));
@@ -253,7 +226,16 @@ describe('ImportComponent', () => {
});
it('should read a file', fakeAsync(() => {
- mockClientService.getBusinessNetworkFromArchive.returns(Promise.resolve({network: 'mockNetwork'}));
+ let metaDataMock = {
+ getPackageJson: sinon.stub().returns({json: 'some json'})
+ };
+
+ let businessNetworkMock = {
+ network: 'mockNetwork',
+ getMetadata: sinon.stub().returns(metaDataMock)
+ };
+
+ mockClientService.getBusinessNetworkFromArchive.returns(Promise.resolve(businessNetworkMock));
mockDragDropComponent.fileDragDropFileAccepted.emit(file);
@@ -264,9 +246,10 @@ describe('ImportComponent', () => {
tick();
mockClientService.getBusinessNetworkFromArchive.should.have.been.called;
-
- component['currentBusinessNetwork'].should.deep.equal({network: 'mockNetwork'});
- component['expandInput'].should.equal(true);
+ component['currentBusinessNetwork'].network.should.equal('mockNetwork');
+ component['expandInput'].should.equal(false);
+ component['chosenNetwork'].should.deep.equal({json: 'some json'});
+ component['sampleDropped'].should.equal(true);
}));
it('should handle error', fakeAsync(() => {
@@ -307,116 +290,145 @@ describe('ImportComponent', () => {
});
describe('deploy', () => {
- it('should deploy a business network from npm', fakeAsync(() => {
-
- let deployNpmMock = sinon.stub(component, 'deployFromNpm').returns(Promise.resolve());
+ let finishedSampleImportSpy;
+ beforeEach(() => {
mockNgbModal.open = sinon.stub().returns({
componentInstance: {},
result: Promise.resolve(true)
});
+ finishedSampleImportSpy = sinon.spy(component.finishedSampleImport, 'emit');
+ });
+
+ it('should deploy a business network', fakeAsync(() => {
+ component['currentBusinessNetwork'] = {network: 'my network'};
+ component['networkName'] = 'newNetwork';
+ component['networkDescription'] = 'myDescription';
+ component['deployNetwork'] = true;
+
+ component.finishedSampleImport.subscribe((result) => {
+ result.should.deep.equal({deployed: true});
+ });
+
component.deploy();
tick();
- deployNpmMock.should.have.been.called;
+ mockBusinessNetworkService.deployBusinessNetwork.should.have.been.calledWith({network: 'my network'}, 'newNetwork', 'myDescription');
+
+ mockNgbModal.open.should.not.have.been.called;
component['deployInProgress'].should.equal(false);
- mockActiveModal.close.should.have.been.called;
+
+ finishedSampleImportSpy.should.have.been.calledWith({deployed: true});
}));
- it('should deploy a business network from business network', fakeAsync(() => {
+ it('should update a business network from business network', fakeAsync(() => {
+ component['deployNetwork'] = false;
+ component['currentBusinessNetwork'] = {network: 'my network'};
+ mockBusinessNetworkService.deployBusinessNetwork.returns(Promise.resolve());
- mockNgbModal.open = sinon.stub().returns({
- componentInstance: {},
- result: Promise.resolve(true)
+ component.finishedSampleImport.subscribe((result) => {
+ result.should.deep.equal({deployed: true});
});
- component['deployNetwork'] = true;
- component['currentBusinessNetwork'] = {network: 'my network', getName : sinon.stub()};
- mockBusinessNetworkService.deployBusinessNetwork.returns(Promise.resolve());
-
component.deploy();
tick();
- mockBusinessNetworkService.deployBusinessNetwork.should.have.been.calledWith({network: 'my network', getName : sinon.match.func}, true);
+ mockNgbModal.open.should.have.been.called;
+
+ mockBusinessNetworkService.updateBusinessNetwork.should.have.been.calledWith({network: 'my network'});
component['deployInProgress'].should.equal(false);
- mockActiveModal.close.should.have.been.called;
+ finishedSampleImportSpy.should.have.been.calledWith({deployed: true});
}));
- it('should update a business network from business network', fakeAsync(() => {
+ it('should do nothing if not replace', fakeAsync(() => {
+ component['deployNetwork'] = false;
+ component['currentBusinessNetwork'] = {network: 'my network'};
mockNgbModal.open = sinon.stub().returns({
componentInstance: {},
- result: Promise.resolve(true)
+ result: Promise.resolve(false)
});
- component['deployNetwork'] = false;
- component['currentBusinessNetwork'] = {network: 'my network', getName : sinon.stub()};
- mockBusinessNetworkService.deployBusinessNetwork.returns(Promise.resolve());
+ component.finishedSampleImport.subscribe((result) => {
+ result.should.deep.equal({deployed: false});
+ });
component.deploy();
tick();
- mockBusinessNetworkService.deployBusinessNetwork.should.have.been.calledWith({network: 'my network', getName : sinon.match.func}, false);
+ mockNgbModal.open.should.have.been.called;
+
+ mockBusinessNetworkService.updateBusinessNetwork.should.not.have.been.called;
+ mockBusinessNetworkService.deployBusinessNetwork.should.not.have.been.called;
component['deployInProgress'].should.equal(false);
- mockActiveModal.close.should.have.been.called;
+ finishedSampleImportSpy.should.have.been.calledWith({deployed: false});
}));
it('should handle error', fakeAsync(() => {
+ component['deployNetwork'] = true;
+ component['currentBusinessNetwork'] = {network: 'my network'};
+ mockBusinessNetworkService.deployBusinessNetwork.returns(Promise.reject('some error'));
- mockNgbModal.open = sinon.stub().returns({
- result: Promise.resolve(true),
- componentInstance: {}
+ component.finishedSampleImport.subscribe((result) => {
+ result.should.deep.equal({deployed: false, error: 'some error'});
});
- component['currentBusinessNetwork'] = {network: 'my network', getName : sinon.stub()};
- mockBusinessNetworkService.deployBusinessNetwork.returns(Promise.reject({message: 'some error'}));
-
- component.deploy();
+ let deployPromise = component.deploy();
tick();
- mockBusinessNetworkService.deployBusinessNetwork.should.have.been.calledWith({network: 'my network', getName : sinon.match.func});
+ mockBusinessNetworkService.deployBusinessNetwork.should.have.been.calledWith({network: 'my network'});
component['deployInProgress'].should.equal(false);
- component.modalService.open.should.have.been.called;
+ finishedSampleImportSpy.should.have.been.calledWith({deployed: false, error: 'some error'});
+ mockAlertService.errorStatus$.next.should.have.been.calledWith('some error');
}));
});
- describe('deployFromNpm', () => {
- it('should get sample from npm and deploy', () => {
- component['sampleNetworks'] = [{name: 'bob'}, {name: 'fred'}];
- component['chosenNetwork'] = 'fred';
+ describe('deployEmptyNetwork', () => {
+ beforeEach(() => {
+ mockBusinessNetworkService.createNewBusinessDefinition.returns({network: 'myNetwork'});
+ });
+
+ it('should create the empty business network if chosen', fakeAsync(() => {
+
component['deployNetwork'] = true;
+ component['networkName'] = 'myName';
+ component['networkDescription'] = 'myDescription';
- component.deployFromNpm();
+ mockBusinessNetworkService.createNewBusinessDefinition.returns({network : 'myNetwork'});
- mockBusinessNetworkService.deployChosenSample.should.have.been.calledWith({name: 'fred'}, true);
- });
+ component.deployEmptyNetwork();
- it('should get sample from npm and update', () => {
- component['sampleNetworks'] = [{name: 'bob'}, {name: 'fred'}];
- component['chosenNetwork'] = 'fred';
- component['deployNetwork'] = false;
+ tick();
+ mockBusinessNetworkService.createNewBusinessDefinition.should.have.been.calledWith('', '', sinon.match.object, sinon.match.string);
+ component['currentBusinessNetwork'].should.deep.equal({network : 'myNetwork'});
+ }));
+ });
- component.deployFromNpm();
+ describe('selectNetwork', () => {
+ it('should select the network', fakeAsync(() => {
+ mockBusinessNetworkService.getChosenSample.returns(Promise.resolve({network: 'myNetwork'}));
+ component.selectNetwork('bob');
- mockBusinessNetworkService.deployChosenSample.should.have.been.calledWith({name: 'fred'}, false);
- });
+ tick();
+
+ component['chosenNetwork'];
+ component['currentBusinessNetwork'].should.deep.equal({network: 'myNetwork'});
+ }));
- it('should deploy the empty business network if chosen', () => {
- component['sampleNetworks'] = [EMPTY_NETWORK];
- component['chosenNetwork'] = EMPTY_NETWORK.name;
- component['owner'] = 'my owner';
- component['repository'] = 'my repository';
- // TODO: figure out why this causes Error: Cannot find module "."
- // component.deployFromGitHub();
- // mockBusinessNetworkService.deploySample.should.have.been.calledWith('my owner', 'my repository', EMPTY_NETWORK);
+ it('should select the empty network', () => {
+ let empty = sinon.stub(component, 'deployEmptyNetwork');
+
+ component.selectNetwork({name : 'Empty Business Network'});
+
+ empty.should.have.been.called;
});
});
@@ -430,11 +442,38 @@ describe('ImportComponent', () => {
let INPUT_NETWORKS = [{name: BASIC_SAMPLE}, {name: BAR}, {name: FOO}];
let result = component.addEmptyNetworkOption(INPUT_NETWORKS);
result.length.should.equal(4);
- result[0].name.should.equal(EMPTY_NETWORK.name);
+ result[0].name.should.equal('Empty Business Network');
result[1].name.should.equal(BASIC_SAMPLE);
result[2].name.should.equal(BAR);
result[3].name.should.equal(FOO);
});
});
+ describe('closeSample', (() => {
+ it('should set the dragged sample back to empty', () => {
+ let selectStub = sinon.stub(component, 'selectNetwork');
+ component['sampleDropped'] = true;
+
+ component['sampleNetworks'] = [{network: 'one'}, {network: 'two'}];
+
+ component.closeSample();
+
+ component['sampleDropped'].should.equal(false);
+ selectStub.should.have.been.calledWith({network: 'two'});
+ });
+ }));
+
+ describe('cancel', () => {
+ it('should close importing', () => {
+ let emitSpy = sinon.spy(component.finishedSampleImport, 'emit');
+
+ component.finishedSampleImport.subscribe((result) => {
+ result.should.deep.equal({deployed: false});
+ });
+
+ component.cancel();
+
+ emitSpy.should.have.been.calledWith({deployed: false});
+ });
+ });
});
diff --git a/packages/composer-playground/src/app/import/import.component.ts b/packages/composer-playground/src/app/import/import.component.ts
new file mode 100644
index 0000000000..25ecf16361
--- /dev/null
+++ b/packages/composer-playground/src/app/import/import.component.ts
@@ -0,0 +1,242 @@
+import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+
+import { AdminService } from '../services/admin.service';
+import { ClientService } from '../services/client.service';
+import { SampleBusinessNetworkService } from '../services/samplebusinessnetwork.service';
+import { AlertService } from '../basic-modals/alert.service';
+import { ReplaceComponent } from '../basic-modals/replace-confirm';
+
+import { BusinessNetworkDefinition } from 'composer-common';
+import { ConnectionProfileService } from '../services/connectionprofile.service';
+
+@Component({
+ selector: 'import-business-network',
+ templateUrl: './import.component.html',
+ styleUrls: ['./import.component.scss'.toString()]
+})
+export class ImportComponent implements OnInit {
+
+ // choose whether to deploy or update the business network
+ @Input() deployNetwork: boolean;
+ @Output() finishedSampleImport = new EventEmitter();
+
+ private deployInProgress: boolean = false;
+ private npmInProgress: boolean = true;
+ private sampleNetworks = [];
+ private primaryNetworkNames = ['basic-sample-network', 'carauction-network'];
+ private chosenNetwork = null;
+ private expandInput: boolean = false;
+ private sampleDropped: boolean = false;
+
+ private maxFileSize: number = 5242880;
+ private supportedFileTypes: string[] = ['.bna'];
+
+ private currentBusinessNetwork = null;
+ private currentConnectionProfile: string = null;
+ private currentBusinessNetworkPromise: Promise;
+ private networkName: string;
+ private networkDescription: string;
+
+ private NAME = 'Empty Business Network';
+ private DESC = 'Start from scratch with a blank business network';
+ private EMPTY_BIZNET = {name: this.NAME, description: this.DESC};
+
+ constructor(private clientService: ClientService,
+ public modalService: NgbModal,
+ private sampleBusinessNetworkService: SampleBusinessNetworkService,
+ private alertService: AlertService,
+ private adminService: AdminService,
+ private connectionProfileService: ConnectionProfileService) {
+
+ }
+
+ ngOnInit(): Promise {
+ this.currentBusinessNetwork = null;
+ this.currentConnectionProfile = this.connectionProfileService.getCurrentConnectionProfile();
+
+ return this.adminService.connectWithoutNetwork(false)
+ .then(() => {
+ this.onShow();
+ });
+ }
+
+ onShow(): Promise {
+ this.npmInProgress = true;
+ return this.sampleBusinessNetworkService.getSampleList()
+ .then((sampleNetworkList) => {
+ this.sampleNetworks = this.addEmptyNetworkOption(sampleNetworkList);
+ this.selectNetwork(this.sampleNetworks[1]);
+ this.npmInProgress = false;
+
+ })
+ .catch((error) => {
+ this.npmInProgress = false;
+ this.alertService.errorStatus$.next(error);
+ });
+ }
+
+ selectNetwork(network): void {
+ this.chosenNetwork = network;
+ if (this.chosenNetwork.name !== this.NAME) {
+ this.currentBusinessNetworkPromise = this.sampleBusinessNetworkService.getChosenSample(this.chosenNetwork).then((result) => {
+ this.currentBusinessNetwork = result;
+ return result;
+ });
+ } else {
+ this.deployEmptyNetwork();
+ }
+
+ }
+
+ removeFile() {
+ this.expandInput = false;
+ this.currentBusinessNetwork = null;
+ }
+
+ deploy() {
+ let replacePromise;
+
+ let deployed: boolean = true;
+
+ if (this.deployNetwork) {
+ replacePromise = Promise.resolve(true);
+ } else {
+ const confirmModalRef = this.modalService.open(ReplaceComponent);
+ confirmModalRef.componentInstance.mainMessage = 'Your Business Network Definition currently in the Playground will be removed & replaced.';
+ confirmModalRef.componentInstance.supplementaryMessage = 'Please ensure that you have exported any current model files in the Playground.';
+ replacePromise = confirmModalRef.result;
+ }
+
+ replacePromise.then((result) => {
+ if (result === true) {
+ this.deployInProgress = true;
+ let deployPromise;
+ if (this.deployNetwork) {
+ return this.sampleBusinessNetworkService.deployBusinessNetwork(this.currentBusinessNetwork, this.networkName, this.networkDescription);
+ } else {
+ return this.sampleBusinessNetworkService.updateBusinessNetwork(this.currentBusinessNetwork);
+ }
+ } else {
+ deployed = false;
+ }
+ })
+ .then(() => {
+ this.deployInProgress = false;
+ this.finishedSampleImport.emit({deployed: deployed});
+ })
+ .catch((error) => {
+ this.deployInProgress = false;
+ this.alertService.errorStatus$.next(error);
+ this.finishedSampleImport.emit({deployed: false, error: error});
+ });
+
+ return replacePromise;
+ }
+
+ deployEmptyNetwork(): void {
+ let readme = 'This is the readme file for the Business Network Definition created in Playground';
+ let packageJson = {
+ name: 'unnamed-network',
+ author: 'author',
+ description: 'Empty Business Network',
+ version: '0.0.1',
+ devDependencies: {
+ 'browserfs': '^1.2.0',
+ 'chai': '^3.5.0',
+ 'composer-admin': 'latest',
+ 'composer-cli': 'latest',
+ 'composer-client': 'latest',
+ 'composer-connector-embedded': 'latest',
+ 'eslint': '^3.6.1',
+ 'istanbul': '^0.4.5',
+ 'jsdoc': '^3.4.1',
+ 'mkdirp': '^0.5.1',
+ 'mocha': '^3.2.0',
+ 'moment': '^2.17.1'
+ },
+ keywords: [],
+ license: 'Apache 2.0',
+ repository: {
+ type: 'e.g. git',
+ url: 'URL'
+ },
+ scripts: {
+ deploy: './scripts/deploy.sh',
+ doc: 'jsdoc --pedantic --recurse -c jsdoc.conf',
+ lint: 'eslint .',
+ postlicchk: 'npm run doc',
+ postlint: 'npm run licchk',
+ prepublish: 'mkdirp ./dist && composer archive create --sourceType dir --sourceName . -a ./dist/unnamed-network.bna',
+ pretest: 'npm run lint',
+ test: 'mocha --recursive'
+ }
+ };
+
+ this.currentBusinessNetworkPromise = Promise.resolve().then(() => {
+ this.currentBusinessNetwork = this.sampleBusinessNetworkService.createNewBusinessDefinition('', '', packageJson, readme);
+ return this.currentBusinessNetwork;
+ });
+ }
+
+ closeSample() {
+ this.sampleDropped = false;
+ this.selectNetwork(this.sampleNetworks[1]);
+ }
+
+ cancel() {
+ this.finishedSampleImport.emit({deployed: false});
+ }
+
+ addEmptyNetworkOption(networks: any[]): any[] {
+
+ let newOrder = [];
+
+ // Append new network option to the list.
+ newOrder.push(this.EMPTY_BIZNET);
+
+ for (let i = 0; i < networks.length; i++) {
+ newOrder.push(networks[i]);
+ }
+
+ return newOrder;
+ }
+
+ private fileDetected() {
+ this.expandInput = true;
+ }
+
+ private fileLeft() {
+ this.expandInput = false;
+
+ }
+
+ private fileAccepted(file: File): void {
+ let fileReader = new FileReader();
+ fileReader.onload = () => {
+ let dataBuffer = Buffer.from(fileReader.result);
+ this.currentBusinessNetworkPromise = this.clientService.getBusinessNetworkFromArchive(dataBuffer)
+ .then((businessNetwork) => {
+ this.chosenNetwork = businessNetwork.getMetadata().getPackageJson();
+ this.currentBusinessNetwork = businessNetwork;
+ // needed for if browse file
+ this.sampleDropped = true;
+ this.expandInput = false;
+ return businessNetwork;
+ })
+ .catch((error) => {
+ let failMessage = 'Cannot import an invalid Business Network Definition. Found ' + error.toString();
+ this.alertService.errorStatus$.next(failMessage);
+ this.expandInput = false;
+ return null;
+ });
+ };
+
+ fileReader.readAsArrayBuffer(file);
+ }
+
+ private fileRejected(reason: string): void {
+ this.alertService.errorStatus$.next(reason);
+ this.expandInput = false;
+ }
+}
diff --git a/packages/composer-playground/src/app/import/import.module.ts b/packages/composer-playground/src/app/import/import.module.ts
new file mode 100644
index 0000000000..ec061a7490
--- /dev/null
+++ b/packages/composer-playground/src/app/import/import.module.ts
@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+
+import { ImportComponent } from './import.component';
+import { FileImporterModule } from '../common/file-importer/file-importer.module';
+import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
+
+@NgModule({
+ imports: [CommonModule, FormsModule, FileImporterModule, PerfectScrollbarModule],
+ entryComponents: [ImportComponent],
+ declarations: [ImportComponent],
+ exports : [ImportComponent]
+})
+
+export class ImportModule {
+}
diff --git a/packages/composer-playground/src/app/editor/import/index.ts b/packages/composer-playground/src/app/import/index.ts
similarity index 100%
rename from packages/composer-playground/src/app/editor/import/index.ts
rename to packages/composer-playground/src/app/import/index.ts
diff --git a/packages/composer-playground/src/app/login/login.component.html b/packages/composer-playground/src/app/login/login.component.html
index d41a7d5319..8c8db5f584 100644
--- a/packages/composer-playground/src/app/login/login.component.html
+++ b/packages/composer-playground/src/app/login/login.component.html
@@ -1,4 +1,4 @@
-
+
+
Identities for {{connectionProfile.name === '$default' ? 'Web Browser' : connectionProfile.name }}
-
-
-
+
diff --git a/packages/composer-playground/src/app/login/login.component.scss b/packages/composer-playground/src/app/login/login.component.scss
index 27ecaa3b38..cc99322663 100644
--- a/packages/composer-playground/src/app/login/login.component.scss
+++ b/packages/composer-playground/src/app/login/login.component.scss
@@ -5,9 +5,13 @@ app-login {
width: 100vw;
background-color: $fourth-highlight;
+ section.header {
+ padding: $space-large $space-large $space-medium $space-large;
+ }
+
section.main-view {
overflow-y: auto;
- height: calc(100vh - 63px - 70px);
+ height: calc(100vh - 63px - 95px - 55px);
padding: $space-medium $space-large;
div.connection-profile:first-child {
@@ -43,9 +47,9 @@ app-login {
}
}
- section.edit-connection-profile {
- padding: $space-large ;
- height: calc(100vh - 63px);
+ section.sub-view {
+ padding: $space-large;
+ height: calc(100vh - 63px - 55px);
overflow-y: auto;
.header {
diff --git a/packages/composer-playground/src/app/login/login.component.spec.ts b/packages/composer-playground/src/app/login/login.component.spec.ts
index 1ed8fa4ca1..8aa1080f8e 100644
--- a/packages/composer-playground/src/app/login/login.component.spec.ts
+++ b/packages/composer-playground/src/app/login/login.component.spec.ts
@@ -78,11 +78,15 @@ class MockConnectionProfileComponent {
}
@Component({
- selector: 'identity-card',
+ selector: 'import-business-network',
template: ''
})
-class MockIdentityCardComponent {
- @Input() identity: any;
+class MockImportComponent {
+
+ @Input()
+ public deployNetwork;
+ @Output()
+ public finishedSampleImport: EventEmitter = new EventEmitter();
}
@Component({
@@ -94,240 +98,287 @@ class MockFooterComponent {
}
describe(`LoginComponent`, () => {
+ @Component({
+ selector: 'identity-card',
+ template: ''
+ })
+ class MockIdentityCardComponent {
+ @Input() identity: any;
+ }
- let component: LoginComponent;
- let fixture: ComponentFixture;
-
- let mockAdminService;
- let mockIdentityService;
- let mockClientService;
- let mockConnectionProfileService;
- let mockInitializationService;
- let routerStub;
- let mockAlertService;
- let mockWalletService;
- let mockModal;
- let mockDrawer;
-
- beforeEach(() => {
-
- mockIdentityService = sinon.createStubInstance(IdentityService);
- mockClientService = sinon.createStubInstance(ClientService);
- mockConnectionProfileService = sinon.createStubInstance(ConnectionProfileService);
- mockAdminService = sinon.createStubInstance(AdminService);
- mockInitializationService = sinon.createStubInstance(InitializationService);
- mockAlertService = sinon.createStubInstance(AlertService);
- mockWalletService = sinon.createStubInstance(WalletService);
- mockDrawer = sinon.createStubInstance(DrawerService);
- mockModal = sinon.createStubInstance(NgbModal);
-
- routerStub = new RouterStub();
-
- mockAlertService.successStatus$ = {next: sinon.stub()};
- mockAlertService.busyStatus$ = {next: sinon.stub()};
- mockAlertService.errorStatus$ = {next: sinon.stub()};
-
- mockWalletService.removeFromWallet = sinon.stub().returns(Promise.resolve(true));
-
- TestBed.configureTestingModule({
- declarations: [
- LoginComponent,
- MockConnectionProfileComponent,
- MockIdentityCardComponent,
- MockFooterComponent
- ],
- providers: [
- {provide: IdentityService, useValue: mockIdentityService},
- {provide: ClientService, useValue: mockClientService},
- {provide: ConnectionProfileService, useValue: mockConnectionProfileService},
- {provide: Router, useValue: routerStub},
- {provide: AdminService, useValue: mockAdminService},
- {provide: InitializationService, useValue: mockInitializationService},
- {provide: AlertService, useValue: mockAlertService},
- {provide: WalletService, useValue: mockWalletService},
- {provide: DrawerService, useValue: mockDrawer},
- {provide: NgbModal, useValue: mockModal}
- ]
- });
-
- fixture = TestBed.createComponent(LoginComponent);
+ describe(`LoginComponent`, () => {
+
+ let component: LoginComponent;
+ let fixture: ComponentFixture;
+
+ let mockAdminService;
+ let mockIdentityService;
+ let mockClientService;
+ let mockConnectionProfileService;
+ let mockInitializationService;
+ let routerStub;
+ let mockAlertService;
+ let mockWalletService;
+ let mockModal;
+ let mockDrawer;
+
+ beforeEach(() => {
+
+ mockIdentityService = sinon.createStubInstance(IdentityService);
+ mockClientService = sinon.createStubInstance(ClientService);
+ mockConnectionProfileService = sinon.createStubInstance(ConnectionProfileService);
+ mockAdminService = sinon.createStubInstance(AdminService);
+ mockInitializationService = sinon.createStubInstance(InitializationService);
+ mockAlertService = sinon.createStubInstance(AlertService);
+ mockWalletService = sinon.createStubInstance(WalletService);
+ mockDrawer = sinon.createStubInstance(DrawerService);
+ mockModal = sinon.createStubInstance(NgbModal);
+
+ routerStub = new RouterStub();
+
+ mockAlertService.successStatus$ = {next: sinon.stub()};
+ mockAlertService.busyStatus$ = {next: sinon.stub()};
+ mockAlertService.errorStatus$ = {next: sinon.stub()};
+
+ mockWalletService.removeFromWallet = sinon.stub().returns(Promise.resolve(true));
+
+ TestBed.configureTestingModule({
+ declarations: [
+ LoginComponent,
+ MockConnectionProfileComponent,
+ MockIdentityCardComponent,
+ MockImportComponent,
+ MockFooterComponent
+ ],
+ providers: [
+ {provide: IdentityService, useValue: mockIdentityService},
+ {provide: ClientService, useValue: mockClientService},
+ {provide: ConnectionProfileService, useValue: mockConnectionProfileService},
+ {provide: Router, useValue: routerStub},
+ {provide: AdminService, useValue: mockAdminService},
+ {provide: InitializationService, useValue: mockInitializationService},
+ {provide: AlertService, useValue: mockAlertService},
+ {provide: WalletService, useValue: mockWalletService},
+ {provide: DrawerService, useValue: mockDrawer},
+ {provide: NgbModal, useValue: mockModal}
+ ]
+ });
- component = fixture.componentInstance;
- });
+ fixture = TestBed.createComponent(LoginComponent);
- describe('ngOnInit', () => {
- it('should create the component', () => {
- component.should.be.ok;
+ component = fixture.componentInstance;
});
- it('should load identities', fakeAsync(() => {
- mockInitializationService.initialize.returns(Promise.resolve());
- let loadConnectionProfilesStub = sinon.stub(component, 'loadConnectionProfiles');
- component.ngOnInit();
-
- tick();
+ describe('ngOnInit', () => {
+ it('should create the component', () => {
+ component.should.be.ok;
+ });
- mockInitializationService.initialize.should.have.been.called;
- loadConnectionProfilesStub.should.have.been.called;
- }));
- });
+ it('should load identities', fakeAsync(() => {
+ mockInitializationService.initialize.returns(Promise.resolve());
+ let loadConnectionProfilesStub = sinon.stub(component, 'loadConnectionProfiles');
+ component.ngOnInit();
- describe('loadConnectionProfiles', () => {
- it('should load the connection profile', fakeAsync(() => {
- mockConnectionProfileService.getAllProfiles.returns(Promise.resolve({myProfile: {name: 'myProfile'}}));
+ tick();
- mockIdentityService.getIdentities.returns(Promise.resolve(['bob']));
+ mockInitializationService.initialize.should.have.been.called;
+ loadConnectionProfilesStub.should.have.been.called;
+ }));
+ });
- component.loadConnectionProfiles();
+ describe('loadConnectionProfiles', () => {
+ it('should load the connection profile', fakeAsync(() => {
+ mockConnectionProfileService.getAllProfiles.returns(Promise.resolve({myProfile: {name: 'myProfile'}}));
- tick();
+ mockIdentityService.getIdentities.returns(Promise.resolve(['bob']));
- mockConnectionProfileService.getAllProfiles.should.have.been.called;
+ component.loadConnectionProfiles();
- mockIdentityService.getIdentities.should.have.been.calledWith('myProfile');
+ tick();
- component['connectionProfiles'].should.deep.equal([{
- name: 'myProfile',
- profile: {name: 'myProfile'},
- default: false,
- identities: [{
- userId: 'bob',
- businessNetwork: 'org-acme-biznet'
- }]
- }]);
- }));
- });
+ mockConnectionProfileService.getAllProfiles.should.have.been.called;
- describe('changeIdentity', () => {
- it('should change identity', fakeAsync(() => {
- mockAdminService.list.returns(Promise.resolve(['myNetwork']));
- mockClientService.ensureConnected.returns(Promise.resolve());
+ mockIdentityService.getIdentities.should.have.been.calledWith('myProfile');
- component.changeIdentity('myProfile', 'bob');
+ component['connectionProfiles'].should.deep.equal([{
+ name: 'myProfile',
+ profile: {name: 'myProfile'},
+ default: false,
+ identities: [{
+ userId: 'bob',
+ businessNetwork: 'org-acme-biznet'
+ }]
+ }]);
+ }));
+ });
- tick();
+ describe('changeIdentity', () => {
+ it('should change identity', fakeAsync(() => {
+ mockAdminService.list.returns(Promise.resolve(['myNetwork']));
+ mockClientService.ensureConnected.returns(Promise.resolve());
- mockConnectionProfileService.setCurrentConnectionProfile.should.have.been.calledWith('myProfile');
- mockIdentityService.setCurrentIdentity.should.have.been.calledWith('bob');
- mockAdminService.list.should.have.been.called;
- mockClientService.ensureConnected.should.have.been.calledWith('myNetwork', true);
+ component.changeIdentity('myProfile', 'bob');
- mockIdentityService.setLoggedIn.should.have.been.calledWith(true);
- routerStub.navigate.should.have.been.calledWith(['editor']);
- }));
+ tick();
- it('should handle error', fakeAsync(() => {
- mockAdminService.list.returns(Promise.reject('some error'));
- mockClientService.ensureConnected.returns(Promise.resolve());
+ mockConnectionProfileService.setCurrentConnectionProfile.should.have.been.calledWith('myProfile');
+ mockIdentityService.setCurrentIdentity.should.have.been.calledWith('bob');
+ mockAdminService.list.should.have.been.called;
+ mockClientService.ensureConnected.should.have.been.calledWith('myNetwork', true);
- component.changeIdentity('myProfile', 'bob');
+ mockIdentityService.setLoggedIn.should.have.been.calledWith(true);
+ routerStub.navigate.should.have.been.calledWith(['editor']);
+ }));
- tick();
+ it('should handle error', fakeAsync(() => {
+ mockAdminService.list.returns(Promise.reject('some error'));
+ mockClientService.ensureConnected.returns(Promise.resolve());
- mockConnectionProfileService.setCurrentConnectionProfile.should.have.been.calledWith('myProfile');
- mockIdentityService.setCurrentIdentity.should.have.been.calledWith('bob');
- mockAdminService.list.should.have.been.called;
- mockClientService.ensureConnected.should.not.have.been.called;
+ component.changeIdentity('myProfile', 'bob');
- mockIdentityService.setLoggedIn.should.not.have.been.called;
- routerStub.navigate.should.not.have.been.called;
+ tick();
- mockAlertService.errorStatus$.next.should.have.been.calledWith('some error');
- }));
- });
+ mockConnectionProfileService.setCurrentConnectionProfile.should.have.been.calledWith('myProfile');
+ mockIdentityService.setCurrentIdentity.should.have.been.calledWith('bob');
+ mockAdminService.list.should.have.been.called;
+ mockClientService.ensureConnected.should.not.have.been.called;
- describe('editConnectionProfile', () => {
- it('should edit the connection profile', () => {
- component.should.be.ok;
- component.editConnectionProfile('myProfile');
+ mockIdentityService.setLoggedIn.should.not.have.been.called;
+ routerStub.navigate.should.not.have.been.called;
- component['editingConectionProfile'].should.equal('myProfile');
+ mockAlertService.errorStatus$.next.should.have.been.calledWith('some error');
+ }));
});
- });
- describe('finishedEditingConnectionProfile', () => {
- it('should close editing connection profile screen', () => {
- let loadConnectionProfilesStub = sinon.stub(component, 'loadConnectionProfiles');
- component.finishedEditingConnectionProfile();
+ describe('editConnectionProfile', () => {
+ it('should edit the connection profile', () => {
+ component.should.be.ok;
+ component.editConnectionProfile('myProfile');
- should.not.exist(component['editingConectionProfile']);
- loadConnectionProfilesStub.should.have.been.called;
- });
- });
-
- describe('removeIdentity', () => {
- it('should open the delete-confirm modal', fakeAsync(() => {
- mockModal.open = sinon.stub().returns({
- componentInstance: {},
- result: Promise.resolve(0)
+ component['editingConectionProfile'].should.equal('myProfile');
});
+ });
- component.removeIdentity('profile', 'name');
- tick();
- mockModal.open.should.have.been.called;
- }));
+ describe('finishedEditingConnectionProfile', () => {
+ it('should close editing connection profile screen', () => {
+ let loadConnectionProfilesStub = sinon.stub(component, 'loadConnectionProfiles');
+ component.finishedEditingConnectionProfile();
- it('should open delete-confirm modal and handle error', fakeAsync(() => {
- mockModal.open = sinon.stub().returns({
- componentInstance: {},
- result: Promise.reject('some error')
+ should.not.exist(component['editingConectionProfile']);
+ loadConnectionProfilesStub.should.have.been.called;
});
+ });
- component.removeIdentity('profile', 'name');
- tick();
- mockAlertService.busyStatus$.next.should.have.been.called;
- mockAlertService.errorStatus$.next.should.have.been.called;
- }));
-
- it('should open delete-confirm modal and handle cancel', fakeAsync(() => {
- mockModal.open = sinon.stub().returns({
- componentInstance: {},
- result: Promise.reject(null)
- });
+ describe('removeIdentity', () => {
+ it('should open the delete-confirm modal', fakeAsync(() => {
+ mockModal.open = sinon.stub().returns({
+ componentInstance: {},
+ result: Promise.resolve(0)
+ });
+
+ component.removeIdentity('profile', 'name');
+ tick();
+ mockModal.open.should.have.been.called;
+ }));
+
+ it('should open delete-confirm modal and handle error', fakeAsync(() => {
+ mockModal.open = sinon.stub().returns({
+ componentInstance: {},
+ result: Promise.reject('some error')
+ });
+
+ component.removeIdentity('profile', 'name');
+ tick();
+ mockAlertService.busyStatus$.next.should.have.been.called;
+ mockAlertService.errorStatus$.next.should.have.been.called;
+ }));
+
+ it('should open delete-confirm modal and handle cancel', fakeAsync(() => {
+ mockModal.open = sinon.stub().returns({
+ componentInstance: {},
+ result: Promise.reject(null)
+ });
+
+ component.removeIdentity('profile', 'name');
+ tick();
+ mockAlertService.busyStatus$.next.should.not.have.been.called;
+ mockAlertService.errorStatus$.next.should.not.have.been.called;
+ }));
+
+ it('should refresh the connection profiles after successfully calling walletService.removeFromWallet()', fakeAsync(() => {
+ mockModal.open = sinon.stub().returns({
+ componentInstance: {},
+ result: Promise.resolve(true)
+ });
+
+ component.loadConnectionProfiles = sinon.stub();
+
+ component.removeIdentity('profile', 'name');
+ tick();
+
+ // check services called
+ component.loadConnectionProfiles.should.have.been.called;
+ mockAlertService.busyStatus$.next.should.have.been.called;
+ mockAlertService.successStatus$.next.should.have.been.called;
+
+ mockAlertService.errorStatus$.next.should.not.have.been.called;
+ }));
+
+ it('should handle errors when calling walletService.removeFromWallet()', fakeAsync(() => {
+ mockModal.open = sinon.stub().returns({
+ componentInstance: {},
+ result: Promise.resolve(true)
+ });
+
+ component.loadConnectionProfiles = sinon.stub();
+ mockWalletService.removeFromWallet = sinon.stub().returns(Promise.reject('some error'));
+
+ component.removeIdentity('profile', 'name');
+ tick();
+
+ // check services called
+ mockAlertService.busyStatus$.next.should.have.been.called;
+ mockAlertService.errorStatus$.next.should.have.been.called;
+
+ mockAlertService.successStatus$.next.should.not.have.been.called;
+ component.loadConnectionProfiles.should.not.have.been.called;
+ }));
+ });
- component.removeIdentity('profile', 'name');
- tick();
- mockAlertService.busyStatus$.next.should.not.have.been.called;
- mockAlertService.errorStatus$.next.should.not.have.been.called;
- }));
+ describe('closeSubView', () => {
+ it('should close the subview', () => {
+ component['showSubScreen'] = true;
+ component['showDeployNetwork'] = true;
+ component['editingConnectionProfile'] = {profile: 'myProfile'};
+ component.closeSubView();
- it('should refresh the connection profiles after successfully calling walletService.removeFromWallet()', fakeAsync(() => {
- mockModal.open = sinon.stub().returns({
- componentInstance: {},
- result: Promise.resolve(true)
+ component['showSubScreen'].should.equal(false);
+ should.not.exist(component['editingConectionProfile']);
+ component['showDeployNetwork'].should.equal(false);
});
+ });
- component.loadConnectionProfiles = sinon.stub();
-
- component.removeIdentity('profile', 'name');
- tick();
-
- // check services called
- component.loadConnectionProfiles.should.have.been.called;
- mockAlertService.busyStatus$.next.should.have.been.called;
- mockAlertService.successStatus$.next.should.have.been.called;
-
- mockAlertService.errorStatus$.next.should.not.have.been.called;
- }));
+ describe('deployNetwork', () => {
+ it('should deploy a new business network', () => {
+ component.deployNetwork({name: 'bob'});
+ mockConnectionProfileService.setCurrentConnectionProfile.should.have.been.calledWith('bob');
- it('should handle errors when calling walletService.removeFromWallet()', fakeAsync(() => {
- mockModal.open = sinon.stub().returns({
- componentInstance: {},
- result: Promise.resolve(true)
+ mockIdentityService.setCurrentIdentity.should.have.been.calledWith('admin');
+ component['showSubScreen'].should.equal(true);
+ component['showDeployNetwork'].should.equal(true);
});
+ });
- component.loadConnectionProfiles = sinon.stub();
- mockWalletService.removeFromWallet = sinon.stub().returns(Promise.reject('some error'));
-
- component.removeIdentity('profile', 'name');
- tick();
+ describe('finishedDeploying', () => {
+ it('should finish deploying', () => {
+ component['showSubScreen'] = true;
- // check services called
- mockAlertService.busyStatus$.next.should.have.been.called;
- mockAlertService.errorStatus$.next.should.have.been.called;
+ component['showDeployNetwork'] = true;
+ component.finishedDeploying();
- mockAlertService.successStatus$.next.should.not.have.been.called;
- component.loadConnectionProfiles.should.not.have.been.called;
- }));
+ component['showSubScreen'].should.equal(false);
+ component['showDeployNetwork'].should.equal(false);
+ });
+ });
});
});
diff --git a/packages/composer-playground/src/app/login/login.component.ts b/packages/composer-playground/src/app/login/login.component.ts
index 4101b37e33..fdd1fd1835 100644
--- a/packages/composer-playground/src/app/login/login.component.ts
+++ b/packages/composer-playground/src/app/login/login.component.ts
@@ -23,6 +23,8 @@ export class LoginComponent implements OnInit {
private connectionProfiles = [];
private editingConectionProfile = null;
+ private showSubScreen: boolean = false;
+ private showDeployNetwork: boolean = false;
constructor(private identityService: IdentityService,
private router: Router,
@@ -66,9 +68,9 @@ export class LoginComponent implements OnInit {
profile: connectionProfile,
default: key === '$default',
identities: identityList
+ });
});
});
- });
this.connectionProfiles = newConnectionProfiles;
});
@@ -92,14 +94,35 @@ export class LoginComponent implements OnInit {
}
editConnectionProfile(connectionProfile): void {
+ this.showSubScreen = true;
this.editingConectionProfile = connectionProfile;
}
finishedEditingConnectionProfile(): Promise {
+ this.showSubScreen = false;
delete this.editingConectionProfile;
return this.loadConnectionProfiles();
}
+ closeSubView(): void {
+ this.showSubScreen = false;
+ delete this.editingConectionProfile;
+ this.showDeployNetwork = false;
+ }
+
+ deployNetwork(connectionProfile) {
+ this.connectionProfileService.setCurrentConnectionProfile(connectionProfile.name);
+ // TODO this needs to be done dynmaically
+ this.identityService.setCurrentIdentity('admin');
+ this.showSubScreen = true;
+ this.showDeployNetwork = true;
+ }
+
+ finishedDeploying() {
+ this.showSubScreen = false;
+ this.showDeployNetwork = false;
+ }
+
removeIdentity(connectionProfile, userId): void {
const confirmModalRef = this.modalService.open(DeleteComponent);
confirmModalRef.componentInstance.headerMessage = 'Remove ID Card';
diff --git a/packages/composer-playground/src/app/login/login.module.ts b/packages/composer-playground/src/app/login/login.module.ts
index 4fe3ab9173..beee766b8a 100644
--- a/packages/composer-playground/src/app/login/login.module.ts
+++ b/packages/composer-playground/src/app/login/login.module.ts
@@ -10,10 +10,11 @@ import { IdentityCardComponent } from './identity-card';
import { DrawerModule } from '../common/drawer';
import { FileImporterModule } from '../common/file-importer/file-importer.module';
import { ConnectionProfileModule } from '../connection-profile/connection-profile.module';
+import { ImportModule } from '../import/import.module';
import { FooterModule } from '../footer/footer.module';
@NgModule({
- imports: [CommonModule, FormsModule, NgbModule, LoginRoutingModule, ConnectionProfileModule, FooterModule, FileImporterModule, DrawerModule],
+ imports: [CommonModule, FormsModule, NgbModule, LoginRoutingModule, ConnectionProfileModule, FooterModule, FileImporterModule, DrawerModule, ImportModule],
entryComponents: [IdentityCardComponent],
declarations: [LoginComponent, IdentityCardComponent]
})
diff --git a/packages/composer-playground/src/app/services/connectionprofile.service.ts b/packages/composer-playground/src/app/services/connectionprofile.service.ts
index 54036c0a26..4d7b260c6b 100644
--- a/packages/composer-playground/src/app/services/connectionprofile.service.ts
+++ b/packages/composer-playground/src/app/services/connectionprofile.service.ts
@@ -46,14 +46,14 @@ export class ConnectionProfileService {
console.log('Currently running version ' + version);
console.log('Checking for $default connection profile');
return this.getAdminConnection().getProfile('$default')
- .catch((error) => {
- // It doesn't exist, so create it.
- console.log('$default connection profile does not exist, creating');
- return this.getAdminConnection().createProfile('$default', {type: 'web'})
- .then(() => {
- return this.walletService.getWallet('$default').add('admin', 'adminpw');
+ .catch((error) => {
+ // It doesn't exist, so create it.
+ console.log('$default connection profile does not exist, creating');
+ return this.getAdminConnection().createProfile('$default', {type: 'web'})
+ .then(() => {
+ return this.walletService.getWallet('$default').add('admin', 'adminpw');
+ });
});
- });
};
getAllProfiles(): Promise {
diff --git a/packages/composer-playground/src/app/services/samplebusinessnetwork.service.spec.ts b/packages/composer-playground/src/app/services/samplebusinessnetwork.service.spec.ts
index 12366399b1..6671d21b73 100644
--- a/packages/composer-playground/src/app/services/samplebusinessnetwork.service.spec.ts
+++ b/packages/composer-playground/src/app/services/samplebusinessnetwork.service.spec.ts
@@ -41,6 +41,8 @@ describe('SampleBusinessNetworkService', () => {
aclFileMock = sinon.createStubInstance(AclFile);
alertMock = sinon.createStubInstance(AlertService);
+ alertMock.busyStatus$ = {next: sinon.stub()};
+
TestBed.configureTestingModule({
imports: [HttpModule],
providers: [SampleBusinessNetworkService,
@@ -88,9 +90,8 @@ describe('SampleBusinessNetworkService', () => {
})));
});
- describe('deployChosenSample', () => {
+ describe('getChosenSample', () => {
it('should deploy the chosen sample', fakeAsync(inject([SampleBusinessNetworkService, XHRBackend], (service: SampleBusinessNetworkService, mockBackend) => {
- let mockDeployNetwork = sinon.stub(service, 'deployBusinessNetwork');
let businessNetworkFromArchiveMock = sandbox.stub(BusinessNetworkDefinition, 'fromArchive').returns(Promise.resolve({name: 'myNetwork'}));
mockBackend.connections.subscribe((connection) => {
@@ -99,43 +100,24 @@ describe('SampleBusinessNetworkService', () => {
})));
});
- service.deployChosenSample({name: 'bob'}, true);
-
- tick();
-
- businessNetworkFromArchiveMock.should.have.been.called;
- mockDeployNetwork.should.have.been.calledWith({name: 'myNetwork'}, true);
-
- })));
-
- it('should update the chosen sample', fakeAsync(inject([SampleBusinessNetworkService, XHRBackend], (service: SampleBusinessNetworkService, mockBackend) => {
- let mockDeployNetwork = sinon.stub(service, 'deployBusinessNetwork');
- let businessNetworkFromArchiveMock = sandbox.stub(BusinessNetworkDefinition, 'fromArchive').returns(Promise.resolve({name: 'myNetwork'}));
-
- mockBackend.connections.subscribe((connection) => {
- connection.mockRespond(new Response(new ResponseOptions({
- body: '1234'
- })));
+ service.getChosenSample({name: 'bob'}).then((result: any) => {
+ result.should.deep.equal({name: 'myNetwork'});
});
- service.deployChosenSample({name: 'bob'}, false);
-
tick();
businessNetworkFromArchiveMock.should.have.been.called;
- mockDeployNetwork.should.have.been.calledWith({name: 'myNetwork'}, false);
})));
it('should handle error', fakeAsync(inject([SampleBusinessNetworkService, XHRBackend], (service: SampleBusinessNetworkService, mockBackend) => {
- let mockDeployNetwork = sinon.stub(service, 'deployBusinessNetwork');
let businessNetworkFromArchiveMock = sandbox.stub(BusinessNetworkDefinition, 'fromArchive').returns(Promise.resolve({name: 'myNetwork'}));
mockBackend.connections.subscribe((connection) => {
connection.mockError(new Error('some error'));
});
- service.deployChosenSample({name: 'bob'}, true)
+ service.getChosenSample({name: 'bob'})
.then(() => {
throw('should not get here');
})
@@ -146,29 +128,67 @@ describe('SampleBusinessNetworkService', () => {
tick();
businessNetworkFromArchiveMock.should.not.have.been.called;
- mockDeployNetwork.should.not.have.been.called;
})));
});
describe('deployBusinessNetwork', () => {
it('should deploy the business network definition', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => {
+ let modalManagerMock = {addModelFiles: sinon.stub(), getModelFiles: sinon.stub().returns(['model'])};
+ let scriptManagerMock = {getScripts: sinon.stub().returns(['script']), addScript: sinon.stub()};
+ let aclManagerMock = {getAclFile: sinon.stub().returns('acl'), setAclFile: sinon.stub()};
+ let metaData = {getPackageJson: sinon.stub().returns({}), getREADME: sinon.stub()};
+
+ businessNetworkMock.getModelManager.returns(modalManagerMock);
+ businessNetworkMock.getScriptManager.returns(scriptManagerMock);
+ businessNetworkMock.getAclManager.returns(aclManagerMock);
+ businessNetworkMock.getMetadata.returns(metaData);
+
+ let mockCreateBN = sinon.stub(service, 'createNewBusinessDefinition').returns(businessNetworkMock);
adminMock.deploy.returns(Promise.resolve());
clientMock.refresh.returns(Promise.resolve());
- alertMock.busyStatus$ = {next: sinon.stub()};
-
- service.deployBusinessNetwork(businessNetworkMock, true);
+ service.deployBusinessNetwork(businessNetworkMock, 'myNetwork', 'myDescription');
tick();
+ mockCreateBN.should.have.been.calledWith('myNetwork', 'myDescription', sinon.match.any, sinon.match.any);
adminMock.deploy.should.have.been.called;
clientMock.refresh.should.have.been.called;
clientMock.reset.should.have.been.called;
alertMock.busyStatus$.next.should.have.been.calledWith(null);
})));
- it('should update the business network definition', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => {
+ it('should handle error', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => {
+ let modalManagerMock = {addModelFiles: sinon.stub(), getModelFiles: sinon.stub().returns(['model'])};
+ let scriptManagerMock = {getScripts: sinon.stub().returns(['script']), addScript: sinon.stub()};
+ let aclManagerMock = {getAclFile: sinon.stub().returns('acl'), setAclFile: sinon.stub()};
+ let metaData = {getPackageJson: sinon.stub().returns({}), getREADME: sinon.stub()};
+ businessNetworkMock.getModelManager.returns(modalManagerMock);
+ businessNetworkMock.getScriptManager.returns(scriptManagerMock);
+ businessNetworkMock.getAclManager.returns(aclManagerMock);
+ businessNetworkMock.getMetadata.returns(metaData);
+
+ let mockCreateBN = sinon.stub(service, 'createNewBusinessDefinition').returns(businessNetworkMock);
+
+ adminMock.deploy.returns(Promise.reject('some error'));
+
+ service.deployBusinessNetwork(businessNetworkMock, 'myNetwork', 'myDescription').then(() => {
+ throw('should not get here');
+ })
+ .catch((error) => {
+ alertMock.busyStatus$.next.should.have.been.calledWith(null);
+ error.should.equal('some error');
+ });
+ tick();
+
+ mockCreateBN.should.have.been.calledWith('myNetwork', 'myDescription', sinon.match.any, sinon.match.any);
+ adminMock.deploy.should.have.been.called;
+ })));
+ });
+
+ describe('updateBusinessNetwork', () => {
+ it('should update the business network definition', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => {
adminMock.update.returns(Promise.resolve());
clientMock.refresh.returns(Promise.resolve());
clientMock.getBusinessNetworkName.returns('myNetwork');
@@ -185,9 +205,7 @@ describe('SampleBusinessNetworkService', () => {
let mockCreateBN = sinon.stub(service, 'createNewBusinessDefinition').returns(businessNetworkMock);
- alertMock.busyStatus$ = {next: sinon.stub()};
-
- service.deployBusinessNetwork(businessNetworkMock, false);
+ service.updateBusinessNetwork(businessNetworkMock);
tick();
@@ -207,11 +225,18 @@ describe('SampleBusinessNetworkService', () => {
})));
it('should handle error', fakeAsync(inject([SampleBusinessNetworkService], (service: SampleBusinessNetworkService) => {
- adminMock.deploy.returns(Promise.reject('some error'));
+ clientMock.getBusinessNetworkName.returns('myNetwork');
+
+ let modalManagerMock = {addModelFiles: sinon.stub(), getModelFiles: sinon.stub().returns(['model'])};
+ let scriptManagerMock = {getScripts: sinon.stub().returns(['script']), addScript: sinon.stub()};
+ let aclManagerMock = {getAclFile: sinon.stub().returns('acl'), setAclFile: sinon.stub()};
+ let metaData = {getPackageJson: sinon.stub().returns({}), getREADME: sinon.stub()};
+
+ let mockCreateBN = sinon.stub(service, 'createNewBusinessDefinition').returns(businessNetworkMock);
- alertMock.busyStatus$ = {next: sinon.stub()};
+ adminMock.update.returns(Promise.reject('some error'));
- service.deployBusinessNetwork(businessNetworkMock, true).then(() => {
+ service.updateBusinessNetwork(businessNetworkMock).then(() => {
throw('should not get here');
})
.catch((error) => {
diff --git a/packages/composer-playground/src/app/services/samplebusinessnetwork.service.ts b/packages/composer-playground/src/app/services/samplebusinessnetwork.service.ts
index c9f4afe870..a29913f586 100644
--- a/packages/composer-playground/src/app/services/samplebusinessnetwork.service.ts
+++ b/packages/composer-playground/src/app/services/samplebusinessnetwork.service.ts
@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
-import { Http, RequestOptions, URLSearchParams } from '@angular/http';
+import { Http, RequestOptions, URLSearchParams } from '@angular/http';
import { AdminService } from './admin.service';
import { ClientService } from './client.service';
@@ -15,7 +15,7 @@ export class SampleBusinessNetworkService {
private http: Http) {
}
- createNewBusinessDefinition(name, description, packageJson, readme) {
+ public createNewBusinessDefinition(name, description, packageJson, readme): BusinessNetworkDefinition {
return new BusinessNetworkDefinition(name, description, packageJson, readme);
}
@@ -30,7 +30,7 @@ export class SampleBusinessNetworkService {
});
}
- public deployChosenSample(chosenNetwork: object, deployNetwork: boolean): Promise {
+ public getChosenSample(chosenNetwork): Promise {
let params: URLSearchParams = new URLSearchParams();
let paramNames = Object.keys(chosenNetwork);
@@ -47,42 +47,67 @@ export class SampleBusinessNetworkService {
.then((response) => {
return BusinessNetworkDefinition.fromArchive(( response)._body);
})
- .then((businessNetwork) => {
- return this.deployBusinessNetwork(businessNetwork, deployNetwork);
- })
.catch((error) => {
throw(error);
});
}
- public deployBusinessNetwork(businessNetworkDefinition: BusinessNetworkDefinition, deployNetwork: boolean): Promise {
- let deployPromise;
+ public deployBusinessNetwork(businessNetworkDefinition: BusinessNetworkDefinition, networkName: string, networkDescription: string): Promise {
+ let packageJson = businessNetworkDefinition.getMetadata().getPackageJson();
+ packageJson.name = networkName;
+ packageJson.description = networkDescription;
- if (deployNetwork) {
- deployPromise = this.adminService.deploy(businessNetworkDefinition);
- } else {
- let currentBusinessNetworkName = this.clientService.getBusinessNetworkName();
+ let newNetwork = this.createNewBusinessDefinition(networkName, networkDescription, packageJson, businessNetworkDefinition.getMetadata().getREADME());
- let packageJson = businessNetworkDefinition.getMetadata().getPackageJson();
- packageJson.name = currentBusinessNetworkName;
+ let modelFiles = this.clientService.filterModelFiles(businessNetworkDefinition.getModelManager().getModelFiles());
- let newNetwork = this.createNewBusinessDefinition(currentBusinessNetworkName, businessNetworkDefinition.getDescription(), packageJson, businessNetworkDefinition.getMetadata().getREADME());
+ newNetwork.getModelManager().addModelFiles(modelFiles);
+ businessNetworkDefinition.getScriptManager().getScripts().forEach((script) => {
+ newNetwork.getScriptManager().addScript(script);
+ });
- let modelFiles = this.clientService.filterModelFiles(businessNetworkDefinition.getModelManager().getModelFiles());
+ if (businessNetworkDefinition.getAclManager().getAclFile()) {
+ newNetwork.getAclManager().setAclFile(businessNetworkDefinition.getAclManager().getAclFile());
+ }
- newNetwork.getModelManager().addModelFiles(modelFiles);
- businessNetworkDefinition.getScriptManager().getScripts().forEach((script) => {
- newNetwork.getScriptManager().addScript(script);
+ return this.adminService.deploy(businessNetworkDefinition)
+ .then(() => {
+ return this.clientService.refresh(businessNetworkDefinition.getName());
+ })
+ .then(() => {
+ return this.clientService.reset();
+ })
+ .then(() => {
+ this.alertService.busyStatus$.next(null);
+ })
+ .catch((error) => {
+ this.alertService.busyStatus$.next(null);
+ throw error;
});
+ }
- if (businessNetworkDefinition.getAclManager().getAclFile()) {
- newNetwork.getAclManager().setAclFile(businessNetworkDefinition.getAclManager().getAclFile());
- }
+ public updateBusinessNetwork(businessNetworkDefinition: BusinessNetworkDefinition): Promise {
+ let currentBusinessNetworkName = this.clientService.getBusinessNetworkName();
+ let currentBusinessNetworkDescription = businessNetworkDefinition.getDescription();
+
+ let packageJson = businessNetworkDefinition.getMetadata().getPackageJson();
+ packageJson.name = currentBusinessNetworkName;
+ packageJson.description = currentBusinessNetworkDescription;
+
+ let newNetwork = this.createNewBusinessDefinition(currentBusinessNetworkName, currentBusinessNetworkDescription, packageJson, businessNetworkDefinition.getMetadata().getREADME());
+
+ let modelFiles = this.clientService.filterModelFiles(businessNetworkDefinition.getModelManager().getModelFiles());
+
+ newNetwork.getModelManager().addModelFiles(modelFiles);
+ businessNetworkDefinition.getScriptManager().getScripts().forEach((script) => {
+ newNetwork.getScriptManager().addScript(script);
+ });
- deployPromise = this.adminService.update(newNetwork);
+ if (businessNetworkDefinition.getAclManager().getAclFile()) {
+ newNetwork.getAclManager().setAclFile(businessNetworkDefinition.getAclManager().getAclFile());
}
- return deployPromise
+ return this.adminService.update(newNetwork)
.then(() => {
return this.clientService.refresh(businessNetworkDefinition.getName());
})
diff --git a/packages/composer-playground/src/assets/styles/components/_model.scss b/packages/composer-playground/src/assets/styles/components/_model.scss
index 62d6e0d39c..0caea6e365 100644
--- a/packages/composer-playground/src/assets/styles/components/_model.scss
+++ b/packages/composer-playground/src/assets/styles/components/_model.scss
@@ -13,7 +13,7 @@
right: 0;
bottom: 0;
left: 0;
- z-index: 1000;
+ z-index: 100000;
display: none;
overflow: hidden;
outline: 0;
diff --git a/packages/composer-playground/src/assets/svg/other/default-network-animated.svg b/packages/composer-playground/src/assets/svg/other/default-network-animated.svg
new file mode 100644
index 0000000000..383cd84a03
--- /dev/null
+++ b/packages/composer-playground/src/assets/svg/other/default-network-animated.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/composer-playground/src/assets/svg/other/default-network.svg b/packages/composer-playground/src/assets/svg/other/default-network.svg
new file mode 100644
index 0000000000..36885d89d0
--- /dev/null
+++ b/packages/composer-playground/src/assets/svg/other/default-network.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/composer-playground/src/assets/svg/other/upload.svg b/packages/composer-playground/src/assets/svg/other/upload.svg
new file mode 100644
index 0000000000..85be079e58
--- /dev/null
+++ b/packages/composer-playground/src/assets/svg/other/upload.svg
@@ -0,0 +1 @@
+
\ No newline at end of file