Compare commits

..

71 Commits
next ... master

Author SHA1 Message Date
Sky Young
5d768d868a Add Google Analytics 2018-05-22 16:03:44 -07:00
Sky Young
3435f825d9 Update Compiled Files 2018-05-22 14:22:15 -07:00
Sky Young
51cc30532d Parse fee correctly 2018-05-22 14:22:05 -07:00
Sky Young
19c60d111d Fix attachment to MutationObserver 2018-05-22 13:14:01 -07:00
Sky Young
e4775417fc On DOM Mutation, load clipboard buttons 2018-05-22 13:01:04 -07:00
Sky Young
c3ca8643ec Import ClipboardJS before main.js 2018-05-22 12:23:44 -07:00
Sky Young
6e3f51fdbd Use buttons for ClipboardJS copy buttons 2018-05-22 12:08:02 -07:00
Sky Young
7ec226faa2 Use ClipboardJS for HTML5 copy 2018-05-22 11:21:57 -07:00
Sky Young
52caae1d59 Match darker style of status for search box 2018-05-21 16:26:41 -07:00
Sky Young
895ba45aec Update progress bar color 2018-05-21 16:14:56 -07:00
Sky Young
c615bb44b2 Update colors to match Flo blue 2018-05-21 16:10:56 -07:00
Sky Young
9325a1c103 Update UI to say Flo instead of Florincoin 2018-05-21 16:03:01 -07:00
Sky Young
e456052358 Hide on livenet 2018-05-21 14:11:33 -07:00
Sky Young
b00f80b967 Add getStatus call to header controller 2018-05-21 14:10:02 -07:00
Sky Young
6c7776904a Show network label if not on mainnet 2018-05-21 14:05:12 -07:00
Sky Young
5c070d0e65 Get Network Info on Index page 2018-05-21 13:56:49 -07:00
Sky Young
0c40d113b4 Update about page 2018-05-18 17:34:52 -07:00
Sky Young
be1788b4e3 Update translations 2018-05-18 17:23:33 -07:00
Sky Young
8668e6abb0 Wrap floData string properly 2018-05-18 16:36:30 -07:00
Sky Young
19e5755ef7 Update version 2018-05-18 16:32:19 -07:00
Sky Young
bc8dc2e375 Attempt to load transactions from the recent block by default 2018-05-18 16:31:38 -07:00
Sky Young
e83a99ae96 Update Currency 2018-05-18 16:31:07 -07:00
Sky Young
c7aa861a3b Restyle floData container 2018-05-18 15:43:14 -07:00
Sky Young
4eba927ded Update version 2018-05-18 15:29:09 -07:00
Sky Young
beb386535f Add floData to latest transactions on homepage 2018-05-18 15:29:00 -07:00
Sky Young
686d775011 Remove floData from table 2018-05-18 15:24:47 -07:00
Sky Young
d5db7a9676 Add floData to transactions in regular list 2018-05-18 15:19:00 -07:00
Sky Young
f098c4d35d Disable build on service start 2018-05-18 15:08:29 -07:00
Sky Young
135f9dd617 Add floData to transaction view 2018-05-17 12:43:44 -07:00
Sky Young
b5b7f9af2f Change API Prefix back to default 2018-05-16 14:37:08 -07:00
Sky Young
c319197e64 Rollback angularjs-all 2018-05-16 14:06:07 -07:00
Sky Young
ef3a02540b build new apiPrefix 2018-05-16 13:46:01 -07:00
OstlerDev
ee303492e3 btc -> flo 2018-01-15 16:39:57 -08:00
Chris Kleeschulte
c825504826
Bumped version. 2017-11-22 16:04:40 -05:00
Chris Kleeschulte
aef5a88dd2
Bumped version. 2017-11-13 14:26:31 -05:00
Chris Kleeschulte
51d3566203
Bumped version. 2017-11-13 09:56:20 -05:00
Chris Kleeschulte
24426b7337
Bumped version. 2017-11-09 22:01:34 -05:00
Chris Kleeschulte
f41fb29e26
Bumped version. 2017-11-09 17:16:40 -05:00
Chris Kleeschulte
271bc416fc
Bumped version. 2017-11-08 09:41:35 -05:00
Chris Kleeschulte
46821f0c15
Bumped version. 2017-11-07 21:42:06 -05:00
Chris Kleeschulte
e13e24d3df
Bumped version. 2017-11-07 15:43:10 -05:00
Chris Kleeschulte
9559af90ad
Bumped version. 2017-11-07 13:27:14 -05:00
Chris Kleeschulte
1e431f9140
Bumped version. 2017-11-06 19:37:05 -05:00
Chris Kleeschulte
d5d6191dfb
Bumped version. 2017-11-06 19:18:07 -05:00
Chris Kleeschulte
0852a26312
Bumped version. 2017-11-05 18:40:59 -05:00
Chris Kleeschulte
e87ad01707
Bumped version. 2017-11-02 17:47:01 -04:00
Chris Kleeschulte
efb275ba99
Bumped version. 2017-11-02 13:51:37 -04:00
Chris Kleeschulte
bc49b1ded5
Bumped version. 2017-11-02 12:06:46 -04:00
Chris Kleeschulte
55e6427d57
Bumped version. 2017-11-01 16:05:41 -04:00
Chris Kleeschulte
96b44e29b5
Bumped version. 2017-10-30 15:43:16 -04:00
Chris Kleeschulte
d4bb931f37
Bumped version. 2017-10-26 17:55:27 -04:00
Chris Kleeschulte
59c4bf2765
Bumped version. 2017-10-26 17:14:55 -04:00
Chris Kleeschulte
8251807292
Bumped version. 2017-10-24 17:51:25 -04:00
Chris Kleeschulte
f34006e513
Bumped version. 2017-10-24 14:30:29 -04:00
Chris Kleeschulte
3ff0341ad5
Bump version 2017-10-20 13:20:38 -04:00
Chris Kleeschulte
a69ef92e31
Bumped version. 2017-10-18 19:21:50 -04:00
Chris Kleeschulte
81155eb292
Added mocha as a dependency. 2017-10-12 19:23:54 -04:00
Chris Kleeschulte
9c00ac8bc4
Added a travis.yml file. 2017-10-12 19:16:52 -04:00
Chris Kleeschulte
65f88ef14a
Bumped version. 2017-10-12 19:10:32 -04:00
Chris Kleeschulte
c52682bb70
Added test stubs. 2017-10-12 19:01:20 -04:00
Chris Kleeschulte
2cc88a2a15
Bumped version. 2017-10-12 18:02:06 -04:00
Chris Kleeschulte
fbc38a731c
Bumped version. 2017-10-12 15:09:44 -04:00
Chris Kleeschulte
9195c90b74
Bumped version. 2017-10-11 17:24:02 -04:00
Chris Kleeschulte
2010f73d81
Bumped version. 2017-10-11 16:41:14 -04:00
Chris Kleeschulte
ba31444df5
Bumped version. 2017-10-09 18:02:13 -04:00
Chris Kleeschulte
a0ba1efeb8
Bumped version. 2017-10-08 15:47:25 -04:00
Chris Kleeschulte
37177c412c
Bumped version. 2017-10-02 16:40:36 -04:00
Chris Kleeschulte
4931504c1e
Bumped version. 2017-10-01 19:20:05 -04:00
Chris Kleeschulte
6cbca55bb1
Apparently pushd and popd are not available in the shell used by exec on
all platforms.
2017-09-27 19:22:58 -04:00
Chris Kleeschulte
7155ff0b91
Added a build runner in line with starting the service. 2017-09-26 17:13:22 -04:00
Jason Dreyzehner
e94154ba4b chore(release): 5.0.0-beta.1 2017-08-18 18:05:36 -04:00
775 changed files with 7896 additions and 182198 deletions

3
.bowerrc Normal file
View File

@ -0,0 +1,3 @@
{
"directory": "public/lib"
}

50
.gitignore vendored
View File

@ -1,4 +1,50 @@
node_modules
package-lock.json
# from https://github.com/github/gitignore/blob/master/Node.gitignore
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz
*.swp
tags
pids
logs
results
build
node_modules
# extras
*.swp
*.swo
*~
.project
peerdb.json
npm-debug.log
.nodemonignore
.DS_Store
public/lib/*
!public/lib/zeroclipboard/ZeroClipboard.swf
db/txs/*
db/txs
db/testnet/txs/*
db/testnet/txs
db/blocks/*
db/blocks
db/testnet/blocks/*
db/testnet/blocks
public/js/angularjs-all.js
public/js/main.js
public/js/vendors.js
public/css/main.css
README.html
po/*
!po/*.po
*.codekit3

43
.jshintrc Normal file
View File

@ -0,0 +1,43 @@
{
"node": true, // Enable globals available when code is running inside of the NodeJS runtime environment.
"browser": true, // Standard browser globals e.g. `window`, `document`.
"esnext": true, // Allow ES.next specific features such as `const` and `let`.
"bitwise": false, // Prohibit bitwise operators (&, |, ^, etc.).
"camelcase": false, // Permit only camelcase for `var` and `object indexes`.
"curly": false, // Require {} for every new block or scope.
"eqeqeq": true, // Require triple equals i.e. `===`.
"immed": true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );`
"latedef": true, // Prohibit variable use before definition.
"newcap": true, // Require capitalization of all constructor functions e.g. `new F()`.
"noarg": true, // Prohibit use of `arguments.caller` and `arguments.callee`.
"quotmark": "single", // Define quotes to string values.
"regexp": true, // Prohibit `.` and `[^...]` in regular expressions.
"undef": true, // Require all non-global variables be declared before they are used.
"unused": true, // Warn unused variables.
"strict": true, // Require `use strict` pragma in every file.
"trailing": true, // Prohibit trailing whitespaces.
"smarttabs": false, // Suppresses warnings about mixed tabs and spaces
"globals": { // Globals variables.
"angular": true
},
"predef": [ // Extra globals.
"define",
"require",
"exports",
"module",
"describe",
"before",
"beforeEach",
"after",
"afterEach",
"it",
"inject",
"$",
"io",
"app",
"moment"
],
"indent": false, // Specify indentation spacing
"devel": true, // Allow development statements e.g. `console.log();`.
"noempty": true // Prohibit use of empty blocks.
}

39
.npmignore Normal file
View File

@ -0,0 +1,39 @@
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz
*.swp
tags
pids
logs
results
build
node_modules
# extras
*.swp
*.swo
*~
.project
peerdb.json
npm-debug.log
.nodemonignore
.DS_Store
db/txs/*
db/txs
db/testnet/txs/*
db/testnet/txs
db/blocks/*
db/blocks
db/testnet/blocks/*
db/testnet/blocks
README.html
k*

View File

@ -1,6 +1,5 @@
sudo: false
language: node_js
node_js:
- 8
after_success:
- yarn send-coverage
- 'v8'
install:
- npm install

148
Gruntfile.js Normal file
View File

@ -0,0 +1,148 @@
'use strict';
// var config = require('flosight-config.json');
module.exports = function(grunt) {
//Load NPM tasks
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-css');
grunt.loadNpmTasks('grunt-markdown');
grunt.loadNpmTasks('grunt-macreload');
grunt.loadNpmTasks('grunt-angular-gettext');
grunt.loadNpmTasks('grunt-replace');
// Project Configuration
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
replace: {
dist: {
options: {
patterns: [
{
match: 'INSIGHT_API_PREFIX',
replacement: '<%= pkg.flosightConfig.apiPrefix %>'
}
],
usePrefix: false
},
files: [
{src: ['public/src/templates/api.js'], dest: 'public/src/js/services/api.js'}
]
}
},
concat: {
options: {
process: function(src, filepath) {
if (filepath.substr(filepath.length - 2) === 'js') {
return '// Source: ' + filepath + '\n' +
src.replace(/(^|\n)[ \t]*('use strict'|"use strict");?\s*/g, '$1');
} else {
return src;
}
}
},
vendors: {
src: ['public/src/js/ios-imagefile-megapixel/megapix-image.js', 'public/lib/qrcode-generator/js/qrcode.js', 'public/src/js/jsqrcode/grid.js', 'public/src/js/jsqrcode/version.js', 'public/src/js/jsqrcode/detector.js', 'public/src/js/jsqrcode/formatinf.js', 'public/src/js/jsqrcode/errorlevel.js', 'public/src/js/jsqrcode/bitmat.js', 'public/src/js/jsqrcode/datablock.js', 'public/src/js/jsqrcode/bmparser.js', 'public/src/js/jsqrcode/datamask.js', 'public/src/js/jsqrcode/rsdecoder.js', 'public/src/js/jsqrcode/gf256poly.js', 'public/src/js/jsqrcode/gf256.js', 'public/src/js/jsqrcode/decoder.js', 'public/src/js/jsqrcode/qrcode.js', 'public/src/js/jsqrcode/findpat.js', 'public/src/js/jsqrcode/alignpat.js', 'public/src/js/jsqrcode/databr.js', 'public/lib/momentjs/min/moment.min.js', 'public/lib/moment/lang/es.js', 'public/lib/zeroclipboard/ZeroClipboard.min.js'],
dest: 'public/js/vendors.js'
},
angular: {
src: ['public/lib/angular/angular.min.js', 'public/lib/angular-resource/angular-resource.min.js', 'public/lib/angular-route/angular-route.min.js', 'public/lib/angular-qrcode/qrcode.js', 'public/lib/angular-animate/angular-animate.min.js', 'public/lib/angular-bootstrap/ui-bootstrap.js', 'public/lib/angular-bootstrap/ui-bootstrap-tpls.js', 'public/lib/angular-ui-utils/ui-utils.min.js', 'public/lib/ngprogress/build/ngProgress.min.js', 'public/lib/angular-gettext/dist/angular-gettext.min.js', 'public/lib/angular-moment/angular-moment.min.js'],
dest: 'public/js/angularjs-all.js'
},
main: {
src: ['public/src/js/app.js', 'public/src/js/controllers/*.js', 'public/src/js/services/*.js', 'public/src/js/directives.js', 'public/src/js/filters.js', 'public/src/js/config.js', 'public/src/js/init.js', 'public/src/js/translations.js'],
dest: 'public/js/main.js'
},
css: {
src: ['public/lib/bootstrap/dist/css/bootstrap.min.css', 'public/src/css/**/*.css'],
dest: 'public/css/main.css'
}
},
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= pkg.version %> */\n',
mangle: false
},
vendors: {
src: 'public/js/vendors.js',
dest: 'public/js/vendors.min.js'
},
angular: {
src: 'public/js/angularjs-all.js',
dest: 'public/js/angularjs-all.min.js'
},
main: {
src: 'public/js/main.js',
dest: 'public/js/main.min.js'
}
},
cssmin: {
css: {
src: 'public/css/main.css',
dest: 'public/css/main.min.css'
}
},
markdown: {
all: {
files: [
{
expand: true,
src: 'README.md',
dest: '.',
ext: '.html'
}
]
}
},
macreload: {
chrome: {
browser: 'chrome',
editor: 'macvim'
}
},
watch: {
main: {
files: ['public/src/js/**/*.js'],
tasks: ['concat:main', 'uglify:main'],
},
css: {
files: ['public/src/css/**/*.css'],
tasks: ['concat:css', 'cssmin'],
},
},
nggettext_extract: {
pot: {
files: {
'po/template.pot': ['public/views/*.html', 'public/views/**/*.html']
}
},
},
nggettext_compile: {
all: {
options: {
module: 'flosight'
},
files: {
'public/src/js/translations.js': ['po/*.po']
}
},
}
});
//Making grunt default to force in order not to break the project.
grunt.option('force', true);
//Default task(s).
grunt.registerTask('default', ['replace', 'watch']);
//Update .pot file
grunt.registerTask('translate', ['nggettext_extract']);
//Compile task (concat + minify)
grunt.registerTask('compile', ['replace', 'nggettext_compile', 'concat', 'uglify', 'cssmin']);
};

21
LICENSE
View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2013-2017 BitPay, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

121
README.md
View File

@ -1,17 +1,118 @@
# Insight
# Flosight UI
**A bitcoin blockchain explorer and API.**
## Requirements
Insight requires [Node.js](https://nodejs.org) 8.2 and [MongoDB](https://www.mongodb.com/). Consider using [n](https://github.com/tj/n) and [m](https://github.com/aheckmann/m) to install the latest versions.
A Florincoin blockchain explorer web application service for [Flocore Node](https://github.com/bitpay/flocore-node) using the [Flosight API](https://github.com/bitpay/flosight-api).
## Quick Start
To get started, clone this repository, then with `mongod` running install and run insight:
Please see the guide at [https://flocore.io/guides/full-node](https://flocore.io/guides/full-node) for information about getting a block explorer running. This is only the front-end component of the block explorer, and is packaged together with all of the necessary components in [Flocore](https://github.com/bitpay/flocore).
## Getting Started
To manually install all of the necessary components, you can run these commands:
```bash
git clone -b next https://github.com/bitpay/insight.git && cd insight/server
npm install
npm start
npm install -g flocore-node
flocore-node create mynode
cd mynode
flocore-node install flosight-api
flocore-node install flosight-ui
flocore-node start
```
Open a web browser to `http://localhost:3001/flosight/`
## Development
To build Flosight UI locally:
```
$ npm run build
```
A watch task is also available:
```
$ npm run watch
```
## Changing routePrefix and apiPrefix
By default, the `flosightConfig` in `package.json` is:
```json
"flosightConfig": {
"apiPrefix": "flosight-api",
"routePrefix": "flosight"
}
```
To change these routes, first make your changes to `package.json`, for example:
```json
"flosightConfig": {
"apiPrefix": "api",
"routePrefix": ""
}
```
Then rebuild the `flosight-ui` service:
```
$ npm run build
```
## Multilanguage support
Flosight UI uses [angular-gettext](http://angular-gettext.rocketeer.be) for multilanguage support.
To enable a text to be translated, add the ***translate*** directive to html tags. See more details [here](http://angular-gettext.rocketeer.be/dev-guide/annotate/). Then, run:
```
grunt compile
```
This action will create a template.pot file in ***po/*** folder. You can open it with some PO editor ([Poedit](http://poedit.net)). Read this [guide](http://angular-gettext.rocketeer.be/dev-guide/translate/) to learn how to edit/update/import PO files from a generated POT file. PO file will be generated inside po/ folder.
If you make new changes, simply run **grunt compile** again to generate a new .pot template and the angular javascript ***js/translations.js***. Then (if use Poedit), open .po file and choose ***update from POT File*** from **Catalog** menu.
Finally changes your default language from ***public/src/js/config***
```
gettextCatalog.currentLanguage = 'es';
```
This line will take a look at any *.po files inside ***po/*** folder, e.g.
**po/es.po**, **po/nl.po**. After any change do not forget to run ***grunt
compile***.
## Note
For more details about the [Flosight API](https://github.com/bitpay/flosight-api) configuration and end-points, go to [Flosight API GitHub repository](https://github.com/bitpay/flosight-api).
## Contribute
Contributions and suggestions are welcomed at the [Flosight UI GitHub repository](https://github.com/bitpay/flosight-ui).
## License
(The MIT License)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,62 +0,0 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": {
"name": "insight-ui"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets",
"favicon.ico"
],
"index": "index.html",
"main": "app/main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
"scripts": [],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"project": "src/tsconfig.app.json"
},
{
"project": "src/tsconfig.spec.json"
},
{
"project": "e2e/tsconfig.e2e.json"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
},
"codeCoverage": {
"exclude": [
"src/polyfills.ts",
"src/test.ts",
"src/mocks.ts",
"**/*.mock.ts"
]
}
},
"defaults": {
"styleExt": "css",
"component": {}
}
}

38
app/.gitignore vendored
View File

@ -1,38 +0,0 @@
# Specifies intentionally untracked files to ignore when using Git
# http://git-scm.com/docs/gitignore
*~
*.sw[mnpcod]
*.log
*.tmp
*.tmp.*
log.txt
*.sublime-project
*.sublime-workspace
.vscode/
npm-debug.log*
.idea/
.sass-cache/
.tmp/
.versions/
coverage/
dist/
node_modules/
tmp/
temp/
hooks/
platforms/
plugins/
plugins/android.json
plugins/ios.json
www/
$RECYCLE.BIN/
# e2e
/e2e/*.js
/e2e/*.map
.DS_Store
Thumbs.db
UserInterfaceState.xcuserstate

View File

@ -1,24 +0,0 @@
[![Build Status](https://travis-ci.org/bitpay/insight-ui.svg?branch=ionic)](https://travis-ci.org/bitpay/insight-ui)
[![codecov.io](https://codecov.io/github/bitpay/insight-ui/coverage.svg?branch=ionic)](https://codecov.io/github/bitpay/insight-ui?branch=ionic)
# Insight UI
## Install & Start
You need to be running [the latest node LTS](https://nodejs.org/en/download/) or newer.
```bash
git clone https://github.com/bitpay/insight-ui.git
cd insight-ui/app
npm install
npm start
```
## Run Unit Tests
```bash
npm test
```
## Run E2E
```
npm run e2e
```

View File

@ -1,32 +0,0 @@
import { browser, element, by } from 'protractor';
describe('InsightApp', () => {
beforeEach(() => {
browser.get('');
});
it('should have a title', () => {
expect(browser.getTitle()).toEqual('Home');
});
it('should have {nav}', () => {
expect(element(by.css('ion-navbar')).isPresent()).toEqual(true);
});
it('has a menu button that displays the left menu', () => {
element(by.css('.bar-button-menutoggle')).click()
.then(() => {
browser.driver.sleep(2000); // wait for the animation
expect(element(by.css('ion-menu')).isPresent()).toEqual(true);
});
});
it('the left menu has a link with title Home', () => {
element(by.css('.bar-button-menutoggle')).click()
.then(() => {
browser.driver.sleep(2000); // wait for the animation
expect(element.all(by.css('ion-label')).first().getText()).toEqual('Home');
});
});
});

View File

@ -1,22 +0,0 @@
import { browser, element, by, ElementFinder } from 'protractor';
describe('BroadcastTxPage', () => {
beforeEach(() => {
browser.get('');
});
it('should have an input field', () => {
element(by.css('.bar-button-menutoggle')).click().then(() => {
browser.driver.sleep(2000); // wait for the animation
element.all(by.className('input-wrapper')).then((items) => {
items[2].click();
browser.driver.sleep(2000); // wait for the animation
let theElem = element.all(by.css('ion-label')).first;
console.log(theElem);
expect(element.all(by.css('ion-input')).first().isPresent()).toEqual(true);
return items[1];
});
});
});
});

View File

@ -1,12 +0,0 @@
{
"extends": "../tsconfig.ng-cli.json",
"compilerOptions": {
"outDir": "../out-tsc/e2e",
"module": "commonjs",
"target": "es5",
"types": [
"jasmine",
"node"
]
}
}

View File

@ -1,12 +0,0 @@
{
"name": "insight-ui",
"app_id": "",
"type": "ionic-angular",
"integrations": {
"cordova": {}
},
"proxies": [{
"path": "/api",
"proxyUrl": "http://localhost:3000/api"
}]
}

View File

@ -1,44 +0,0 @@
// Karma configuration file, see link for more information
// https://karma-runner.github.io/0.13/config/configuration-file.html
module.exports = function (config) {
config.set({
basePath: '',
frameworks: ['jasmine', '@angular/cli'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter'),
require('karma-coverage-istanbul-reporter'),
require('@angular/cli/plugins/karma')
],
client:{
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
files: [
{ pattern: './src/test.ts', watched: false }
],
preprocessors: {
'./src/test.ts': ['@angular/cli']
},
mime: {
'text/x-typescript': ['ts','tsx']
},
coverageIstanbulReporter: {
reports: [ 'html', 'lcovonly' ],
fixWebpackSourcePaths: true
},
angularCli: {
environment: 'dev'
},
reporters: config.angularCli && config.angularCli.codeCoverage
? ['progress', 'coverage-istanbul']
: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: false
});
};

View File

@ -1,65 +0,0 @@
{
"name": "insight-ui",
"private": true,
"scripts": {
"clean": "ionic-app-scripts clean",
"build": "ionic-app-scripts build",
"ionic:build": "ionic-app-scripts build",
"ionic:serve": "ionic-app-scripts serve",
"e2e": "ionic-app-scripts build && protractor",
"postinstall": "webdriver-manager update --gecko false",
"start": "ionic serve",
"test": "ng test --code-coverage",
"cov": "opn coverage/index.html",
"test-ci": "ng test --watch=false --code-coverage && npm run e2e"
},
"dependencies": {
"@angular/common": "4.1.3",
"@angular/compiler": "4.1.3",
"@angular/compiler-cli": "4.1.3",
"@angular/core": "4.1.3",
"@angular/forms": "4.1.3",
"@angular/http": "4.1.3",
"@angular/platform-browser": "4.1.3",
"@angular/platform-browser-dynamic": "4.1.3",
"@angular/router": "4.1.3",
"@ionic-native/core": "3.10.2",
"@ionic-native/splash-screen": "3.10.2",
"@ionic-native/status-bar": "3.10.2",
"@ionic/storage": "2.0.1",
"angular2-moment": "^1.6.0",
"angular2-qrcode": "^2.0.1",
"ionic-angular": "3.4.2",
"ionicons": "3.0.0",
"rxjs": "5.4.0",
"sw-toolbox": "3.6.0",
"zone.js": "0.8.12"
},
"devDependencies": {
"@angular/cli": "1.1.2",
"@ionic/app-scripts": "1.3.7",
"@types/jasmine": "2.5.41",
"@types/node": "7.0.4",
"codecov": "2.2.0",
"ionic": "3.9.2",
"jasmine-core": "2.5.2",
"jasmine-spec-reporter": "3.2.0",
"karma": "1.4.1",
"karma-chrome-launcher": "2.1.1",
"karma-cli": "1.0.1",
"karma-coverage-istanbul-reporter": "1.2.1",
"karma-jasmine": "1.1.0",
"karma-jasmine-html-reporter": "0.2.2",
"opn-cli": "^3.1.0",
"protractor": "5.1.2",
"serve-static": "1.12.3",
"ts-node": "3.0.4",
"tslint": "5.3.2",
"tslint-eslint-rules": "4.1.1",
"typescript": "2.3.3"
},
"engines": {
"node": ">=8"
},
"license": "MIT"
}

View File

@ -1,33 +0,0 @@
// Protractor configuration file, see link for more information
// https://github.com/angular/protractor/blob/master/lib/config.ts
const { SpecReporter } = require('jasmine-spec-reporter');
exports.config = {
allScriptsTimeout: 11000,
specs: [
'./e2e/**/*.e2e-spec.ts'
],
capabilities: {
'browserName': 'chrome'
},
directConnect: true,
baseUrl: 'http://localhost:4200/',
framework: 'jasmine',
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000,
print: function() {}
},
useAllAngular2AppRoots: true,
beforeLaunch: function() {
require('ts-node').register({
project: 'e2e/tsconfig.e2e.json'
});
require('connect')().use(require('serve-static')('www')).listen(4200);
},
onPrepare() {
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
}
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 818 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

View File

@ -1,63 +0,0 @@
import { Component, ViewChild } from '@angular/core';
import { Platform, MenuController, Nav } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import {
HomePage,
BlocksPage,
BroadcastTxPage,
NodeStatusPage,
VerifyMessagePage
} from '../pages';
@Component({
templateUrl: './app.html'
})
export class InsightApp {
@ViewChild(Nav) public nav: Nav;
private menu: MenuController;
private platform: Platform;
private splash: SplashScreen;
private status: StatusBar;
public rootPage: any;
public pages: Array<{ title: string, component: any }>;
constructor(platform: Platform, menu: MenuController, splash: SplashScreen, status: StatusBar) {
this.menu = menu;
this.platform = platform;
this.splash = splash;
this.status = status;
this.rootPage = HomePage;
this.initializeApp();
// set our app's pages
this.pages = [
{ title: 'Home', component: HomePage },
{ title: 'Blocks', component: BlocksPage },
{ title: 'Broadcast Transaction', component: BroadcastTxPage },
{ title: 'Verify Signed Message', component: VerifyMessagePage },
{ title: 'Node Status', component: NodeStatusPage }
];
}
private initializeApp(): void {
this.platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
this.status.styleDefault();
this.splash.hide();
});
}
public openPage(page: any): void {
// close the menu when clicking a link from the menu
this.menu.close();
// navigate to the new page if it is not the current page
this.nav.setRoot(page.component);
}
}

View File

@ -1,13 +0,0 @@
<ion-menu [content]="content">
<ion-content>
<ion-list>
<button ion-item *ngFor="let p of pages" (click)="openPage(p)">
{{p.title}}
</button>
</ion-list>
</ion-content>
</ion-menu>
<ion-nav [root]="rootPage" #content swipeBackEnabled="false"></ion-nav>

View File

@ -1,45 +0,0 @@
import { HttpModule } from '@angular/http';
import { NgModule, ErrorHandler } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { InsightApp } from './app.component';
import { PagesModule, HomePage, BlocksPage, BroadcastTxPage, NodeStatusPage, VerifyMessagePage } from '../pages';
import { BlocksService, StorageService } from '../services';
import { ApiProvider } from '../providers/api/api';
import { CurrencyProvider } from '../providers/currency/currency';
import { BlocksProvider } from '../providers/blocks/blocks';
@NgModule({
declarations: [
InsightApp
],
imports: [
BrowserModule,
HttpModule,
PagesModule,
IonicModule.forRoot(InsightApp)
],
bootstrap: [IonicApp],
entryComponents: [
InsightApp,
HomePage,
BlocksPage,
BroadcastTxPage,
NodeStatusPage,
VerifyMessagePage
],
providers: [
StatusBar,
SplashScreen,
StorageService,
BlocksService,
{provide: ErrorHandler, useClass: IonicErrorHandler},
ApiProvider,
CurrencyProvider,
BlocksProvider
]
})
export class AppModule {}

View File

@ -1,37 +0,0 @@
// http://ionicframework.com/docs/v2/theming/
// App Global Sass
// --------------------------------------------------
// Put style rules here that you want to apply globally. These
// styles are for the entire app and not just one component.
// Additionally, this file can be also used as an entry point
// to import other Sass files to be included in the output CSS.
.ellipsis {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.summary ion-label {
color: #333;
font-weight: bold;
}
.summary ion-item {
color: #999;
font-size: 1.4rem;
}
body {
user-select: text;
}
// Shared Sass variables, which can be used to adjust Ionic's
// default Sass variables, belong in "theme/variables.scss".
//
// To declare rules for a specific mode, create a child rule
// for the .md, .ios, or .wp mode classes. The mode class is
// automatically applied to the <body> element in the app.

View File

@ -1,29 +0,0 @@
import { InsightApp } from './app.component';
import { MenuMock, NavMock, PlatformMock, SplashMock, StatusMock } from '../mocks';
import { BroadcastTxPage } from '../pages';
let instance: InsightApp = null;
describe('InsightApp', () => {
beforeEach(() => {
instance = new InsightApp((<any> new PlatformMock), (<any> new MenuMock), (<any>new SplashMock()), (<any>new StatusMock()));
instance['nav'] = (<any>new NavMock());
});
it('initializes with four possible pages', () => {
expect(instance['pages'].length).toEqual(4);
});
it('initializes with a root page', () => {
expect(instance['rootPage']).not.toBe(null);
});
it('opens a page', () => {
spyOn(instance['menu'], 'close');
spyOn(instance['nav'], 'setRoot');
instance.openPage(instance['pages'][1]);
expect(instance['menu']['close']).toHaveBeenCalled();
expect(instance['nav'].setRoot).toHaveBeenCalledWith(BroadcastTxPage);
});
});

View File

@ -1,5 +0,0 @@
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,19 +0,0 @@
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { IonicModule } from 'ionic-angular';
@NgModule({
declarations: [
],
imports: [
FormsModule,
IonicModule,
ReactiveFormsModule
],
exports: [
],
entryComponents: [],
providers: []
})
export class ComponentsModule {}

View File

@ -1,15 +0,0 @@
<ion-navbar color="primary">
<button ion-button menuToggle>
<ion-icon name="menu"></ion-icon>
</button>
<ion-title>{{title}}</ion-title>
<ion-buttons end>
<button ion-button (click)="changeCurrency()">
<ion-icon name="logo-bitcoin" *ngIf="currency.currencySymbol !== 'USD'"></ion-icon><ion-icon name="logo-usd" *ngIf="currency.currencySymbol === 'USD'"></ion-icon>&nbsp;{{ currency.currencySymbol }}
</button>
<button ion-button icon-only (click)="toggleSearch()">
<ion-icon name="search"></ion-icon>
</button>
</ion-buttons>
</ion-navbar>
<ion-searchbar [hidden]="!showSearch" (ionInput)="search($event)" placeholder="{{ 'Search for block, transaction or address' }}" [(ngModel)]="q" [debounce]="1500"></ion-searchbar>

View File

@ -1,16 +0,0 @@
import { NgModule } from '@angular/core';
import { IonicModule } from 'ionic-angular';
import { HeadNavComponent } from './head-nav';
@NgModule({
declarations: [
HeadNavComponent
],
imports: [
IonicModule
],
exports: [
HeadNavComponent
]
})
export class HeadNavComponentModule {}

View File

@ -1,3 +0,0 @@
head-nav {
}

View File

@ -1,145 +0,0 @@
import { Component } from '@angular/core';
import { Input } from '@angular/core';
import { NavController } from 'ionic-angular';
import { Http } from '@angular/http';
import { ApiProvider } from '../../providers/api/api';
import { CurrencyProvider } from '../../providers/currency/currency';
import { ActionSheetController } from 'ionic-angular';
/**
* Generated class for the HeadNavComponent component.
*
* See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html
* for more info on Angular Components.
*/
@Component({
selector: 'head-nav',
templateUrl: 'head-nav.html'
})
export class HeadNavComponent {
public showSearch: boolean = false;
public loading: boolean;
@Input() public title: string;
public q: string;
public badQuery: boolean = false;
constructor(private navCtrl: NavController, private http: Http, private api: ApiProvider, public currency: CurrencyProvider, public actionSheetCtrl: ActionSheetController) {
}
public search(): void {
this.showSearch = false;
let apiPrefix: string = this.api.apiPrefix;
this.http.get(apiPrefix + 'block/' + this.q).subscribe(
function (data: any): void {
this.resetSearch();
console.log('block', data);
let parsedData: any = JSON.parse(data._body);
this.navCtrl.push('block-detail', {
'blockHash': parsedData.hash
});
}.bind(this),
() => {
this.http.get(apiPrefix + 'tx/' + this.q).subscribe(
function (data: any): void {
this.resetSearch();
console.log('tx', data);
let parsedData: any = JSON.parse(data._body);
this.navCtrl.push('transaction', {
'txId': parsedData.txid
});
}.bind(this),
() => {
this.http.get(apiPrefix + 'addr/' + this.q).subscribe(
function (data: any): void {
this.resetSearch();
console.log('addr', data);
let parsedData: any = JSON.parse(data._body);
this.navCtrl.push('address', {
'addrStr': parsedData.addrStr
});
}.bind(this),
() => {
this.http.get(apiPrefix + 'block-index/' + this.q).subscribe(
function (data: any): void {
this.resetSearch();
let parsedData: any = JSON.parse(data._body);
this.navCtrl.push('block-detail', {
'blockHash': parsedData.blockHash
});
}.bind(this),
function (): void {
this.loading = false;
this.reportBadQuery();
}.bind(this)
);
}
);
}
);
}
);
}
/* tslint:disable:no-unused-variable */
private reportBadQuery(): void {
this.badQuery = true;
console.log('badQuery', this.badQuery);
setTimeout(
function (): void {
this.badQuery = false;
console.log('badQuery', this.badQuery);
}.bind(this),
2000
);
};
private resetSearch(): void {
this.q = '';
this.loading = false;
}
/* tslint:enable:no-unused-variable */
public changeCurrency(): void {
let actionSheet: any = this.actionSheetCtrl.create({
title: 'Change Denomination',
buttons: [
{
text: 'USD',
handler: () => {
this.currency.setCurrency('USD');
}
},
{
text: 'BTC',
handler: () => {
this.currency.setCurrency('BTC');
}
},
{
text: 'mBTC',
handler: () => {
this.currency.setCurrency('mBTC');
}
},
{
text: 'bits',
handler: () => {
this.currency.setCurrency('bits');
}
},
{
text: 'Cancel',
role: 'cancel'
}
]
});
actionSheet.present();
}
public toggleSearch(): void {
this.showSearch = !this.showSearch;
}
}

View File

@ -1 +0,0 @@
export * from './components.module';

View File

@ -1,45 +0,0 @@
<!-- Generated template for the LatestBlocksComponent component -->
<div>
<div *ngIf="loading">
<ion-spinner name="crescent"></ion-spinner>
</div>
<div *ngIf="!loading">
<ion-grid>
<ion-row>
<ion-col><b>Height</b></ion-col>
<ion-col *ngIf="showTimeAs === 'age'"><b>Age</b></ion-col>
<ion-col *ngIf="showTimeAs === 'timestamp'"><b>Timestamp</b></ion-col>
<ion-col text-right><b>Transactions</b></ion-col>
<ion-col hideWhen="portrait"><b>Mined By</b></ion-col>
<ion-col text-right><b>Size</b></ion-col>
</ion-row>
<ion-row *ngFor="let block of getBlocks()">
<ion-col>
<a (click)="goToBlock(block.hash)">{{block.height}}</a>
</ion-col>
<ion-col *ngIf="showTimeAs === 'age'">
{{ block.time | amFromUnix | amTimeAgo }}
</ion-col>
<ion-col *ngIf="showTimeAs === 'timestamp'">
{{ block.time * 1000 | date:'medium' }}
</ion-col>
<ion-col text-right>
{{block.txlength}}
</ion-col>
<ion-col hideWhen="portrait">
<a *ngIf="block.poolInfo.poolName" href="{{block.poolInfo.url}}">{{block.poolInfo.poolName}}</a>
</ion-col>
<ion-col text-right>
{{ block.size }}
</ion-col>
</ion-row>
<ion-row *ngIf="showAllBlocksButton">
<ion-col text-center>
<button ion-button (click)="goToBlocks()">See all blocks</button>
</ion-col>
</ion-row>
</ion-grid>
</div>
</div>

View File

@ -1,18 +0,0 @@
import { NgModule } from '@angular/core';
import { IonicModule } from 'ionic-angular';
import { LatestBlocksComponent } from './latest-blocks';
import { MomentModule } from 'angular2-moment';
@NgModule({
declarations: [
LatestBlocksComponent
],
imports: [
IonicModule,
MomentModule
],
exports: [
LatestBlocksComponent
]
})
export class LatestBlocksComponentModule {}

View File

@ -1,23 +0,0 @@
latest-blocks {
ion-grid {
// border: 2px solid green;
margin: 10px 0 20px;
ion-row {
border-top: 1px solid #ccc;
}
ion-row:nth-child(even) {
background-color: #f4f4f4;
}
ion-row:first-child {
background-color: white;
border-top: none;
}
ion-row:last-child {
background-color: white;
}
}
}

View File

@ -1,65 +0,0 @@
import { Component, NgZone, Input } from '@angular/core';
import { BlocksProvider } from '../../providers/blocks/blocks';
import { NavController } from 'ionic-angular';
/**
* Generated class for the LatestBlocksComponent component.
*
* See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html
* for more info on Angular Components.
*/
@Component({
selector: 'latest-blocks',
templateUrl: 'latest-blocks.html'
})
export class LatestBlocksComponent {
public loading: boolean = true;
public blocks: Array<any> = [];
@Input() public numBlocks: number;
@Input() public showAllBlocksButton: boolean;
@Input() public showTimeAs: string;
constructor(private blocksProvider: BlocksProvider, private navCtrl: NavController, ngZone: NgZone) {
this.loadBlocks();
ngZone.runOutsideAngular(() => {
setInterval(
function (): void {
ngZone.run(function (): void {
this.loadBlocks.call(this);
}.bind(this));
}.bind(this),
1000 * 30
);
});
}
private loadBlocks(): void {
this.blocksProvider.getBlocks().subscribe(
(data) => {
this.blocks = JSON.parse(data['_body']).blocks;
this.loading = false;
},
(err) => {
console.log('err', err);
this.loading = false;
}
);
}
public goToBlock(blockHash: string): void {
this.navCtrl.push('block-detail', {
'blockHash': blockHash
});
}
public getBlocks(): Array<any> {
/* tslint:disable:no-unused-variable */
return this.blocks.filter((block, index) => index < this.numBlocks);
/* tslint:enable:no-unused-variable */
}
public goToBlocks(): void {
this.navCtrl.push('blocks');
}
}

View File

@ -1,27 +0,0 @@
<div>
<div *ngIf="loading">
<ion-spinner name="crescent"></ion-spinner>
</div>
<div *ngIf="!loading">
<ion-grid>
<ion-row>
<ion-col><b>Hash</b></ion-col>
<ion-col text-right><b>Value Out</b></ion-col>
</ion-row>
<ion-row *ngFor="let tx of transactions">
<ion-col col-9>
<div class="ellipsis">
<a (click)="goToTx(tx.txid)">{{ tx.txid }}</a>
</div>
</ion-col>
<ion-col col-3 text-right>
{{ currency.getConversion(tx.valueOut) }}
</ion-col>
</ion-row>
</ion-grid>
</div>
</div>

View File

@ -1,16 +0,0 @@
import { NgModule } from '@angular/core';
import { IonicModule } from 'ionic-angular';
import { LatestTransactionsComponent } from './latest-transactions';
@NgModule({
declarations: [
LatestTransactionsComponent
],
imports: [
IonicModule
],
exports: [
LatestTransactionsComponent
]
})
export class LatestTransactionsComponentModule {}

View File

@ -1,23 +0,0 @@
latest-transactions {
ion-grid {
// border: 2px solid green;
margin: 10px 0 20px;
ion-row {
border-top: 1px solid #ccc;
}
ion-row:nth-child(even) {
background-color: #f4f4f4;
}
ion-row:first-child {
background-color: white;
border-top: none;
}
ion-row:last-child {
background-color: white;
}
}
}

View File

@ -1,65 +0,0 @@
import { Component, NgZone, Input } from '@angular/core';
import { Http } from '@angular/http';
import { NavController } from 'ionic-angular';
import { ApiProvider } from '../../providers/api/api';
import { CurrencyProvider } from '../../providers/currency/currency';
/**
* Generated class for the LatestTransactionsComponent component.
*
* See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html
* for more info on Angular Components.
*/
@Component({
selector: 'latest-transactions',
templateUrl: 'latest-transactions.html'
})
export class LatestTransactionsComponent {
private loading: boolean = true;
private transactions: Array<any> = [];
@Input() public refreshSeconds: number = 10;
private timer: number;
constructor(private http: Http, private navCtrl: NavController, private api: ApiProvider, public currency: CurrencyProvider, private ngZone: NgZone) {
this.loadTransactions();
}
public ngOnChanges(): void {
if (this.timer) {
clearInterval(this.timer);
}
this.ngZone.runOutsideAngular(() => {
this.timer = setInterval(
function (): void {
this.ngZone.run(function (): void {
this.loadTransactions.call(this);
}.bind(this));
}.bind(this),
1000 * this.refreshSeconds
);
});
}
private loadTransactions(): void {
let url: string = this.api.apiPrefix + 'txs';
this.http.get(url).subscribe(
(data) => {
this.transactions = JSON.parse(data['_body']);
this.loading = false;
},
(err) => {
console.log('err is', err);
this.loading = false;
}
);
}
public goToTx(txId: string): void {
this.navCtrl.push('transaction', {
'txId': txId
});
}
}

View File

@ -1,14 +0,0 @@
<div *ngIf="loading">
<ion-spinner name="crescent"></ion-spinner>
</div>
<div *ngIf="!loading">
<ion-grid>
<ion-row *ngFor="let tx of transactions.txs">
<ion-col col-12>
<transaction [tx]="tx"></transaction>
</ion-col>
</ion-row>
</ion-grid>
</div>

View File

@ -1,18 +0,0 @@
import { NgModule } from '@angular/core';
import { IonicModule } from 'ionic-angular';
import { TransactionListComponent } from './transaction-list';
import { TransactionComponentModule } from '../transaction/transaction.module';
@NgModule({
declarations: [
TransactionListComponent
],
imports: [
IonicModule,
TransactionComponentModule
],
exports: [
TransactionListComponent
]
})
export class TransactionListComponentModule {}

View File

@ -1,3 +0,0 @@
transaction-list {
}

View File

@ -1,40 +0,0 @@
import { Component } from '@angular/core';
import { Input } from '@angular/core';
import { Http } from '@angular/http';
import { ApiProvider } from '../../providers/api/api';
/**
* Generated class for the TransactionListComponent component.
*
* See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html
* for more info on Angular Components.
*/
@Component({
selector: 'transaction-list',
templateUrl: 'transaction-list.html'
})
export class TransactionListComponent {
public loading: boolean = true;
@Input() public queryType: string;
@Input() public queryValue: string;
public transactions: any = [];
constructor(private http: Http, private api: ApiProvider) {
}
private ngOnInit(): void {
let url: string = this.api.apiPrefix + 'txs?' + this.queryType + '=' + this.queryValue;
this.http.get(url).subscribe(
(data) => {
this.transactions = JSON.parse(data['_body']);
this.loading = false;
},
(err) => {
console.log('err is', err);
this.loading = false;
}
);
}
}

View File

@ -1,99 +0,0 @@
<ion-grid>
<ion-row>
<ion-col col-8>
<div class="ellipsis">
<ion-icon name="add-circle" [hidden]="expanded" (click)="toggleExpanded()"></ion-icon><ion-icon name="remove-circle" [hidden]="!expanded" (click)="toggleExpanded()"></ion-icon> <span><a (click)="goToTx(tx.txid)">{{ tx.txid }}</a></span>
</div>
</ion-col>
<ion-col col-4 text-right>
<div [hidden]="!tx.firstSeenTs">
<span translate>first seen at</span>
<time>{{tx.firstSeenTs * 1000 | date:'medium'}}</time>
</div>
<div [hidden]="!tx.blocktime && tx.firstSeenTs">
<span translate>mined</span>
<time>{{tx.time * 1000 | date:'medium'}}</time>
</div>
</ion-col>
</ion-row>
<ion-row>
<ion-col col-12 col-md-5>
<ion-list [hidden]="!tx.isCoinBase">
<ion-item>
No Inputs (Newly Generated Coins)
</ion-item>
</ion-list>
<ion-list [hidden]="tx.isCoinBase">
<ion-item *ngFor="let vin of aggregateItems(tx.vin)">
<div>
<div class="ellipsis">
<p><a (click)="goToAddress(vin.addr)">{{ vin.addr }}</a></p>
</div>
<div [hidden]="!expanded">
<p *ngIf="vin.confirmations"><b>Confirmations</b> {{vin.confirmations}}</p>
<p><b>scriptSig</b></p>
<div *ngFor="let item of vin.items">
<div *ngIf="item.scriptSig">
<div *ngFor="let scriptSig of item.scriptSig.asm | split:' '">
<div class="ellipsis">
<p>{{ scriptSig }}</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div item-end>
{{ currency.getConversion(vin.value) }}
</div>
</ion-item>
</ion-list>
</ion-col>
<ion-col col-12 col-md-1 text-center>
<ion-icon name="arrow-forward"></ion-icon>
</ion-col>
<ion-col col-12 col-md-6>
<ion-list>
<ion-item *ngFor="let vout of tx.vout">
<div>
<div class="ellipsis">
<p><a (click)="goToAddress(getAddress(vout))">{{ getAddress(vout) }}</a></p>
</div>
<div [hidden]="!expanded">
<p><b>Type</b> {{vout.scriptPubKey.type}}</p>
<p><b>scriptPubKey</b></p>
<div class="ellipsis">
<p>{{vout.scriptPubKey.asm}}</p>
</div>
</div>
</div>
<div item-end>
{{ currency.getConversion(vout.value) }}
<span [hidden]="!vout.spentTxId">(S)</span>
<span [hidden]="vout.spentTxId">(U)</span>
</div>
</ion-item>
</ion-list>
</ion-col>
</ion-row>
<ion-row>
<ion-col col-3>
<span [hidden]="tx.isCoinBase">Fee {{ currency.getConversion(tx.fees) }}</span>
</ion-col>
<ion-col col-6 text-center>
{{ tx.confirmations }} Confirmations
</ion-col>
<ion-col col-3 text-right>
<span class="">{{ currency.getConversion(tx.valueOut) }}</span>
</ion-col>
</ion-row>
</ion-grid>

View File

@ -1,18 +0,0 @@
import { NgModule } from '@angular/core';
import { IonicModule } from 'ionic-angular';
import { TransactionComponent } from './transaction';
import { SplitPipe } from '../../pipes/split/split';
@NgModule({
declarations: [
TransactionComponent,
SplitPipe
],
imports: [
IonicModule
],
exports: [
TransactionComponent
]
})
export class TransactionComponentModule {}

View File

@ -1,14 +0,0 @@
transaction {
// TODO Customize the grid to have 13 columns so that we have 6-col inputs, 6-col outputs, 1 col arrow
// See http://ionicframework.com/docs/api/components/grid/Grid/#customizing-the-grid
ion-grid {
background-color: #F4F4F4;
border: 1px solid #eee;
border-radius: 2px;
ion-row {
border: 1px solid #eee;
}
}
}

View File

@ -1,115 +0,0 @@
import { Component } from '@angular/core';
import { Input } from '@angular/core';
import { NavController } from 'ionic-angular';
import { CurrencyProvider } from '../../providers/currency/currency';
/**
* Generated class for the TransactionComponent component.
*
* See https://angular.io/docs/ts/latest/api/core/index/ComponentMetadata-class.html
* for more info on Angular Components.
*/
@Component({
selector: 'transaction',
templateUrl: 'transaction.html'
})
export class TransactionComponent {
private COIN: number = 100000000;
public expanded: boolean = false;
@Input() public tx: any = {};
constructor(private navCtrl: NavController, public currency: CurrencyProvider) {
}
public getAddress(vout: any): string {
if (vout.scriptPubKey && vout.scriptPubKey.addresses) {
return vout.scriptPubKey.addresses[0];
} else {
return 'Unparsed address';
}
}
public goToTx(txId: string): void {
this.navCtrl.push('transaction', {
'txId': txId
});
}
public goToAddress(addrStr: string): void {
this.navCtrl.push('address', {
'addrStr': addrStr
});
}
public toggleExpanded(): void {
this.expanded = !this.expanded;
}
public aggregateItems(items: Array<any>): Array<any> {
if (!items) return [];
let l: number = items.length;
let ret: Array<any> = [];
let tmp: any = {};
let u: number = 0;
for (let i: number = 0; i < l; i++) {
let notAddr: boolean = false;
// non standard input
if (items[i].scriptSig && !items[i].addr) {
items[i].addr = 'Unparsed address [' + u++ + ']';
items[i].notAddr = true;
notAddr = true;
}
// non standard output
if (items[i].scriptPubKey && !items[i].scriptPubKey.addresses) {
items[i].scriptPubKey.addresses = ['Unparsed address [' + u++ + ']'];
items[i].notAddr = true;
notAddr = true;
}
// multiple addr at output
if (items[i].scriptPubKey && items[i].scriptPubKey.addresses.length > 1) {
items[i].addr = items[i].scriptPubKey.addresses.join(',');
ret.push(items[i]);
continue;
}
let addr: string = items[i].addr || (items[i].scriptPubKey && items[i].scriptPubKey.addresses[0]);
if (!tmp[addr]) {
tmp[addr] = {};
tmp[addr].valueSat = 0;
tmp[addr].count = 0;
tmp[addr].addr = addr;
tmp[addr].items = [];
}
tmp[addr].isSpent = items[i].spentTxId;
tmp[addr].doubleSpentTxID = tmp[addr].doubleSpentTxID || items[i].doubleSpentTxID;
tmp[addr].doubleSpentIndex = tmp[addr].doubleSpentIndex || items[i].doubleSpentIndex;
tmp[addr].dbError = tmp[addr].dbError || items[i].dbError;
tmp[addr].valueSat += Math.round(items[i].value * this.COIN);
tmp[addr].items.push(items[i]);
tmp[addr].notAddr = notAddr;
if (items[i].unconfirmedInput)
tmp[addr].unconfirmedInput = true;
tmp[addr].count++;
}
for (let v in tmp) {
let obj: any = tmp[v];
obj.value = obj.value || parseInt(obj.valueSat) / this.COIN;
ret.push(obj);
}
return ret;
};
}

View File

@ -1,14 +0,0 @@
/*
Declaration files are how the Typescript compiler knows about the type information(or shape) of an object.
They're what make intellisense work and make Typescript know all about your code.
A wildcard module is declared below to allow third party libraries to be used in an app even if they don't
provide their own type declarations.
To learn more about using third party libraries in an Ionic app, check out the docs here:
http://ionicframework.com/docs/v2/resources/third-party-libs/
For more info on type definition files, check out the Typescript docs here:
https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html
*/
declare module '*';

View File

@ -1,41 +0,0 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8">
<title>Insight</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="format-detection" content="telephone=no">
<meta name="msapplication-tap-highlight" content="no">
<link rel="icon" type="image/x-icon" href="assets/icon/favicon.ico">
<link rel="manifest" href="manifest.json">
<meta name="theme-color" content="#4e8ef7">
<!-- cordova.js required for cordova apps -->
<script src="cordova.js"></script>
<!-- un-comment this code to enable service worker
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('service-worker.js')
.then(() => console.log('service worker installed'))
.catch(err => console.error('Error', err));
}
</script>-->
<link href="build/main.css" rel="stylesheet">
</head>
<body>
<!-- Ionic's root component and where the app will load -->
<ion-app></ion-app>
<!-- The polyfills js is generated during the build process -->
<script src="build/polyfills.js"></script>
<!-- The bundle js is generated during the build process -->
<script src="build/main.js"></script>
</body>
</html>

View File

@ -1,13 +0,0 @@
{
"name": "Ionic",
"short_name": "Ionic",
"start_url": "index.html",
"display": "standalone",
"icons": [{
"src": "assets/imgs/logo.png",
"sizes": "512x512",
"type": "image/png"
}],
"background_color": "#4e8ef7",
"theme_color": "#4e8ef7"
}

View File

@ -1,187 +0,0 @@
/* tslint:disable */
// IONIC:
import { EventEmitter} from '@angular/core';
import { FormBuilder } from '@angular/forms';
// from
// https://github.com/stonelasley/ionic-mocks/
// should the package be incorporated?
declare var jasmine: any;
export class AlertMock {
public static instance(): any {
let instance = jasmine.createSpyObj('Alert', ['present', 'dismiss']);
instance.present.and.returnValue(Promise.resolve());
instance.dismiss.and.returnValue(Promise.resolve());
return instance;
}
}
export class AlertControllerMock {
public static instance(alertMock?: AlertMock): any {
let instance = jasmine.createSpyObj('AlertController', ['create']);
instance.create.and.returnValue(alertMock || AlertMock.instance());
return instance;
}
}
export class ToastMock {
public create(): any {
let rtn: Object = {};
rtn['present'] = (() => true);
return rtn;
}
}
export class ConfigMock {
public get(): any {
return '';
}
public getBoolean(): boolean {
return true;
}
public getNumber(): number {
return 1;
}
public setTransition(): void {
return;
}
}
export class FormMock {
public register(): any {
return true;
}
}
export class NavMock {
public pop(): any {
return new Promise(function(resolve: Function): void {
resolve();
});
}
public push(): any {
return new Promise(function(resolve: Function): void {
resolve();
});
}
public getActive(): any {
return {
'instance': {
'model': 'something',
},
};
}
public setRoot(): any {
return true;
}
public popToRoot(): any {
return true;
}
}
export class PlatformMock {
public ready(): Promise<{String}> {
return new Promise((resolve) => {
resolve('READY');
});
}
public registerBackButtonAction(fn: Function, priority?: number): Function {
return (() => true);
}
public hasFocus(ele: HTMLElement): boolean {
return true;
}
public doc(): HTMLDocument {
return document;
}
public is(): boolean {
return true;
}
public getElementComputedStyle(container: any): any {
return {
paddingLeft: '10',
paddingTop: '10',
paddingRight: '10',
paddingBottom: '10',
};
}
public onResize(callback: any) {
return callback;
}
public registerListener(ele: any, eventName: string, callback: any): Function {
return (() => true);
}
public win(): Window {
return window;
}
public raf(callback: any): number {
return 1;
}
public timeout(callback: any, timer: number): any {
return setTimeout(callback, timer);
}
public cancelTimeout(id: any) {
// do nothing
}
public getActiveElement(): any {
return document['activeElement'];
}
}
export class SplashMock {
public hide() {
return Promise.resolve(true);
}
}
export class StatusMock {
public styleDefault() {
return Promise.resolve(true);
}
}
export class MenuMock {
public close(): any {
return new Promise((resolve: Function) => {
resolve();
});
}
}
export class AppMock {
public getActiveNav(): NavMock {
return new NavMock();
}
}
/* tslint:enable */

Some files were not shown because too many files have changed in this diff Show More