Compare commits

..

1 Commits

Author SHA1 Message Date
bumi ece573ab3c load kredits contract definition from kredits-contracts package 2017-02-05 21:48:18 +08:00
125 changed files with 832 additions and 38661 deletions
+4
View File
@@ -0,0 +1,4 @@
{
"directory": "bower_components",
"analytics": false
}
+1 -1
View File
@@ -5,5 +5,5 @@
Setting `disableAnalytics` to true will prevent any data from being sent. Setting `disableAnalytics` to true will prevent any data from being sent.
*/ */
"disableAnalytics": true "disableAnalytics": false
} }
-20
View File
@@ -1,20 +0,0 @@
# unconventional js
/blueprints/*/files/
/vendor/
# compiled output
/dist/
/tmp/
# dependencies
/bower_components/
/node_modules/
# misc
/coverage/
!.*
# ember-try
/.node_modules.ember-try/
/bower.json.ember-try
/package.json.ember-try
-47
View File
@@ -1,47 +0,0 @@
module.exports = {
root: true,
parserOptions: {
ecmaVersion: 2017,
sourceType: 'module'
},
globals: {
console: true
},
plugins: [
'ember'
],
extends: [
'eslint:recommended',
'plugin:ember/recommended'
],
env: {
browser: true
},
rules: {
'ember/avoid-leaking-state-in-ember-objects': 'warn',
'no-console': 'off'
},
overrides: [
// node files
{
files: [
'.eslintrc.js',
'.template-lintrc.js',
'ember-cli-build.js',
'testem.js',
'blueprints/*/index.js',
'config/**/*.js',
'lib/*/index.js',
'server/**/*.js'
],
parserOptions: {
sourceType: 'script',
ecmaVersion: 2015
},
env: {
browser: false,
node: true
}
}
]
};
+7 -16
View File
@@ -1,26 +1,17 @@
# See https://help.github.com/ignore-files/ for more about ignoring files. # See https://help.github.com/ignore-files/ for more about ignoring files.
# compiled output # compiled output
/dist/ /dist
/tmp/ /tmp
# dependencies # dependencies
/bower_components/ /node_modules
/node_modules/ /bower_components
# misc # misc
/.env*
/.pnp*
/.sass-cache /.sass-cache
/connect.lock /connect.lock
/coverage/ /coverage/*
/libpeerconnection.log /libpeerconnection.log
/npm-debug.log* npm-debug.log*
/testem.log testem.log
/yarn-error.log
.tm_properties
# ember-try
/.node_modules.ember-try/
/bower.json.ember-try
/package.json.ember-try
+32
View File
@@ -0,0 +1,32 @@
{
"predef": [
"document",
"window",
"-Promise"
],
"browser": true,
"boss": true,
"curly": true,
"debug": false,
"devel": true,
"eqeqeq": true,
"evil": true,
"forin": false,
"immed": false,
"laxbreak": false,
"newcap": true,
"noarg": true,
"noempty": false,
"nonew": false,
"nomen": false,
"onevar": false,
"plusplus": false,
"regexp": false,
"undef": true,
"sub": true,
"strict": false,
"white": false,
"eqnull": true,
"esversion": 6,
"unused": true
}
-9
View File
@@ -1,9 +0,0 @@
'use strict';
module.exports = {
extends: 'recommended',
rules: {
'simple-unless': false
}
};
+10 -12
View File
@@ -1,27 +1,25 @@
--- ---
language: node_js language: node_js
node_js: node_js:
- "10" - "6"
sudo: false sudo: false
dist: xenial
addons:
chrome: stable
cache: cache:
directories: directories:
- $HOME/.npm - $HOME/.npm
- $HOME/.cache # includes bowers cache
env:
global:
# See https://git.io/vdao3 for details.
- JOBS=1
before_install: before_install:
- npm config set spin false - npm config set spin false
- npm install -g bower
- bower --version
- npm install phantomjs-prebuilt
- node_modules/phantomjs-prebuilt/bin/phantomjs --version
install:
- npm install
- bower install
script: script:
- npm run lint:hbs
- npm run lint:js
- npm test - npm test
+8 -71
View File
@@ -10,24 +10,22 @@ A short introduction of this app could easily go here.
You will need the following things properly installed on your computer. You will need the following things properly installed on your computer.
* [Git](https://git-scm.com/) * [Git](https://git-scm.com/)
* [Node.js](https://nodejs.org/) (with npm) * [Node.js](https://nodejs.org/) (with NPM)
* [Bower](https://bower.io/)
* [Ember CLI](https://ember-cli.com/) * [Ember CLI](https://ember-cli.com/)
* [Google Chrome](https://google.com/chrome/) * [PhantomJS](http://phantomjs.org/)
## Installation ## Installation
* `git clone git@github.com:67P/kredits-web.git` this repository * `git clone <repository-url>` this repository
* `cd kredits-web` * `cd kredits-web`
* `npm install` * `npm install`
* `bower install`
## Running / Development ## Running / Development
* `ember serve`
* `ember serve` - by default kredits-web connects to the Ethreum Kovan network
* Visit your app at [http://localhost:4200](http://localhost:4200). * Visit your app at [http://localhost:4200](http://localhost:4200).
* Visit your tests at [http://localhost:4200/tests](http://localhost:4200/tests).
See [working with locally deployed contracts](https://github.com/67P/kredits-web#working-with-locally-deployed-contracts) for details on how to develop with locally deployed contracts.
### Code Generators ### Code Generators
@@ -38,12 +36,6 @@ Make use of the many generators for code, try `ember help generate` for more det
* `ember test` * `ember test`
* `ember test --server` * `ember test --server`
### Linting
* `npm run lint:hbs`
* `npm run lint:js`
* `npm run lint:js -- --fix`
### Building ### Building
* `ember build` (development) * `ember build` (development)
@@ -51,66 +43,11 @@ Make use of the many generators for code, try `ember help generate` for more det
### Deploying ### Deploying
_(You need collaborator permissions on the 5apps Deploy project.)_ Specify what it takes to deploy your app.
`npm run deploy`
## Working with locally deployed contracts
The smart contracts and their JavaScript wrapper library are developed in the
[kredits-contracts](https://github.com/67P/kredits-contracts) repo/package.
You can run `kredits-web` on your machine, against a local, simulated Ethereum
network, provided e.g. by [ganache](http://truffleframework.com/ganache/).
[kredits-contracts](https://github.com/67P/kredits-contracts) holds all the tools
to start and set up such a simulated network, as well as to deploy smart
contracts to it.
These are the basic steps to get up and running:
#### 1. IPFS
Run a local IPFS deamon in offline mode.
* Make sure CORS headers are configured. See [IPFS](#ipfs) for more info.
* `ipfs daemon --offline`
#### 2. kredits-contracts
Get your local Ethereum development node running. (See [kredits-contracts README](https://github.com/67P/kredits-contracts)
for details.
* Clone [kredits-contracts](https://github.com/67P/kredits-contracts)
* `npm install`
* `npm run devchain` - runs a local development chain
* `npm run bootstrap` - bootstrap runs deploys all the contracts
* `npm link` - make the `kredits-contracts` module linkable as `kredits-contracts` on your machine (currently broken :( )
#### 3. kredits-web
With IPFS and Ethereum/ganache running, you can now start this Ember app.
* `npm link kredits-contracts` - link the local `kredits-contracts` package
* `npm run start:local` - WEB3_PROVIDER_URL=http://localhost:7545 must be set for local settings
If you restart the devchain your network ID changes. So kredits-contracts does not find the correct DAO Kernel address.
If that is the case the DAO address must be provided as `KREDITS_KERNEL_ADDRESS` environment variable.
* `KREDITS_KERNEL_ADDRESS=<0xYOURADDRESS> npm run start:local` - find your address with the `npm run dao:address` command in the kredits-contracts repo.
#### IPFS
Install IPFS with your favorite package manager and run
ipfs init (on initial installation)
ipfs config --json API.HTTPHeaders.Access-Control-Allow-Origin '["localhost:4200"]'
ipfs config --json API.HTTPHeaders.Access-Control-Allow-Methods '["PUT", "GET", "POST"]'
ipfs config --json API.HTTPHeaders.Access-Control-Allow-Credentials '["true"]'
## Further Reading / Useful Links ## Further Reading / Useful Links
* [ember.js](https://emberjs.com/) * [ember.js](http://emberjs.com/)
* [ember-cli](https://ember-cli.com/) * [ember-cli](https://ember-cli.com/)
* Development Browser Extensions * Development Browser Extensions
* [ember inspector for chrome](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi) * [ember inspector for chrome](https://chrome.google.com/webstore/detail/ember-inspector/bmdblncegkenkacieihfhpjfppoconhi)
+6 -2
View File
@@ -1,9 +1,13 @@
import Application from '@ember/application'; import Ember from 'ember';
import Resolver from './resolver'; import Resolver from './resolver';
import loadInitializers from 'ember-load-initializers'; import loadInitializers from 'ember-load-initializers';
import config from './config/environment'; import config from './config/environment';
const App = Application.extend({ let App;
Ember.MODEL_FACTORY_INJECTIONS = true;
App = Ember.Application.extend({
modulePrefix: config.modulePrefix, modulePrefix: config.modulePrefix,
podModulePrefix: config.podModulePrefix, podModulePrefix: config.podModulePrefix,
Resolver Resolver
@@ -1,70 +0,0 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
import { and, notEmpty } from '@ember/object/computed';
export default Component.extend({
attributes: null,
contributors: Object.freeze([]),
isValidContributor: notEmpty('contributorId'),
isValidKind: notEmpty('kind'),
isValidAmount: computed('amount', function() {
return parseInt(this.amount, 10) > 0;
}),
isValidDescription: notEmpty('description'),
isValidUrl: notEmpty('url'),
isValid: and('isValidContributor',
'isValidKind',
'isValidAmount',
'isValidDescription'),
init () {
this._super(...arguments);
this.set('defaultDate', new Date());
// Default attributes used by reset
this.set('attributes', {
contributorId: null,
kind: null,
date: [new Date()],
amount: null,
description: null,
url: null,
});
this.reset();
},
reset () {
this.setProperties(this.attributes);
},
actions: {
submit () {
if (!this.isValid) {
alert('Invalid data. Please review and try again.');
return;
}
const attributes = this.getProperties(Object.keys(this.attributes));
const [ date/* , time */ ] = attributes.date[0].toISOString().split('T');
attributes.date = date;
this.set('inProgress', true);
this.save(attributes)
.then((/*contribution*/) => {
this.reset();
}, err => {
console.warn(err);
window.alert('Something went wrong. Check the browser console for details.');
})
.finally(() => this.set('inProgress', false));
}
}
});
@@ -1,58 +0,0 @@
<form {{action "submit" on="submit"}}>
<p>
<select required onchange={{action (mut contributorId) value="target.value"}}>
<option value="" selected disabled hidden>Contributor</option>
{{#each contributors as |contributor|}}
<option value={{contributor.id}} selected={{eq contributorId contributor.id}}>{{contributor.github_username}}</option>
{{/each}}
</select>
</p>
<p>
<select required onchange={{action (mut kind) value="target.value"}}>
<option value="" selected disabled hidden>Kind</option>
<option value="community" selected={{eq kind "community"}}>Community</option>
<option value="design" selected={{eq kind "design"}}>Design</option>
<option value="dev" selected={{eq kind "dev"}}>Development</option>
<option value="docs" selected={{eq kind "docs"}}>Documentation</option>
<option value="ops" selected={{eq kind "ops"}}>IT Operations</option>
<option value="special" selected={{eq kind "ops"}}>Special</option>
</select>
</p>
<p>
{{ember-flatpickr
allowInput=false
altFormat="F j, Y"
altInput=true
altInputClass="date-alt"
date=date
dateFormat="Y-m-d"
defaultDate=defaultDate
maxDate=defaultDate
onChange=(action (mut date))
}}
</p>
<p>
{{input type="text"
placeholder="500"
value=amount
class=(if isValidAmount "valid" "")}}
</p>
<p>
{{input type="text"
placeholder="Description"
value=description
class=(if isValidDescription "valid" "")}}
</p>
<p>
{{input type="text"
placeholder="URL (optional)"
value=url
class=(if isValidUrl "valid" "")}}
</p>
<p class="actions">
{{input type="submit"
disabled=inProgress
value=(if inProgress "Processing" "Save")}}
</p>
</form>
+21 -64
View File
@@ -1,76 +1,33 @@
import Component from '@ember/component'; import Ember from 'ember';
import { and, notEmpty } from '@ember/object/computed';
import { inject as service } from '@ember/service';
import { isPresent } from '@ember/utils';
export default Component.extend({ export default Ember.Component.extend({
kredits: service(), id: null,
realName: null,
address: null,
attributes: null, classId: function() {
let value = this.get('id');
return (Ember.isEmpty(value)) ? null : 'valid';
}.property('id'),
// TODO: add proper address validation classRealName: function() {
isValidAccount: notEmpty('account'), let value = this.get('realName');
isValidName: notEmpty('name'), return (Ember.isEmpty(value)) ? null : 'valid';
isValidURL: notEmpty('url'), }.property('realName'),
isValidGithubUID: notEmpty('github_uid'),
isValidGithubUsername: notEmpty('github_username'),
isValidGiteaUsername: notEmpty('gitea_username'),
isValidWikiUsername: notEmpty('wiki_username'),
isValid: and(
'isValidAccount',
'isValidName',
'isValidGithubUID'
),
inProgress: false, classAddress: function() {
let value = this.get('address');
return (Ember.isEmpty(value)) ? null : 'valid';
}.property('address'),
init () {
this._super(...arguments);
this.setDefaultAttributes();
this.reset();
},
setDefaultAttributes () {
if (isPresent(this.attributes)) { return; }
this.set('attributes', {
account: null,
name: null,
kind: 'person',
url: null,
github_username: null,
github_uid: null,
gitea_username: null,
wiki_username: null
});
},
reset: function() {
this.setProperties(this.attributes);
},
actions: { actions: {
submit () { save() {
if (!this.isValid) { console.log('id', this.get('id'));
alert('Invalid data. Please review and try again.'); console.log('realName', this.get('realName'));
return; console.log('address', this.get('address'));
}
const attributes = Object.keys(this.attributes);
const contributor = this.getProperties(attributes);
this.set('inProgress', true);
this.save(contributor).then(() => {
this.reset();
}).catch(err => {
console.warn(err);
window.alert('Something went wrong. Please check the browser console.');
}).finally(() => {
this.set('inProgress', false);
});
} }
} }
+20 -44
View File
@@ -1,50 +1,26 @@
<form {{action "submit" on="submit"}}> <form {{action "save" on="submit"}}>
<p> <p>
<label for="c-account">Ethereum account</label> {{input name="id"
{{input name="account" id="c-account" type="text"
type="text" value=account placeholder="GitHub UID (123)"
value=id
class=classId}}
</p>
<p>
{{input name="realname"
type="text"
placeholder="Carl Sagan"
value=realName
class=classRealName}}
</p>
<p>
{{input name="address"
type="text"
placeholder="0xF18E631Ea191aE4ebE70046Fcb01a436554421BA4" placeholder="0xF18E631Ea191aE4ebE70046Fcb01a436554421BA4"
class=(if isValidAccount "valid" "")}} value=address
</p> class=classAddress}}
<p>
<label for="c-kind">Kind</label>
<select required onchange={{action (mut kind) value="target.value"}} id="c-kind">
<option value="person" selected={{eq kind "person"}}>Person</option>
<option value="organization" selected={{eq kind "organization"}}>Organization</option>
</select>
</p>
<p>
<label for="c-name">Name</label>
{{input name="name" type="text" value=name placeholder="Zero Cool"
class=(if isValidName "valid" "") id="c-name"}}
</p>
<p>
<label for="c-url">URL</label>
{{input name="url" type="text" value=url placeholder="http://zerocool.bit"
class=(if isValidURL "valid" "") id="c-url"}}
</p>
<p>
<label for="c-github-uid">GitHub UID</label>
{{input name="github_uid" type="text" value=github_uid placeholder="2342"
class=(if isValidGithubUID "valid" "") id="c-github-uid"}}
</p>
<p>
<label for="c-github-username">GitHub username</label>
{{input name="github_username" type="text" value=github_username placeholder="zerocool"
class=(if isValidGithubUsername "valid" "") id="c-github-username"}}
</p>
<p>
<label for="c-gitea-username">Gitea username</label>
{{input name="gitea_username" type="text" value=gitea_username placeholder="zerocool"
class=(if isValidGiteaUsername "valid" "") id="c-gitea-username"}}
</p>
<p>
<label for="c-wiki-username">Wiki username</label>
{{input name="wiki_username" type="text" value=wiki_username placeholder="ZeroCool"
class=(if isValidWikiUsername "valid" "") id="c-wiki-username"}}
</p> </p>
<p class="actions"> <p class="actions">
{{input type="submit" disabled=inProgress <input type="submit" value="Save">
value=(if inProgress "Processing" "Save")}}
</p> </p>
</form> </form>
-64
View File
@@ -1,64 +0,0 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
import { and, notEmpty } from '@ember/object/computed';
export default Component.extend({
attributes: null,
contributors: Object.freeze([]),
isValidContributor: notEmpty('contributorId'),
isValidAmount: computed('amount', function() {
return parseInt(this.amount, 10) > 0;
}),
isValidDescription: notEmpty('description'),
isValidUrl: notEmpty('url'),
isValid: and('isValidContributor',
'isValidAmount',
'isValidDescription'),
init () {
this._super(...arguments);
// Default attributes used by reset
this.set('attributes', {
contributorId: null,
kind: 'community',
amount: null,
description: null,
url: null,
});
},
didInsertElement() {
this._super(...arguments);
this.reset();
},
reset: function() {
this.setProperties(this.attributes);
},
actions: {
submit() {
if (!this.isValid) {
alert('Invalid data. Please review and try again.');
return;
}
let attributes = Object.keys(this.attributes);
let proposal = this.getProperties(attributes);
let saved = this.save(proposal);
// The promise handles inProgress
this.set('inProgress', saved);
saved.then(() => {
this.reset();
window.scroll(0,0);
window.alert('Proposal added.');
});
}
}
});
-44
View File
@@ -1,44 +0,0 @@
<form {{action "submit" on="submit"}}>
<p>
<select required onchange={{action (mut contributorId) value="target.value"}}>
<option value="" selected disabled hidden>Contributor</option>
{{#each contributors as |contributor|}}
<option value={{contributor.id}} selected={{eq contributorId contributor.id}}>{{contributor.github_username}}</option>
{{/each}}
</select>
</p>
<p>
<select required onchange={{action (mut kind) value="target.value"}}>
<option value="community" selected={{eq kind "community"}}>Community</option>
<option value="design" selected={{eq kind "design"}}>Design</option>
<option value="dev" selected={{eq kind "dev"}}>Development</option>
<option value="docs" selected={{eq kind "docs"}}>Documentation</option>
<option value="ops" selected={{eq kind "ops"}}>IT Operations</option>
</select>
</p>
<p>
{{input type="text"
placeholder="100"
value=amount
class=(if isValidAmount "valid" "")}}
</p>
<p>
{{input type="text"
placeholder="Description"
value=description
class=(if isValidDescription "valid" "")}}
</p>
<p>
{{input type="text"
placeholder="URL (optional)"
value=url
class=(if isValidUrl "valid" "")}}
</p>
<p class="actions">
{{input type="submit"
disabled=(is-pending inProgress)
value=(if (is-pending inProgress) "Processing" "Save")}}
{{#link-to "index"}}Back{{/link-to}}
</p>
</form>
@@ -1,64 +0,0 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
let categoryColors = {
community: "#fb6868",
design: "#fbe468",
dev: "#e068fb",
docs: "#97fb68",
ops: "#8f68fb",
}
export default Component.extend({
contributions: null,
chartOptions: Object.freeze({
legend: {
display: false
}
}),
chartData: computed('contributions', function() {
let kredits = this.contributions
.filterBy('vetoed', false)
.map(c => {
return { kind: c.kind, amount: c.amount }
})
.reduce(function (kinds, c) {
if (c.kind in kinds) {
kinds[c.kind] = kinds[c.kind] + c.amount
} else {
kinds[c.kind] = c.amount;
}
return kinds;
}, {});
return {
datasets: [{
data: [
kredits['community'],
kredits['design'],
kredits['dev'],
kredits['ops'],
kredits['docs'],
],
borderColor: [
categoryColors.community,
categoryColors.design,
categoryColors.dev,
categoryColors.ops,
categoryColors.docs,
],
borderWidth: 1
}],
labels: [
'Community',
'Design',
'Development',
'Operations & Infrastructure',
'Documentation'
],
}
})
});
@@ -1,7 +0,0 @@
<div class="chart">
{{ember-chart type="doughnut"
data=chartData
options=chartOptions
width=200
height=200}}
</div>
@@ -1,20 +0,0 @@
import Component from '@ember/component';
export default Component.extend({
tagName: 'ul',
classNames: ['contribution-list'],
actions: {
veto (contributionId) {
if (this.contractInteractionEnabled) {
this.vetoContribution(contributionId);
} else {
window.alert('Only members can veto contributions. Please ask someone to set you up.');
}
}
}
});
@@ -1,25 +0,0 @@
{{#each contributions as |contribution|}}
<li data-contribution-id={{contribution.id}} class="{{contribution-status contribution}} {{if contribution.vetoed "vetoed"}}">
<p class="meta">
<span class="recipient">{{user-avatar contributor=contribution.contributor}}</span>
<span class="category {{contribution.kind}}">({{contribution.kind}})</span>
<span class="title">
{{#if contribution.url}}
<a href={{contribution.url}} target="_blank" rel="noopener">{{contribution.description}}</a>
{{else}}
{{contribution.description}}
{{/if}}
</span>
</p>
<p class="kredits-amount">
<span class="amount">{{contribution.amount}}</span><span class="symbol">₭S</span>
</p>
{{#unless contribution.vetoed}}
{{#unless (is-confirmed-contribution contribution)}}
<p class="voting">
<button {{action "veto" contribution.id}} class="small danger">veto</button>
</p>
{{/unless}}
{{/unless}}
</li>
{{/each}}
+3 -17
View File
@@ -1,22 +1,8 @@
import Component from '@ember/component'; import Ember from 'ember';
export default Component.extend({ export default Ember.Component.extend({
tagName: 'table', tagName: 'table',
classNames: 'contributor-list', classNames: 'contributor-list'
selectedContributor: null,
actions: {
toggleContributorInfo(contributor) {
if (contributor.showMetadata) {
contributor.set('showMetadata', false);
} else {
this.contributorList.setEach('showMetadata', false);
contributor.set('showMetadata', true);
}
}
}
}); });
+5 -30
View File
@@ -1,39 +1,14 @@
<tbody> <tbody>
{{#each contributorList as |c|}} {{#each contributors as |contributor|}}
<tr role="button" class={{if (is-current-user c.contributor) "current-user"}} {{action "toggleContributorInfo" c}}> <tr>
<td class="person"> <td class="person">
{{user-avatar contributor=c.contributor}} {{c.contributor.name}} <img class="avatar" src={{contributor.avatarURL}}>
{{contributor.github_username}}
</td> </td>
<td class="kredits"> <td class="kredits">
<span class="amount"> <span class="amount">{{contributor.kredits}}</span>
{{#if showUnconfirmedKredits}}
{{c.amountTotal}}
{{else}}
{{c.amountConfirmed}}
{{/if}}
</span>
<span class="symbol">₭S</span> <span class="symbol">₭S</span>
</td> </td>
</tr> </tr>
<tr class="metadata {{if (is-current-user c.contributor) "current-user"}} {{if c.showMetadata "visible"}}">
<td colspan="2">
<ul>
<li>
<a href="https://rinkeby.etherscan.io/address/{{c.contributor.account}}" target="_blank" rel="noopener">Inspect Ethereum transactions</a>
</li>
{{#if c.contributor.ipfsHash}}
<li>
<a href="https://ipfs.io/ipfs/{{c.contributor.ipfsHash}}" target="_blank" rel="noopener">Inspect IPFS profile</a>
</li>
{{/if}}
<li>
{{link-to "Edit profile" "contributors.edit" c.contributor.id}}
</li>
</ul>
{{#if c.showMetadata}}
<pre>{{c.contributor.ipfsData}}</pre>
{{/if}}
</td>
</tr>
{{/each}} {{/each}}
</tbody> </tbody>
+2 -2
View File
@@ -1,6 +1,6 @@
import Component from '@ember/component'; import Ember from 'ember';
export default Component.extend({ export default Ember.Component.extend({
classNames: ['loading-spinner'] classNames: ['loading-spinner']
+2 -2
View File
@@ -2,7 +2,7 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1" x="0px" y="0px" viewBox="0 0 132 100" version="1.1" x="0px" y="0px" viewBox="0 0 132 100"
enable-background="new 0 0 100 100" xml:space="preserve"> enable-background="new 0 0 100 100" xml:space="preserve">
<path id="path-comet" <path id="path-comet"
d="M79.062,24.173L79.062,24.173l-0.021-0.011c-0.068-0.03-0.137-0.062-0.204-0.093L42.392,7.337 d="M79.062,24.173L79.062,24.173l-0.021-0.011c-0.068-0.03-0.137-0.062-0.204-0.093L42.392,7.337
c0,0,3.065,14.104,4.458,18.019l0,0c0,0-41.754-12.481-46.85-13.67c1.67,6.52,30.607,62.492,30.607,62.492 c0,0,3.065,14.104,4.458,18.019l0,0c0,0-41.754-12.481-46.85-13.67c1.67,6.52,30.607,62.492,30.607,62.492
c5.848,11.873,19.394,18.485,33.522,18.485c19.811,0,35.87-16.059,35.87-35.869C100,42.313,91.418,29.837,79.062,24.173z"> c5.848,11.873,19.394,18.485,33.522,18.485c19.811,0,35.87-16.059,35.87-35.869C100,42.313,91.418,29.837,79.062,24.173z">
@@ -10,5 +10,5 @@
</svg> </svg>
</p> </p>
<p> <p>
Loading data... Loading data from Ethereum...
</p> </p>
+3 -7
View File
@@ -1,6 +1,6 @@
import Component from '@ember/component'; import Ember from 'ember';
export default Component.extend({ export default Ember.Component.extend({
tagName: 'ul', tagName: 'ul',
classNames: ['proposal-list'], classNames: ['proposal-list'],
@@ -8,11 +8,7 @@ export default Component.extend({
actions: { actions: {
confirm(proposalId) { confirm(proposalId) {
if (this.contractInteractionEnabled) { this.sendAction('confirmAction', proposalId);
this.confirmProposal(proposalId);
} else {
window.alert('Only members can vote on proposals. Please ask someone to set you up.');
}
} }
} }
+8 -17
View File
@@ -1,20 +1,11 @@
{{#each proposals as |proposal|}} {{#each proposals as |proposal|}}
<li data-proposal-id={{proposal.id}} class={{if proposal.isExecuted "confirmed" "unconfirmed"}}> <li>
<p class="meta"> <span class="id">#{{proposal.id}}</span>
<span class="category {{proposal.kind}}">♥ ({{proposal.kind}})</span> Issue{{#if proposal.executed}}d{{/if}}
<span class="recipient">{{proposal.contributor.name}}:</span> <span class="amount">{{proposal.amount}}</span><span class="symbol">₭S</span>
</p> to <span class="recipient" title="{{proposal.recipientAddress}}">{{proposal.recipientName}}</span>
<p class="kredits-amount"> <span class="votes">({{proposal.votesCount}}/{{proposal.votesNeeded}} votes)</span>
<span class="amount">{{proposal.amount}}</span><span class="symbol">₭S</span>
</p> {{#unless proposal.executed}}<button {{action "confirm" proposal.id}}>+1</button>{{/unless}}
<p class="description">
<span class="description">{{proposal.description}}</span>
</p>
<p class="voting">
{{#unless proposal.isExecuted}}
<span class="votes">({{proposal.votesCount}}/{{proposal.votesNeeded}} votes)</span>
<button {{action "confirm" proposal.id}}>+1</button>
{{/unless}}
</p>
</li> </li>
{{/each}} {{/each}}
-11
View File
@@ -1,11 +0,0 @@
import Component from '@ember/component';
import { alias } from '@ember/object/computed';
export default Component.extend({
contributor: null,
tagName: 'img',
classNames: ['avatar'],
attributeBindings: ['src', 'title'],
src: alias('contributor.avatarURL'),
title: alias('contributor.name')
});
+2 -4
View File
@@ -1,6 +1,4 @@
import Controller from '@ember/controller'; import Ember from 'ember';
import { inject as service } from '@ember/service';
export default Controller.extend({ export default Ember.Controller.extend({
kredits: service(),
}); });
-30
View File
@@ -1,30 +0,0 @@
import Controller from '@ember/controller';
import { alias, filterBy, sort } from '@ember/object/computed';
import { inject as service } from '@ember/service';
export default Controller.extend({
kredits: service(),
contributors: alias('kredits.contributors'),
minedContributors: filterBy('contributors', 'id'),
contributorsSorting: Object.freeze(['name:asc']),
sortedContributors: sort('minedContributors', 'contributorsSorting'),
actions: {
save (contribution) {
const contributor = this.contributors.findBy('id', contribution.contributorId);
contribution.contributorIpfsHash = contributor.ipfsHash;
return this.kredits.addContribution(contribution)
.then(contribution => {
this.transitionToRoute('index');
return contribution;
});
}
}
});
-18
View File
@@ -1,18 +0,0 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default Controller.extend({
kredits: service(),
actions: {
save (attributes) {
return this.kredits
.updateContributor(this.model.id, attributes)
.then(() => this.transitionToRoute('index'))
}
}
});
-18
View File
@@ -1,18 +0,0 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default Controller.extend({
kredits: service(),
actions: {
save (contributor) {
return this.kredits
.addContributor(contributor)
.then(() => this.transitionToRoute('index'))
}
}
});
+43 -28
View File
@@ -1,43 +1,58 @@
import Controller from '@ember/controller'; import Ember from 'ember';
import { computed } from '@ember/object';
import { alias, not, sort } from '@ember/object/computed'; const {
import { inject as service } from '@ember/service'; computed,
inject: {
service
}
} = Ember;
export default Ember.Controller.extend({
export default Controller.extend({
kredits: service(), kredits: service(),
currentBlock: alias('kredits.currentBlock'),
contributions: alias('kredits.contributions'), contractInteractionEnabled: computed.alias('kredits.web3Provided'),
contributionsConfirmed: alias('kredits.contributionsConfirmed'),
contributionsUnconfirmed: alias('kredits.contributionsUnconfirmed'),
contributionsSorting: Object.freeze(['id:desc']), findContributorByAddress(address) {
contributionsUnconfirmedSorted: sort('contributionsUnconfirmed', 'contributionsSorting'), return this.get('model.contributors')
contributionsConfirmedSorted: sort('contributionsConfirmed', 'contributionsSorting'), .findBy('address', address);
},
kreditsByContributor: alias('kredits.kreditsByContributor'), proposalsOpen: function() {
let proposals = this.get('model.proposals')
.filterBy('executed', false)
.map(p => {
p.recipientName = this.findContributorByAddress(p.recipientAddress).github_username;
return p;
});
return proposals;
}.property('model.proposals.[]', 'model.contributors.[]'),
kreditsToplistSorting: computed('showUnconfirmedKredits', function(){ proposalsClosed: function() {
return this.showUnconfirmedKredits ? ['amountTotal:desc'] : ['amountConfirmed:desc']; let proposals = this.get('model.proposals')
}), .filterBy('executed', true)
kreditsToplist: sort('kreditsByContributor', 'kreditsToplistSorting'), .map(p => {
p.recipientName = this.findContributorByAddress(p.recipientAddress).github_username;
return p;
});
return proposals;
}.property('model.proposals.[]', 'model.contributors.[]'),
showUnconfirmedKredits: true, proposalsSorting: ['id:desc'],
hideUnconfirmedKredits: not('showUnconfirmedKredits'), proposalsClosedSorted: Ember.computed.sort('proposalsClosed', 'proposalsSorting'),
proposalsOpenSorted: Ember.computed.sort('proposalsOpen', 'proposalsSorting'),
contributorsSorting: ['kredits:desc'],
contributorsSorted: Ember.computed.sort('model.contributors', 'contributorsSorting'),
actions: { actions: {
vetoContribution (contributionId) { confirmProposal(proposalId) {
this.kredits.veto(contributionId).then(transaction => { this.get('kredits').vote(proposalId).then(transactionId => {
console.debug('[controllers:index] Veto submitted to Ethereum blockhain: '+transaction.hash); window.confirm('Vote submitted to Ethereum blockhain: '+transactionId);
});
},
confirmProposal (proposalId) {
this.kredits.vote(proposalId).then(transaction => {
console.debug('[controllers:index] Vote submitted to Ethereum blockhain: '+transaction.hash);
}); });
} }
} }
}); });
-24
View File
@@ -1,24 +0,0 @@
import Controller from '@ember/controller';
import { alias, filterBy } from '@ember/object/computed';
import { inject as service } from '@ember/service';
export default Controller.extend({
kredits: service(),
contributors: alias('kredits.contributors'),
minedContributors: filterBy('contributors', 'id'),
actions: {
save(proposal) {
// contributorIpfsHash is needed for the proposal ipfs data. I'm not happy to do this here but I think to load all the contributors in addProposal again is a bit too much. I hope we can refactor it later.
let contributor = this.contributors.findBy('id', proposal.contributorId);
proposal.contributorIpfsHash = contributor.get('ipfsHash');
return this.kredits.addProposal(proposal)
.then((proposal) => {
this.transitionToRoute('index');
return proposal;
});
}
}
});
-20
View File
@@ -1,20 +0,0 @@
import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';
import { alias } from '@ember/object/computed';
export default Helper.extend({
kredits: service(),
currentBlock: alias('kredits.currentBlock'),
compute([contribution]) {
if (contribution.vetoed) {
return 'vetoed';
} else if (contribution.confirmedAt > this.currentBlock) {
return 'unconfirmed';
} else {
return 'confirmed'
}
}
});
-15
View File
@@ -1,15 +0,0 @@
import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';
import { alias } from '@ember/object/computed';
export default Helper.extend({
kredits: service(),
currentBlock: alias('kredits.currentBlock'),
compute([contribution]) {
return !contribution.vetoed &&
(contribution.confirmedAt <= this.currentBlock);
}
});
-16
View File
@@ -1,16 +0,0 @@
import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';
import { alias } from '@ember/object/computed';
import { isPresent } from '@ember/utils';
export default Helper.extend({
kredits: service(),
currentUser: alias('kredits.currentUser'),
compute([contributor]) {
return isPresent(contributor) && isPresent(this.currentUser) &&
contributor.account === this.currentUser.account;
}
});
+3 -9
View File
@@ -3,22 +3,16 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Kosmos Kredits</title> <title>KreditsWeb</title>
<meta name="description" content=""> <meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
{{content-for "head"}} {{content-for "head"}}
<link integrity="" rel="stylesheet" href="{{rootURL}}assets/vendor.css"> <link rel="stylesheet" href="{{rootURL}}assets/vendor.css">
<link integrity="" rel="stylesheet" href="{{rootURL}}assets/kredits-web.css"> <link rel="stylesheet" href="{{rootURL}}assets/kredits-web.css">
{{content-for "head-footer"}} {{content-for "head-footer"}}
<script>
window.addEventListener('load', function() {
window.windowLoadComplete = true;
});
</script>
</head> </head>
<body> <body>
{{content-for "body"}} {{content-for "body"}}
-28
View File
@@ -1,28 +0,0 @@
import EmberObject from '@ember/object';
import bignumber from 'kredits-web/utils/cps/bignumber';
export default EmberObject.extend({
// Contract
id: null,
contributorId: null,
amount: null,
confirmedAt: bignumber('confirmedAtBlock', 'toNumber'),
vetoed: null,
ipfsHash: null,
creatorAccount: null,
// IPFS
kind: null,
description: null,
details: null,
url: null,
ipfsData: '',
init () {
this._super(...arguments);
this.set('details', {});
}
});
+8 -25
View File
@@ -1,31 +1,14 @@
import { computed } from '@ember/object'; import Ember from 'ember';
import EmberObject from '@ember/object';
import bignumber from 'kredits-web/utils/cps/bignumber';
import kreditsValue from 'kredits-web/utils/cps/kredits';
export default EmberObject.extend({ export default Ember.Object.extend({
// Contract
id: bignumber('idRaw', 'toString'),
account: null,
balance: kreditsValue('balanceRaw'),
totalKreditsEarned: bignumber('totalKreditsEarnedRaw', 'toNumber'),
contributionsCount: bignumber('contributionsCountRaw', 'toNumber'),
isCore: false,
ipfsHash: null,
// IPFS
kind: null,
name: null,
url: null,
github_username: null, github_username: null,
github_uid: null, github_uid: null,
wiki_username: null, kredits: null,
ipfsData: '', address: null,
avatarURL: function() {
return `https\:\/\/avatars2.githubusercontent.com/u/${this.get('github_uid')}?v=3&s=128`;
}.property('github_uid')
avatarURL: computed('github_uid', function() {
let github_uid = this.github_uid;
if (github_uid) {
return `https://avatars2.githubusercontent.com/u/${github_uid}?v=3&s=128`;
}
}),
}); });
+9 -26
View File
@@ -1,32 +1,15 @@
import EmberObject from '@ember/object'; import Ember from 'ember';
import { alias } from '@ember/object/computed';
import bignumber from 'kredits-web/utils/cps/bignumber';
export default EmberObject.extend({ export default Ember.Object.extend({
// Contract id: null,
id: bignumber('idRaw', 'toString'), creator: null,
creatorAccount: null, recipient: null,
contributorId: bignumber('contributorIdRaw', 'toString'), votesCount: null,
amount: bignumber('amountRaw', 'toNumber'), votesNeeded: null,
votesCount: bignumber('votesCountRaw', 'toNumber'), amount: null,
votesNeeded: bignumber('votesNeededRaw', 'toNumber'),
executed: null, executed: null,
ipfsHash: null,
// Shortcuts
isExecuted: alias('executed'),
// IPFS
kind: null,
description: null,
details: null,
url: null, url: null,
ipfsData: '', ipfsHash: null
init () {
this._super(...arguments);
this.set('details', {});
}
}); });
+3 -12
View File
@@ -1,22 +1,13 @@
import EmberRouter from '@ember/routing/router'; import Ember from 'ember';
import config from './config/environment'; import config from './config/environment';
const Router = EmberRouter.extend({ const Router = Ember.Router.extend({
location: config.locationType, location: config.locationType,
rootURL: config.rootURL rootURL: config.rootURL
}); });
Router.map(function() { Router.map(function() {
this.route('proposals', function() { this.route('spinner');
this.route('new');
});
this.route('contributions', function() {
this.route('new');
});
this.route('contributors', function() {
this.route('new');
this.route('edit', { path: ':id/edit' });
});
}); });
export default Router; export default Router;
+2 -29
View File
@@ -1,31 +1,4 @@
import { inject as service } from '@ember/service'; import Ember from 'ember';
import Route from '@ember/routing/route';
export default Route.extend({ export default Ember.Route.extend({
kredits: service(),
beforeModel(transition) {
const kredits = this.kredits;
return kredits.setup().then(() => {
kredits.get('kredits').preflightChecks().catch((error) => {
console.error('Kredits preflight check failed!');
console.error(error);
});
if (kredits.get('accountNeedsUnlock')) {
if (confirm('It looks like you have an Ethereum wallet available. Please unlock your account.')) {
transition.retry();
}
}
}).catch((error) => {
console.log('Error initializing Kredits', error);
});
},
afterModel() {
return this.kredits.loadInitialData()
.then(() => {
this.kredits.addContractEventHandlers();
});
}
}); });
-29
View File
@@ -1,29 +0,0 @@
import { inject as service } from '@ember/service';
import Route from '@ember/routing/route';
import { alias } from '@ember/object/computed';
export default Route.extend({
kredits: service(),
contributors: alias('kredits.contributors'),
model(params) {
return this.kredits.contributors.findBy('id', params.id);
},
setupController (controller, model) {
this._super(controller, model);
controller.set('attributes', {
account: model.account,
name: model.name,
kind: model.kind,
url: model.url,
github_username: model.github_username,
github_uid: model.github_uid,
gitea_username: model.gitea_username,
wiki_username: model.wiki_username
});
}
});
+18
View File
@@ -0,0 +1,18 @@
import Ember from 'ember';
export default Ember.Route.extend({
kredits: Ember.inject.service(),
model() {
let kredits = this.get('kredits');
return Ember.RSVP.hash({
contributors: kredits.getContributors(),
totalSupply: kredits.getValueFromContract('totalSupply'),
contributorsCount: kredits.getValueFromContract('contributorsCount'),
proposals: kredits.getProposals()
});
}
});
+4
View File
@@ -0,0 +1,4 @@
import Ember from 'ember';
export default Ember.Route.extend({
});
+113 -375
View File
@@ -1,400 +1,138 @@
import ethers from 'npm:ethers'; import Ember from 'ember';
import Kredits from 'npm:kredits-contracts'; import Web3 from 'npm:web3';
import RSVP from 'rsvp';
import Service from '@ember/service';
import EmberObject from '@ember/object';
import { computed } from '@ember/object';
import { alias, notEmpty } from '@ember/object/computed';
import { isEmpty } from '@ember/utils';
import groupBy from 'kredits-web/utils/group-by';
import formatKredits from 'kredits-web/utils/format-kredits';
import config from 'kredits-web/config/environment'; import config from 'kredits-web/config/environment';
import Contributor from 'kredits-web/models/contributor' import Contributor from 'kredits-web/models/contributor';
import Proposal from 'kredits-web/models/proposal' import Proposal from 'kredits-web/models/proposal';
import Contribution from 'kredits-web/models/contribution' import kreditsContracts from 'npm:kredits-contracts';
export default Service.extend({ export default Ember.Service.extend({
currentBlock: null, web3Instance: null,
currentUserAccounts: null, // default to not having an account. this is the wen web3 is loaded. web3Provided: false, // Web3 provided (using Mist Browser, Metamask et al.)
currentUser: null,
contributors: null,
contributions: null,
proposals: null,
currentUserIsContributor: notEmpty('currentUser'), web3: function() {
currentUserIsCore: alias('currentUser.isCore'), if (this.get('web3Instance')) {
hasAccounts: notEmpty('currentUserAccounts'), return this.get('web3Instance');
}
accountNeedsUnlock: computed('currentUserAccounts', function() { let web3Instance;
return this.currentUserAccounts && isEmpty(this.currentUserAccounts);
}),
contributionsUnconfirmed: computed('contributions.[]', 'currentBlock', function() { if (typeof window.web3 !== 'undefined') {
return this.contributions.filter(contribution => { Ember.Logger.debug('[kredits] Using user-provided instance, e.g. from Mist browser or Metamask');
return contribution.confirmedAt > this.currentBlock; web3Instance = window.web3;
this.set('web3Provided', true);
} else {
Ember.Logger.debug('[kredits] Creating new instance from npm module class');
let provider = new Web3.providers.HttpProvider(config.web3ProviderUrl);
web3Instance = new Web3(provider);
}
this.set('web3Instance', web3Instance);
window.web3 = web3Instance;
return web3Instance;
}.property('web3Instance'),
kreditsContract: function() {
if (this.get('kreditsContractInstance')) {
return this.get('kreditsContractInstance');
}
let contract = kreditsContracts(this.get('web3'))['Kredits'];
window.Kredits = contract;
this.set('kreditsContractInstance', contract);
return contract;
}.property('web3'),
getValueFromContract(contractMethod, ...args) {
return new Ember.RSVP.Promise((resolve, reject) => {
this.get('kreditsContract')[contractMethod](...args, (err, data) => {
if (err) { reject(err); }
resolve(data);
});
}); });
}),
contributionsConfirmed: computed('contributions.[]', 'currentBlock', function() {
return this.contributions
.filterBy('vetoed', false)
.filter(contribution => {
return contribution.confirmedAt <= this.currentBlock;
});
}),
kreditsByContributor: computed('contributionsUnconfirmed.@each.vetoed', 'contributors.[]', function() {
const contributionsUnconfirmed = this.contributionsUnconfirmed.filterBy('vetoed', false);
const contributionsGrouped = groupBy(contributionsUnconfirmed, 'contributorId');
const contributorsWithUnconfirmed = contributionsGrouped.map(c => c.value.toString());
const contributorsWithOnlyConfirmed = this.contributors.reject(c => contributorsWithUnconfirmed.includes(c.id))
const kreditsByContributor = contributionsGrouped.map(c => {
const amountUnconfirmed = c.items.mapBy('amount').reduce((a, b) => a + b);
const contributor = this.contributors.findBy('id', c.value.toString());
return EmberObject.create({
contributor: contributor,
amountUnconfirmed: amountUnconfirmed,
amountConfirmed: contributor.totalKreditsEarned,
amountTotal: contributor.totalKreditsEarned + amountUnconfirmed
})
});
contributorsWithOnlyConfirmed.forEach(c => {
kreditsByContributor.push(EmberObject.create({
contributor: c,
amountUnconfirmed: 0,
amountConfirmed: c.totalKreditsEarned,
amountTotal: c.totalKreditsEarned
}));
})
return kreditsByContributor;
}),
init () {
this._super(...arguments);
this.set('contributors', []);
this.set('proposals', []);
this.set('contributions', []);
}, },
// This is called in the application route's beforeModel(). So it is getContributorData(i) {
// initialized before everything else, and we can rely on the ethProvider and let promise = new Ember.RSVP.Promise((resolve, reject) => {
// the potential currentUserAccounts to be available this.getValueFromContract('contributorAddresses', i).then(address => {
getEthProvider () { this.getValueFromContract('contributors', address).then(person => {
let ethProvider; this.getValueFromContract('balanceOf', address).then(balance => {
let contributor = Contributor.create({
return new RSVP.Promise(async (resolve) => { address: address,
function instantiateWithoutAccount () { github_username: person[1],
console.debug('[kredits] Creating new instance from npm module class'); github_uid: person[0],
console.debug(`[kredits] providerURL: ${config.web3ProviderUrl}`); ipfsHash: person[3],
ethProvider = new ethers.providers.JsonRpcProvider(config.web3ProviderUrl); kredits: balance.toNumber()
resolve({ });
ethProvider: ethProvider, Ember.Logger.debug('[kredits] contributor', contributor);
ethSigner: null resolve(contributor);
});
}
async function instantiateWithAccount (web3Provider, context) {
console.debug('[kredits] Using user-provided instance, e.g. from Mist browser or Metamask');
ethProvider = new ethers.providers.Web3Provider(web3Provider);
// const network = await ethProvider.getNetwork();
ethProvider.listAccounts().then(accounts => {
context.set('currentUserAccounts', accounts);
const ethSigner = accounts.length === 0 ? null : ethProvider.getSigner();
resolve({
ethProvider,
ethSigner
}); });
}); });
}).catch(err => reject(err));
});
return promise;
},
getContributors() {
return this.getValueFromContract('contributorsCount').then(contributorsCount => {
let contributors = [];
for(var i = 0; i < contributorsCount.toNumber(); i++) {
contributors.push(this.getContributorData(i));
} }
if (window.ethereum) { return Ember.RSVP.all(contributors);
try {
// Request account access if needed
await window.ethereum.enable();
// Acccounts now exposed
instantiateWithAccount(window.ethereum, this);
} catch (error) {
instantiateWithoutAccount();
}
}
// Legacy dapp browsers...
else if (window.web3) {
instantiateWithAccount(window.web3.currentProvider, this);
}
// Non-dapp browsers...
else {
instantiateWithoutAccount();
}
}); });
}, },
setup () { getProposalData(i) {
return this.getEthProvider().then((providerAndSigner) => { let promise = new Ember.RSVP.Promise((resolve, reject) => {
let kredits = new Kredits(providerAndSigner.ethProvider, providerAndSigner.ethSigner, { this.getValueFromContract('proposals', i).then(p => {
addresses: { Kernel: config.kreditsKernelAddress }, let proposal = Proposal.create({
apm: config.kreditsApmDomain, id : i,
ipfsConfig: config.ipfs creatorAddress : p[0],
}); recipientAddress : p[1],
return kredits votesCount : p[2].toNumber(),
.init() votesNeeded : p[3].toNumber(),
.then(async (kredits) => { amount : p[4].toNumber(),
this.set('kredits', kredits); executed : p[5],
this.set('currentBlock', await kredits.provider.getBlockNumber()); url : p[6],
ipfsHash : p[7]
if (this.currentUserAccounts && this.currentUserAccounts.length > 0) {
this.getCurrentUser.then((contributorData) => {
this.set('currentUser', contributorData);
});
}
return kredits;
}); });
Ember.Logger.debug('[kredits] proposal', proposal);
resolve(proposal);
}).catch(err => reject(err));
});
return promise;
},
getProposals() {
return this.getValueFromContract('proposalsCount').then(proposalsCount => {
let proposals = [];
for(var i = 0; i < proposalsCount.toNumber(); i++) {
proposals.push(this.getProposalData(i));
}
return Ember.RSVP.all(proposals);
}); });
}, },
totalSupply: computed(function() { vote(proposalId) {
return this.kredits.Token.functions.totalSupply().then(total => { Ember.Logger.debug('[kredits] vote for', proposalId);
return formatKredits(total); return new Ember.RSVP.Promise((resolve, reject) => {
}) this.get('kreditsContract').vote(proposalId, (err, data) => {
}), if (err) { reject(err); }
Ember.Logger.debug('[kredits] vote response', data);
totalKreditsEarned: computed(function() { resolve(data);
return this.kredits.Contribution.functions.totalKreditsEarned(true)
.then(total => total.toNumber());
}),
loadInitialData () {
return this.getContributors()
.then(contributors => this.contributors.pushObjects(contributors))
.then(() => this.getContributions())
.then(contributions => this.contributions.pushObjects(contributions))
},
addContributor (attributes) {
if (attributes.github_uid) {
const uidInt = parseInt(attributes.github_uid);
attributes.github_uid = uidInt;
}
console.debug('[kredits] add contributor', attributes);
return this.kredits.Contributor.add(attributes, { gasLimit: 350000 })
.then(data => {
console.debug('[kredits] add contributor response', data);
}); });
});
}, },
updateContributor (id, attributes) { logKreditsContract: function() {
if (attributes.github_uid) { Ember.Logger.debug('[kredits] kreditsContract', this.get('kreditsContract'));
const uidInt = parseInt(attributes.github_uid); }.on('init')
attributes.github_uid = uidInt;
}
console.debug('[kredits] update contributor', attributes);
return this.kredits.Contributor.updateProfile(id, attributes, { gasLimit: 350000 })
.then(data => {
console.debug('[kredits] updateProfile response', data);
});
},
getContributors () {
return this.kredits.Contributor.all()
.then((contributors) => {
return contributors.map((contributor) => {
return Contributor.create(contributor);
});
});
},
addContribution (attributes) {
console.debug('[kredits] add contribution', attributes);
return this.kredits.Contribution.addContribution(attributes, { gasLimit: 300000 })
.then(data => {
console.debug('[kredits] add contribution response', data);
attributes.contributor = this.contributors.findBy('id', attributes.contributorId);
const contribution = Contribution.create(attributes);
// TODO receive from wrapper
contribution.set('confirmedAtBlock', data.blockNumber + 40320);
this.contributions.pushObject(contribution);
return contribution;
});
},
addProposal (attributes) {
console.debug('[kredits] add proposal', attributes);
return this.kredits.Proposal.addProposal(attributes)
.then((data) => {
console.debug('[kredits] add proposal response', data);
attributes.contributor = this.contributors.findBy('id', attributes.contributorId);
return Proposal.create(attributes);
});
},
getProposals () {
return this.kredits.Proposal.all()
.then((proposals) => {
return proposals.map((proposal) => {
proposal.contributor = this.contributors.findBy('id', proposal.contributorId.toString());
return Proposal.create(proposal);
});
});
},
getContributions () {
return this.kredits.Contribution.all({page: {size: 200}})
.then(contributions => {
return contributions.map(contribution => {
contribution.contributor = this.contributors.findBy('id', contribution.contributorId.toString());
return Contribution.create(contribution);
});
});
},
vote (proposalId) {
console.debug('[kredits] vote for', proposalId);
return this.kredits.Proposal.functions.vote(proposalId)
.then(data => {
console.debug('[kredits] vote response', data);
return data;
});
},
veto (contributionId) {
console.debug('[kredits] veto against', contributionId);
return this.kredits.Contribution.functions.veto(contributionId, { gasLimit: 300000 })
.then(data => {
console.debug('[kredits] veto response', data);
return data;
});
},
getCurrentUser: computed('kredits.provider', function() {
if (isEmpty(this.currentUserAccounts)) {
return RSVP.resolve();
}
return this.kredits.Contributor
.functions.getContributorIdByAddress(this.get('currentUserAccounts.firstObject'))
.then((id) => {
// check if the user is a contributor or not
if (id === 0) {
return RSVP.resolve();
} else {
return this.kredits.Contributor.getById(id);
}
});
}),
findProposalById(proposalId) {
return this.proposals.findBy('id', proposalId.toString());
},
// Contract events
addContractEventHandlers () {
this.kredits.Contributor
.on('ContributorProfileUpdated', this.handleContributorChange.bind(this))
.on('ContributorAccountUpdated', this.handleContributorChange.bind(this))
.on('ContributorAdded', this.handleContributorChange.bind(this))
this.kredits.Contribution
.on('ContributionVetoed', this.handleContributionVetoed.bind(this))
this.kredits.Proposal
.on('ProposalCreated', this.handleProposalCreated.bind(this))
.on('ProposalVoted', this.handleProposalVoted.bind(this))
.on('ProposalExecuted', this.handleProposalExecuted.bind(this));
this.kredits.Token
.on('Transfer', this.handleTransfer.bind(this));
},
async handleContributorChange (contributorId, ...args) {
console.debug('[kredits] Contributor add/update event received for ID', contributorId);
console.debug('[kredits] Event data:', args);
const contributorData = await this.kredits.Contributor.getById(contributorId);
const newContributor = Contributor.create(contributorData);
const oldContributor = this.contributors.findBy('id', contributorId.toString());
if (oldContributor) {
console.debug('[kredits] old contributor', oldContributor);
this.contributors.removeObject(oldContributor);
}
console.debug('[kredits] new contributor', newContributor);
this.contributors.pushObject(newContributor);
},
handleContributionVetoed (contributionId) {
console.debug('[kredits] ContributionVetoed event received for ', contributionId);
const contribution = this.contributions.findBy('id', contributionId);
console.debug('[kredits] contribution', contribution);
if (contribution) {
contribution.set('vetoed', true);
}
},
handleProposalCreated (proposalId) {
let proposal = this.findProposalById(proposalId);
if (proposal) {
console.debug('[events] proposal exists, not adding from event');
return;
}
this.kredits.Proposal.getById(proposalId)
.then((proposal) => {
proposal.contributor = this.contributors.findBy('id', proposal.contributorId.toString());
this.proposals.pushObject(Proposal.create(proposal));
});
},
// TODO: We may want to reload that proposal to show the voter as voted
handleProposalVoted (proposalId, voterId, totalVotes) {
let proposal = this.findProposalById(proposalId);
if (proposal) {
proposal.set('votesCount', totalVotes);
}
},
handleProposalExecuted (proposalId, contributorId, amount) {
let proposal = this.findProposalById(proposalId);
if (proposal.get('isExecuted')) {
console.debug('[events] proposal already executed, not adding from event');
return;
}
proposal.set('executed', true);
this.contributors
.findBy('id', contributorId.toString())
.incrementProperty('balance', amount);
},
handleTransfer (from, to, value) {
value = value.toNumber();
this.contributors
.findBy('address', from)
.decrementProperty('balance', value);
this.contributors
.findBy('address', to)
.incrementProperty('balance', value);
},
}); });
-42
View File
@@ -1,42 +0,0 @@
button, input[type=submit], .button {
display: inline-block;
padding: 0.6rem 2rem;
background-color: rgba(22, 21, 40, 0.6);
border: 1px solid rgba(22, 21, 40, 1);
border-radius: 3px;
color: $primary-color;
font-weight: 500;
text-decoration: none;
text-transform: uppercase;
cursor: pointer;
letter-spacing: 0.1em;
&:hover {
background-color: rgba(22, 21, 40, 0.8);
}
&.small {
font-size: 0.8rem;
padding: 0.2rem 0.8rem;
}
&.danger {
color: $red;
background-color: rgba(40, 21, 21, 0.6);
border-color: rgba(40, 21, 21, 1);
&:hover {
background-color: rgba(40, 21, 21, 0.8);
}
}
&.green {
color: $green;
background-color: rgba(21, 40, 21, 0.6);
border-color: rgba(21, 40, 21, 1);
&:hover {
background-color: rgba(21, 40, 21, 0.8);
}
}
}
-15
View File
@@ -1,15 +0,0 @@
$blue: #68d7fb;
$purple: #8f68fb;
$pink: #e068fb;
$green: #97fb68;
$yellow: #fbe468;
$red: #fb6868;
$primary-color: $blue;
$body-text-color: #fff;
#topbar {
background-color: rgba(255, 0, 255, .2);
}
-107
View File
@@ -1,107 +0,0 @@
section#add-contributor,
section#add-contribution,
section#add-proposal {
form {
p {
margin-bottom: 1.5rem;
&.actions {
padding-top: 1.5rem;
text-align: center;
a {
color: $primary-color;
margin-left: 1rem;
}
}
}
label {
display: block;
margin-bottom: 0.5rem;
opacity: 0.7;
}
input[type=text], select {
width: 100%;
padding: 1rem;
border: none;
border-bottom: 1px solid rgba(255,255,255,0.2);
background-color: rgba(22, 21, 40, 0.3);
color: #fff;
font-size: 1.2rem;
transition: border-color 0.1s linear;
&:focus, &.valid {
background-color: rgba(22, 21, 40, 0.6);
}
&:focus {
border-color: $blue;
}
&::placeholder {
color: rgba(238, 238, 238, 0.5);
}
}
select {
-moz-appearance: none;
-webkit-appearance: none;
appearance: none;
border-radius: 0;
background-color: rgba(22, 21, 40, 0.6);
background-image:
linear-gradient(45deg, transparent 50%, gray 50%),
linear-gradient(135deg, gray 50%, transparent 50%);
background-position:
calc(100% - 1.5rem) calc(1rem + 0.5rem),
calc(100% - 1rem) calc(1rem + 0.5rem);
background-size:
0.5rem 0.5rem,
0.5rem 0.5rem;
background-repeat: no-repeat;
&:invalid {
color: rgba(238, 238, 238, 0.5);
}
}
input[type=submit] {
padding: 0.6rem 2rem;
&:disabled {
background-color: transparent;
}
}
input[type=checkbox] {
display: none;
}
label.checkbox {
line-height: 3.2rem;
font-size: 1.2rem;
&::before {
display: inline-block;
margin-right: 0.8rem;
height: 3.2rem;
width: 3.2rem;
font-size: 2rem;
background-color: rgba(22, 21, 40, 0.3);
border-bottom: 1px solid rgba(255,255,255,0.2);
text-align: center;
vertical-align: middle;
content: '';
color: rgba(255,255,255,0.2);
}
}
input[type=checkbox]:checked + label.checkbox {
&::before {
background-color: rgba(22, 21, 40, 0.6);
color: #fff;
}
}
}
}
+18 -69
View File
@@ -1,82 +1,31 @@
main { section {
padding: 1rem 2rem; @include outer-container;
margin-bottom: 8rem;
@include media-max(small) {
padding: 1rem;
}
&#index {
width: 100%;
display: grid;
grid-row-gap: 2rem;
grid-template-areas:
"stats"
"contributions";
}
&.center-column {
display: flex;
flex-direction: column;
align-items: center;
section {
width: 600px;
max-width: 100%;
header {
text-align: center;
}
}
}
}
@media (min-width: 550px) {
main {
&#index {
grid-column-gap: 4rem;
grid-row-gap: 2rem;
grid-template-columns: 2fr 4fr;
grid-template-areas:
"stats contributions";
}
}
}
main section {
margin-bottom: 5rem;
&:first-of-type { &:first-of-type {
margin-top: 2rem; margin-top: 6rem;
} }
@include media-max(small) { @include media($mobile) {
margin-bottom: 5rem; margin-bottom: 5rem;
&:first-of-type {
margin-top: 2rem;
}
} }
header { header {
margin-bottom: 3rem; @include span-columns(12);
padding-bottom: 3rem;
text-align: center;
// background-color: purple;
&.with-nav { @include media($mobile) {
display: grid; @include span-columns(10);
grid-template-columns: auto 5rem; @include shift(1);
grid-template-areas: padding-bottom: 2rem;
"title" "actions";
} }
h2 { div.content {
display: inline-block; @include span-columns(12);
// padding-left: 1.2rem;
}
nav {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
}
@include media-max(small) {
margin-bottom: 2rem;
} }
} }
} }
-33
View File
@@ -1,33 +0,0 @@
$breakpoints-max: (
small: 600px,
medium: 960px,
large: 1280px
);
$breakpoints-min: (
small: 601px,
medium: 961px,
large: 1281px
);
@mixin media-max($screen-size) {
@if map-has-key($breakpoints-max, $screen-size) {
@media (max-width: map-get($breakpoints-max, $screen-size)) {
@content;
}
} @else {
// Debugging
@warn "'#{$screen-size}' has not been declared as a breakpoint."
}
}
@mixin media-min($screen-size) {
@if map-has-key($breakpoints-min, $screen-size) {
@media (min-width: map-get($breakpoints-min, $screen-size)) {
@content;
}
} @else {
// Debugging
@warn "'#{$screen-size}' has not been declared as a breakpoint."
}
}
+34 -50
View File
@@ -2,7 +2,6 @@
margin: 0; margin: 0;
padding: 0; padding: 0;
box-sizing: border-box; box-sizing: border-box;
font-size: 14px;
} }
*:hover, *:active, *:focus { *:hover, *:active, *:focus {
@@ -11,19 +10,22 @@
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: transparent;
} }
@import "mediaqueries"; @import "bourbon";
@import "settings/neat";
@import "neat";
@import "settings/breakpoints";
@import "layout"; @import "layout";
@import "colors";
$font-family-sans: 'Open Sans', sans-serif; $font-family-sans: 'Open Sans', sans-serif;
body { body {
font-family: $font-family-sans; background-image: url('/img/bg.jpg');
font-weight: 300;
background-image: linear-gradient(to bottom, rgba(22, 21, 40, .4), rgba(0, 0, 0, .75)), url('/img/bg.jpg');
background-repeat: none; background-repeat: none;
background-attachment: fixed; background-attachment: fixed;
color: $body-text-color; font-family: $font-family-sans;
font-size: 16px;
font-weight: 300;
color: #fff;
} }
@media screen and (min-width: 900px) { @media screen and (min-width: 900px) {
@@ -40,66 +42,48 @@ h1, h2, h3, h4, h5, input, button {
section { section {
h2 { h2 {
font-size: 1.4rem; font-size: 2.8rem;
color: $primary-color; color: lightblue;
@include media($mobile) {
font-size: 2rem;
}
} }
&#people { &#contributors {
.content { .content {
p.stats { p.stats {
margin-bottom: 1rem; padding-top: 3rem;
font-size: 1rem; font-size: 1rem;
color: white; color: lightblue;
text-align: center; text-align: center;
span.number { span.number {
font-weight: 600; font-weight: 600;
} }
} @include media($mobile) {
} padding-top: 2rem;
} }
&#contributions-by-type {
.chart {
width: 50%;
margin-left: auto;
margin-right: auto;
@include media-max(small) {
width: 75%;
}
}
}
&#proposals-open, &#proposals-closed {
.actions {
padding-top: 3rem;
font-size: 1rem;
color: $primary-color;
text-align: center;
@include media-max(small) {
padding-top: 2rem;
}
a {
color: $primary-color;
} }
} }
} }
} }
@media (min-width: 550px) { button, input[type=submit] {
section { display: inline-block;
h2 { border: 1px solid rgba(22, 21, 40, 1);
font-size: 2rem; background-color: rgba(22, 21, 40, 0.6);
} color: lightblue;
border-radius: 3px;
font-weight: 500;
text-transform: uppercase;
cursor: pointer;
letter-spacing: 0.1em;
&:hover {
background-color: rgba(22, 21, 40, 0.8);
} }
} }
@import "buttons";
@import "forms";
@import "components/topbar";
@import "components/loading-spinner"; @import "components/loading-spinner";
@import "components/contributor-list"; @import "components/contributor-list";
@import "components/add-contributor";
@import "components/proposal-list"; @import "components/proposal-list";
@import "components/contribution-list";
@import "components/user-avatar";
@@ -0,0 +1,33 @@
section#add-contributor {
form {
p {
margin-bottom: 1rem;
&.actions {
padding-top: 1rem;
text-align: center;
}
}
input[type=text] {
width: 100%;
padding: 1rem;
border: none;
border-bottom: 1px solid rgba(255,255,255,0.2);
background-color: rgba(22, 21, 40, 0.3);
color: #fff;
font-size: 1.2rem;
&:focus, &.valid {
background-color: rgba(22, 21, 40, 0.6);
}
}
input[type=submit] {
padding: 0.6rem 2rem;
}
}
}
@@ -1,134 +0,0 @@
main section {
@include media-max(small) {
&#contributions-unconfirmed, &#contributions-confirmed {
margin-top: 0;
}
}
}
ul.contribution-list {
clear: both;
width: 100%;
list-style: none;
li {
display: grid;
grid-template-columns: auto 5rem 5rem;
grid-row-gap: 0.5rem;
padding: 0.8rem 1.2rem;
background-color: rgba(255,255,255,0.1);
font-size: 1.2rem;
border-bottom: 1px solid rgba(255,255,255,0.2);
&:first-of-type {
border-top: 1px solid rgba(255,255,255,0.2);
}
&.confirmed {
grid-template-columns: auto 5rem;
}
&.vetoed {
grid-template-columns: auto 5rem;
text-decoration: line-through;
opacity: 0.6;
}
p {
align-self: center;
margin: 0;
font-size: inherit;
line-height: 2rem;
&.kredits-amount, &.voting {
text-align: right;
}
}
span {
font-size: inherit;
&.title {
a {
font-size: inherit;
text-decoration: none;
color: $body-text-color;
}
a:hover, a:active {
color: $primary-color;
}
}
}
.description {
line-height: 1.4em;
font-size: 1rem;
}
.category {
color: $blue;
padding-right: 0.2rem;
&.community { color: $red; }
&.dev { color: $pink; }
&.design { color: $yellow; }
&.docs { color: $green; }
&.ops { color: $purple; }
}
.amount {
font-weight: 500;
}
.symbol {
font-size: 0.8rem;
padding-left: 0.2rem;
}
.recipient {
font-weight: 500;
}
.votes {
font-size: 1rem;
color: $primary-color;
margin-right: 0.5rem;
}
}
}
@media (min-width: 550px) {
ul.proposal-list {
li {
grid-template-columns: auto 10rem;
grid-row-gap: 0.5rem;
p {
&.kredits-amount, &.voting {
text-align: right;
}
}
&.unconfirmed {
p {
&.kredits-amount, &.voting {
text-align: right;
}
&.description {
grid-column-start: span 1;
}
&.voting {
grid-column-start: span 1;
}
}
}
.description {
font-size: inherit;
}
}
}
}
+22 -73
View File
@@ -1,89 +1,38 @@
table.contributor-list { table.contributor-list {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
margin-bottom: 1.5rem;
tr { tr {
border-bottom: 1px solid rgba(255,255,255,0.2); border-bottom: 1px solid rgba(255,255,255,0.2);
&:first-of-type { &:first-of-type {
border-top: 1px solid rgba(255,255,255,0.2); border-top: 1px solid rgba(255,255,255,0.2);
} }
}
td {
padding: 0 1.2rem;
line-height: 4.2rem;
background-color: rgba(255,255,255,0.1); background-color: rgba(255,255,255,0.1);
&.person {
&.current-user { text-align: left;
background-color: rgba(255,255,255,0.2); font-size: 1.4rem;
} img.avatar {
width: 2rem;
&.metadata { height: 2rem;
height: 0; vertical-align: middle;
visibility: hidden; margin-right: 0.2rem;
border-radius: 1rem;
&:not(.visible) {
border-bottom: none;
}
td {
padding: 0 1.2rem;
}
a {
color: $primary-color;
&:hover, &:active {
color: #fff;
}
}
ul {
list-style: none;
display: block;
overflow: hidden;
height: 0;
li {
display: inline;
&+li {
margin-left: 1rem;
}
}
}
&.visible {
height: auto;
visibility: visible;
ul {
height: auto;
}
} }
} }
&.kredits {
td { text-align: right;
padding: 0 1.2rem; .amount {
line-height: 3.6rem; font-size: 1.4rem;
&.person {
text-align: left;
font-size: 1.2rem;
img.avatar {
margin-right: 0.2rem;
}
} }
.symbol {
&.kredits { font-size: 1rem;
text-align: right; padding-left: 0.2rem;
.amount {
font-size: 1.2rem;
font-weight: 500;
}
.symbol {
font-size: 0.8rem;
padding-left: 0.2rem;
}
}
pre {
line-height: 1rem;
padding-bottom: 1rem;
} }
} }
} }
+3 -3
View File
@@ -11,9 +11,9 @@
margin-top: 12rem; margin-top: 12rem;
text-align: center; text-align: center;
font-size: 1.4rem; font-size: 1.4rem;
color: $primary-color; color: lightblue;
@include media-max(small) { @include media($mobile) {
margin-top: 6rem; margin-top: 6rem;
} }
@@ -23,7 +23,7 @@
margin-bottom: 2rem; margin-bottom: 2rem;
#path-comet { #path-comet {
fill: $primary-color; fill: lightblue;
opacity: 0.1; opacity: 0.1;
animation-name: pulse; animation-name: pulse;
+16 -83
View File
@@ -4,111 +4,44 @@ ul.proposal-list {
list-style: none; list-style: none;
li { li {
display: grid; // display: block;
grid-template-columns: auto 5rem; padding: 0 1.2rem;
grid-row-gap: 0.5rem; line-height: 4.2rem;
padding: 1rem 1.2rem;
background-color: rgba(255,255,255,0.1); background-color: rgba(255,255,255,0.1);
font-size: 1.2rem; font-size: 1.4rem;
border-bottom: 1px solid rgba(255,255,255,0.2); border-bottom: 1px solid rgba(255,255,255,0.2);
&:first-of-type { &:first-of-type {
border-top: 1px solid rgba(255,255,255,0.2); border-top: 1px solid rgba(255,255,255,0.2);
} }
p { .id {
align-self: center; color: lightblue;
margin: 0;
font-size: inherit;
line-height: 2rem;
&.kredits-amount, &.voting {
text-align: right;
}
&.description {
grid-column-start: span 2;
}
&.voting {
grid-column-start: span 2;
}
}
span {
font-size: inherit;
}
.description {
line-height: 1.4em;
font-size: 1rem;
}
.category {
color: $blue;
padding-right: 0.2rem; padding-right: 0.2rem;
&.community { color: $red; }
&.dev { color: $pink; }
&.design { color: $yellow; }
&.docs { color: $green; }
&.ops { color: $purple; }
} }
.amount { .amount {
font-weight: 500; font-weight: 500;
} }
.symbol { .symbol {
font-size: 1rem; font-size: 1rem;
font-weight: 500; font-weight: 500;
padding-left: 0.2rem; padding-left: 0.2rem;
} }
.recipient { .recipient {
font-weight: 500; font-weight: 500;
} }
.votes { .votes {
font-size: 1rem; font-size: 1rem;
color: $primary-color; color: lightblue;
margin-right: 0.5rem; padding-left: 1rem;
}
button {
float: right;
margin-top: 1.1rem;
height: 2rem;
line-height: 2rem;
padding: 0 0.6rem;
} }
} }
} }
@media (min-width: 550px) {
ul.proposal-list {
li {
grid-template-columns: auto 10rem;
grid-row-gap: 0.5rem;
p {
&.kredits-amount, &.voting {
text-align: right;
}
}
&.unconfirmed {
p {
&.kredits-amount, &.voting {
text-align: right;
}
&.description {
grid-column-start: span 1;
}
&.voting {
grid-column-start: span 1;
}
}
}
.description {
font-size: inherit;
}
}
}
}
-22
View File
@@ -1,22 +0,0 @@
#topbar {
padding: 0 1rem;
height: 3rem;
line-height: 3rem;
background-color: rgba(0,0,0,.3);
@include media-min(medium) {
padding: 0 2rem;
height: 4rem;
line-height: 4rem;
}
h1 {
display: inline-block;
text-transform: uppercase;
}
section#user-account {
display: inline-block;
float: right;
}
}
-7
View File
@@ -1,7 +0,0 @@
img.avatar {
width: 2rem;
height: 2rem;
vertical-align: middle;
margin-right: 0.2rem;
border-radius: 1rem;
}
+1
View File
@@ -0,0 +1 @@
$mobile: new-breakpoint(max-width 600px);
+5
View File
@@ -0,0 +1,5 @@
// $visual-grid: true;
// $visual-grid-color: red;
// $visual-grid-index: front;
// $visual-grid-opacity: 0.5;
$max-width: em(500, 12);
+3 -16
View File
@@ -1,16 +1,3 @@
<header id="topbar"> <main>
<h1>Kosmos Kredits</h1> {{outlet}}
</main>
<section id="user-account">
{{#if kredits.hasAccounts }}
{{#if kredits.currentUser}}
{{kredits.currentUser.name}}
{{#if kredits.currentUserIsCore}}(core){{/if}}
{{/if}}
{{else}}
Anonymous
{{/if}}
</section>
</header>
{{outlet}}
-13
View File
@@ -1,13 +0,0 @@
<main class="center-column">
<section id="add-contribution">
<header>
<h2>Submit a contribution</h2>
</header>
<div class="content">
{{add-contribution contributors=sortedContributors save=(action "save")}}
</div>
</section>
</main>
-13
View File
@@ -1,13 +0,0 @@
<main class="center-column">
<section id="add-contributor">
<header>
<h2>Update contributor profile</h2>
</header>
<div class="content">
{{add-contributor attributes=attributes save=(action "save")}}
</div>
</section>
</main>
-13
View File
@@ -1,13 +0,0 @@
<main class="center-column">
<section id="add-contributor">
<header>
<h2>Add contributor profile</h2>
</header>
<div class="content">
{{add-contributor save=(action "save")}}
</div>
</section>
</main>
+36 -59
View File
@@ -1,69 +1,46 @@
<main id="index"> <section id="contributors">
<header>
<h2>Kosmos Contributors</h2>
</header>
<div id="stats"> <div class="content">
<section id="people"> {{contributor-list contributors=contributorsSorted}}
<header class="with-nav">
<h2>Contributors</h2>
{{#if kredits.hasAccounts}}
<nav>
{{link-to "add" "contributors.new" title="Add contributor profile" class="button small green"}}
</nav>
{{/if}}
</header>
<div class="content">
{{contributor-list contributorList=kreditsToplist
showUnconfirmedKredits=showUnconfirmedKredits}}
<p class="stats"> <p class="stats">
<span class="number">{{await kredits.totalKreditsEarned}}</span> kredits confirmed and issued to <span class="number">{{model.totalSupply}}</span> kredits issued and distributed among
<span class="number">{{contributorsWithKredits.length}}</span> contributors <span class="number">{{model.contributorsCount}}</span> contributors.
</p> </p>
<p class="stats">
{{input type="checkbox" id="hide-unnconfirmed-kredits" checked=showUnconfirmedKredits}}
<label for="hide-unnconfirmed-kredits">Show unconfirmed kredits in toplist</label>
</p>
</div>
</section>
<section id="contributions-by-type">
<header>
<h2>Contributions by type</h2>
</header>
<div class="content">
{{chart-contributions-by-type contributions=contributions}}
</div>
</section>
</div> </div>
</section>
<div id="contributions"> {{#if contractInteractionEnabled}}
{{#if contributionsUnconfirmed}} {{#if proposalsOpen}}
<section id="contributions-unconfirmed"> <section id="proposals-open">
<header class="with-nav">
<h2>Latest Contributions</h2>
{{#if kredits.hasAccounts}}
<nav>
{{link-to "add" "contributions.new" title="Submit a contribution" class="button small green"}}
</nav>
{{/if}}
</header>
<div class="content">
{{!-- TODO: We need a better naming for kredits.hasAccounts --}}
{{contribution-list contributions=contributionsUnconfirmedSorted
vetoContribution=(action "vetoContribution")
contractInteractionEnabled=kredits.hasAccounts}}
</div>
</section>
{{/if}}
<section id="contributions-confirmed">
<header> <header>
<h2>Confirmed Contributions</h2> <h2>Open Proposals</h2>
</header> </header>
<div class="content"> <div class="content">
{{contribution-list contributions=contributionsConfirmedSorted {{proposal-list proposals=proposalsOpenSorted confirmAction="confirmProposal"}}
vetoContribution=(action "vetoContribution")}}
</div> </div>
</section> </section>
</div> {{/if}}
</main> <section id="proposals-closed">
<header>
<h2>Closed Proposals</h2>
</header>
<div class="content">
{{proposal-list proposals=proposalsClosedSorted confirmAction="confirmProposal"}}
</div>
</section>
<section id="add-contributor">
<header>
<h2>Add Contributor</h2>
</header>
<div class="content">
{{add-contributor kredits=kredits}}
</div>
</section>
{{/if}}
-10
View File
@@ -1,10 +0,0 @@
<section id="add-proposal">
<header>
<h2>Add Proposal</h2>
</header>
<div class="content">
{{add-proposal contributors=minedContributors save=(action "save")}}
</div>
</section>
+1
View File
@@ -0,0 +1 @@
{{loading-spinner}}
-20
View File
@@ -1,20 +0,0 @@
import { computed } from '@ember/object';
import ethers from 'npm:ethers';
export default function(dependentKey, converterMethod) {
return computed(dependentKey, {
get () {
let value = this.get(dependentKey);
if (value && ethers.utils.BigNumber.isBigNumber(value)) {
return value[converterMethod]();
} else {
return value;
}
},
set (key, value) {
const bnValue = ethers.utils.bigNumberify(value);
this.set(dependentKey, bnValue);
return bnValue[converterMethod]();
}
});
}
-17
View File
@@ -1,17 +0,0 @@
import { computed } from '@ember/object';
import ethers from 'npm:ethers';
import formatKredits from 'kredits-web/utils/format-kredits';
export default function(dependentKey, options = {}) {
return computed(dependentKey, {
get () {
const value = this.get(dependentKey);
return formatKredits(value, options);
},
set (key, value) {
const bnValue = ethers.utils.bigNumberify(value);
this.set(dependentKey, bnValue);
return formatKredits(bnValue, options);
}
});
}
-9
View File
@@ -1,9 +0,0 @@
import ethers from 'npm:ethers';
export default function(value, options = {}) {
let etherValue = ethers.utils.formatEther(value);
if (!options.decimals) {
etherValue = parseInt(etherValue).toString();
}
return etherValue;
}
-27
View File
@@ -1,27 +0,0 @@
//
// Code from https://github.com/HeroicEric/ember-group-by (MIT licensed)
//
import { A } from '@ember/array';
import { get } from '@ember/object';
import { isPresent } from '@ember/utils';
export default function groupBy (collection, property) {
let groups = A();
let items = collection;
if (items) {
items.forEach(function(item) {
let value = get(item, property);
let group = groups.findBy('value', value);
if (isPresent(group)) {
get(group, 'items').push(item);
} else {
group = { property: property, value: value, items: [item] };
groups.push(group);
}
});
}
return groups;
}
+9
View File
@@ -0,0 +1,9 @@
{
"name": "kredits-web",
"dependencies": {
"ember": "~2.10.0",
"ember-cli-shims": "0.1.3",
"bourbon": "^4.2.7",
"neat": "^1.8.0"
}
}
+3 -44
View File
@@ -1,14 +1,10 @@
/* jshint node: true */ /* jshint node: true */
'use strict';
module.exports = function(environment) { module.exports = function(environment) {
var ENV = {
let ENV = {
modulePrefix: 'kredits-web', modulePrefix: 'kredits-web',
environment, environment: environment,
rootURL: '/', rootURL: '/',
locationType: 'auto', locationType: 'auto',
EmberENV: { EmberENV: {
FEATURES: { FEATURES: {
// Here you can enable experimental features on an ember canary build // Here you can enable experimental features on an ember canary build
@@ -23,40 +19,16 @@ module.exports = function(environment) {
APP: { APP: {
// Here you can pass flags/options to your application instance // Here you can pass flags/options to your application instance
// when it is created // when it is created
},
browserify: {
tests: true,
transform: [
["babelify", {
presets: ["es2015"],
global: true
}]
]
},
web3ProviderUrl: 'https://rinkeby.infura.io/v3/d4f788b7a6584f7db2fc3c268d4d09e9',
ipfs: {
host: 'ipfs.kosmos.org',
port: '5444',
protocol: 'https'
} }
}; };
if (environment === 'development') { if (environment === 'development') {
ENV.web3ProviderUrl = "http://139.59.248.169:8545";
// ENV.APP.LOG_RESOLVER = true; // ENV.APP.LOG_RESOLVER = true;
// ENV.APP.LOG_ACTIVE_GENERATION = true; // ENV.APP.LOG_ACTIVE_GENERATION = true;
// ENV.APP.LOG_TRANSITIONS = true; // ENV.APP.LOG_TRANSITIONS = true;
// ENV.APP.LOG_TRANSITIONS_INTERNAL = true; // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
// ENV.APP.LOG_VIEW_LOOKUPS = true; // ENV.APP.LOG_VIEW_LOOKUPS = true;
ENV.web3ProviderUrl = 'https://rinkeby.infura.io/v3/d4f788b7a6584f7db2fc3c268d4d09e9';
ENV.ipfs = {
host: 'localhost',
port: '5001',
protocol: 'http'
};
} }
if (environment === 'test') { if (environment === 'test') {
@@ -68,22 +40,9 @@ module.exports = function(environment) {
ENV.APP.LOG_VIEW_LOOKUPS = false; ENV.APP.LOG_VIEW_LOOKUPS = false;
ENV.APP.rootElement = '#ember-testing'; ENV.APP.rootElement = '#ember-testing';
ENV.APP.autoboot = false;
} }
if (environment === 'production') { if (environment === 'production') {
// here you can enable a production-specific feature
ENV.kreditsApmDomain = process.env.KREDITS_APM_DOMAIN || 'open.aragonpm.eth';
}
if (process.env.WEB3_PROVIDER_URL) {
ENV.web3ProviderUrl = process.env.WEB3_PROVIDER_URL;
}
if (process.env.KREDITS_KERNEL_ADDRESS) {
ENV.kreditsKernelAddress = process.env.KREDITS_KERNEL_ADDRESS;
}
if (process.env.KREDITS_APM_DOMAIN) {
ENV.kreditsApmDomain = process.env.KREDITS_APM_DOMAIN;
} }
return ENV; return ENV;
-3
View File
@@ -1,3 +0,0 @@
{
"jquery-integration": true
}
-18
View File
@@ -1,18 +0,0 @@
'use strict';
const browsers = [
'last 1 Chrome versions',
'last 1 Firefox versions',
'last 1 Safari versions'
];
const isCI = !!process.env.CI;
const isProduction = process.env.EMBER_ENV === 'production';
if (isCI || isProduction) {
browsers.push('ie 11');
}
module.exports = {
browsers
};
+10 -12
View File
@@ -1,17 +1,15 @@
'use strict'; /*jshint node:true*/
/* global require, module */
const EmberApp = require('ember-cli/lib/broccoli/ember-app'); var EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) { module.exports = function(defaults) {
let app = new EmberApp(defaults, { var app = new EmberApp(defaults, {
// sassOptions: { // Add options here
// includePaths: [ sassOptions: {
// 'node_modules/bourbon/app/assets/stylesheets' includePaths: [
// ] 'bower_components/bourbon/app/assets/stylesheets',
// }, 'bower_components/neat/app/assets/stylesheets'
sourcemaps: { ]
enabled: true,
extensions: ['js']
} }
}); });
-4
View File
@@ -1,4 +0,0 @@
{
"node": true,
"browser": false
}
-20098
View File
File diff suppressed because it is too large Load Diff
+31 -54
View File
@@ -1,69 +1,46 @@
{ {
"name": "kredits-web", "name": "kredits-web",
"version": "1.1.0", "version": "0.0.0",
"private": true, "description": "Small description for kredits-web goes here",
"description": "Contribution dashboard of the Kosmos project",
"repository": "https://github.com/67P/kredits-web",
"license": "MIT", "license": "MIT",
"author": "Kosmos Contributors <mail@kosmos.org>", "author": "",
"directories": { "directories": {
"doc": "doc", "doc": "doc",
"test": "tests" "test": "tests"
}, },
"repository": "",
"scripts": { "scripts": {
"lint:hbs": "ember-template-lint .",
"lint:js": "eslint .",
"test": "ember test",
"start": "KREDITS_APM_DOMAIN=open.aragonpm.eth ember serve",
"start:local": "WEB3_PROVIDER_URL=http://localhost:7545 ember s",
"build": "ember build", "build": "ember build",
"build-prod": "rm -rf release/* && ember build -prod --output-path release", "start": "ember server",
"preversion": "npm test", "test": "ember test"
"version": "npm run build-prod && git add release/",
"deploy": "git push 5apps master"
}, },
"devDependencies": { "devDependencies": {
"@ember/jquery": "^0.5.2", "broccoli-asset-rev": "^2.4.5",
"@ember/optional-features": "^0.6.3", "ember-ajax": "^2.4.1",
"babel-preset-es2015": "^6.22.0",
"babelify": "^7.3.0",
"broccoli-asset-rev": "^2.7.0",
"ember-ajax": "^4.0.1",
"ember-awesome-macros": "0.41.0",
"ember-browserify": "^1.1.13", "ember-browserify": "^1.1.13",
"ember-cli": "~3.8.1", "ember-cli": "2.10.0",
"ember-cli-app-version": "^3.2.0", "ember-cli-app-version": "^2.0.0",
"ember-cli-babel": "^7.1.2", "ember-cli-babel": "^5.1.7",
"ember-cli-chart": "^3.4.0", "ember-cli-dependency-checker": "^1.3.0",
"ember-cli-dependency-checker": "^3.1.0", "ember-cli-htmlbars": "^1.0.10",
"ember-cli-eslint": "^4.2.3", "ember-cli-htmlbars-inline-precompile": "^0.3.3",
"ember-cli-htmlbars": "^3.0.0", "ember-cli-inject-live-reload": "^1.4.1",
"ember-cli-htmlbars-inline-precompile": "^1.0.3", "ember-cli-jshint": "^2.0.1",
"ember-cli-inject-live-reload": "^1.8.2", "ember-cli-qunit": "^3.0.1",
"ember-cli-sass": "^7.2.0", "ember-cli-release": "^0.2.9",
"ember-cli-sri": "^2.1.1", "ember-cli-sass": "6.1.1",
"ember-cli-template-lint": "^1.0.0-beta.1", "ember-cli-sri": "^2.1.0",
"ember-cli-uglify": "^2.1.0", "ember-cli-test-loader": "^1.1.0",
"ember-cli-update": "^0.21.2", "ember-cli-uglify": "^1.2.0",
"ember-export-application-global": "^2.0.0", "ember-export-application-global": "^1.0.5",
"ember-flatpickr": "^2.14.0", "ember-load-initializers": "^0.5.1",
"ember-load-initializers": "^1.1.0", "ember-resolver": "^2.0.3",
"ember-macro-helpers": "0.17.0", "loader.js": "^4.0.10",
"ember-maybe-import-regenerator": "^0.1.6", "web3": "^0.18.2",
"ember-promise-helpers": "1.0.6", "kredits-contracts": "67P/kredits-contracts"
"ember-qunit": "^3.4.1",
"ember-resolver": "^5.0.1",
"ember-source": "~3.8.0",
"ember-truth-helpers": "github:jmurphyau/ember-truth-helpers#31a14373a31f1f82c77537720549b47a95c28e5f",
"eslint-plugin-ember": "^5.2.0",
"ethers": "^4.0.27",
"kosmos-schemas": "^2.0.0",
"kredits-contracts": "^5.3.0",
"loader.js": "^4.7.0",
"qunit-dom": "^0.8.0",
"tv4": "^1.3.0"
}, },
"engines": { "engines": {
"node": "8.* || >= 10.*" "node": ">= 0.12.0"
} },
"private": true
} }
+15
View File
@@ -0,0 +1,15 @@
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<!-- Read this: www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html -->
<!-- Most restrictive policy: -->
<site-control permitted-cross-domain-policies="none"/>
<!-- Least restrictive policy: -->
<!--
<site-control permitted-cross-domain-policies="all"/>
<allow-access-from domain="*" to-ports="*" secure="false"/>
<allow-http-request-headers-from domain="*" headers="*" secure="false"/>
-->
</cross-domain-policy>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,190 +0,0 @@
"use strict"
define("kredits-web/app",["exports","kredits-web/resolver","ember-load-initializers","kredits-web/config/environment"],function(e,t,n,r){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var i=Ember.Application.extend({modulePrefix:r.default.modulePrefix,podModulePrefix:r.default.podModulePrefix,Resolver:t.default});(0,n.default)(i,r.default.modulePrefix)
var o=i
e.default=o}),define("kredits-web/components/add-contribution/component",["exports"],function(e){function t(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=[],r=!0,i=!1,o=void 0
try{for(var s,u=e[Symbol.iterator]();!(r=(s=u.next()).done)&&(n.push(s.value),!t||n.length!==t);r=!0);}catch(a){i=!0,o=a}finally{try{r||null==u.return||u.return()}finally{if(i)throw o}}return n}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var n=Ember.Component.extend({attributes:null,contributors:Object.freeze([]),isValidContributor:Ember.computed.notEmpty("contributorId"),isValidKind:Ember.computed.notEmpty("kind"),isValidAmount:Ember.computed("amount",function(){return parseInt(this.amount,10)>0}),isValidDescription:Ember.computed.notEmpty("description"),isValidUrl:Ember.computed.notEmpty("url"),isValid:Ember.computed.and("isValidContributor","isValidKind","isValidAmount","isValidDescription"),init:function(){this._super.apply(this,arguments),this.set("defaultDate",new Date),this.set("attributes",{contributorId:null,kind:null,date:[new Date],amount:null,description:null,url:null}),this.reset()},reset:function(){this.setProperties(this.attributes)},actions:{submit:function(){var e=this
if(this.isValid){var n=this.getProperties(Object.keys(this.attributes)),r=t(n.date[0].toISOString().split("T"),1)[0]
n.date=r,this.set("inProgress",!0),this.save(n).then(function(){e.reset()},function(e){console.warn(e),window.alert("Something went wrong. Check the browser console for details.")}).finally(function(){return e.set("inProgress",!1)})}else alert("Invalid data. Please review and try again.")}}})
e.default=n}),define("kredits-web/components/add-contribution/template",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.HTMLBars.template({id:"vo6G9r3I",block:'{"symbols":["contributor"],"statements":[[7,"form"],[9],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[7,"select"],[11,"required",""],[12,"onchange",[27,"action",[[22,0,[]],[27,"mut",[[23,["contributorId"]]],null]],[["value"],["target.value"]]]],[9],[0,"\\n "],[7,"option"],[11,"value",""],[11,"selected",""],[11,"disabled",""],[11,"hidden",""],[9],[0,"Contributor"],[10],[0,"\\n"],[4,"each",[[23,["contributors"]]],null,{"statements":[[0," "],[7,"option"],[12,"value",[22,1,["id"]]],[12,"selected",[27,"eq",[[23,["contributorId"]],[22,1,["id"]]],null]],[9],[1,[22,1,["github_username"]],false],[10],[0,"\\n"]],"parameters":[1]},null],[0," "],[10],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[7,"select"],[11,"required",""],[12,"onchange",[27,"action",[[22,0,[]],[27,"mut",[[23,["kind"]]],null]],[["value"],["target.value"]]]],[9],[0,"\\n "],[7,"option"],[11,"value",""],[11,"selected",""],[11,"disabled",""],[11,"hidden",""],[9],[0,"Kind"],[10],[0,"\\n "],[7,"option"],[11,"value","community"],[12,"selected",[27,"eq",[[23,["kind"]],"community"],null]],[9],[0,"Community"],[10],[0,"\\n "],[7,"option"],[11,"value","design"],[12,"selected",[27,"eq",[[23,["kind"]],"design"],null]],[9],[0,"Design"],[10],[0,"\\n "],[7,"option"],[11,"value","dev"],[12,"selected",[27,"eq",[[23,["kind"]],"dev"],null]],[9],[0,"Development"],[10],[0,"\\n "],[7,"option"],[11,"value","docs"],[12,"selected",[27,"eq",[[23,["kind"]],"docs"],null]],[9],[0,"Documentation"],[10],[0,"\\n "],[7,"option"],[11,"value","ops"],[12,"selected",[27,"eq",[[23,["kind"]],"ops"],null]],[9],[0,"IT Operations"],[10],[0,"\\n "],[7,"option"],[11,"value","special"],[12,"selected",[27,"eq",[[23,["kind"]],"ops"],null]],[9],[0,"Special"],[10],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[1,[27,"ember-flatpickr",null,[["allowInput","altFormat","altInput","altInputClass","date","dateFormat","defaultDate","maxDate","onChange"],[false,"F j, Y",true,"date-alt",[23,["date"]],"Y-m-d",[23,["defaultDate"]],[23,["defaultDate"]],[27,"action",[[22,0,[]],[27,"mut",[[23,["date"]]],null]],null]]]],false],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[1,[27,"input",null,[["type","placeholder","value","class"],["text","500",[23,["amount"]],[27,"if",[[23,["isValidAmount"]],"valid",""],null]]]],false],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[1,[27,"input",null,[["type","placeholder","value","class"],["text","Description",[23,["description"]],[27,"if",[[23,["isValidDescription"]],"valid",""],null]]]],false],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[1,[27,"input",null,[["type","placeholder","value","class"],["text","URL (optional)",[23,["url"]],[27,"if",[[23,["isValidUrl"]],"valid",""],null]]]],false],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[11,"class","actions"],[9],[0,"\\n "],[1,[27,"input",null,[["type","disabled","value"],["submit",[23,["inProgress"]],[27,"if",[[23,["inProgress"]],"Processing","Save"],null]]]],false],[0,"\\n "],[10],[0,"\\n"],[3,"action",[[22,0,[]],"submit"],[["on"],["submit"]]],[10],[0,"\\n\\n"]],"hasEval":false}',meta:{moduleName:"kredits-web/components/add-contribution/template.hbs"}})
e.default=t}),define("kredits-web/components/add-contributor/component",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.Component.extend({kredits:Ember.inject.service(),attributes:null,isValidAccount:Ember.computed.notEmpty("account"),isValidName:Ember.computed.notEmpty("name"),isValidURL:Ember.computed.notEmpty("url"),isValidGithubUID:Ember.computed.notEmpty("github_uid"),isValidGithubUsername:Ember.computed.notEmpty("github_username"),isValidGiteaUsername:Ember.computed.notEmpty("gitea_username"),isValidWikiUsername:Ember.computed.notEmpty("wiki_username"),isValid:Ember.computed.and("isValidAccount","isValidName","isValidGithubUID"),inProgress:!1,init:function(){this._super.apply(this,arguments),this.setDefaultAttributes(),this.reset()},setDefaultAttributes:function(){Ember.isPresent(this.attributes)||this.set("attributes",{account:null,name:null,kind:"person",url:null,github_username:null,github_uid:null,gitea_username:null,wiki_username:null})},reset:function(){this.setProperties(this.attributes)},actions:{submit:function(){var e=this
if(this.isValid){var t=Object.keys(this.attributes),n=this.getProperties(t)
this.set("inProgress",!0),this.save(n).then(function(){e.reset()}).catch(function(e){console.warn(e),window.alert("Something went wrong. Please check the browser console.")}).finally(function(){e.set("inProgress",!1)})}else alert("Invalid data. Please review and try again.")}}})
e.default=t}),define("kredits-web/components/add-contributor/template",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.HTMLBars.template({id:"ub+zr3DC",block:'{"symbols":[],"statements":[[7,"form"],[9],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[7,"label"],[11,"for","c-account"],[9],[0,"Ethereum account"],[10],[0,"\\n "],[1,[27,"input",null,[["name","id","type","value","placeholder","class"],["account","c-account","text",[23,["account"]],"0xF18E631Ea191aE4ebE70046Fcb01a436554421BA4",[27,"if",[[23,["isValidAccount"]],"valid",""],null]]]],false],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[7,"label"],[11,"for","c-kind"],[9],[0,"Kind"],[10],[0,"\\n "],[7,"select"],[11,"required",""],[12,"onchange",[27,"action",[[22,0,[]],[27,"mut",[[23,["kind"]]],null]],[["value"],["target.value"]]]],[11,"id","c-kind"],[9],[0,"\\n "],[7,"option"],[11,"value","person"],[12,"selected",[27,"eq",[[23,["kind"]],"person"],null]],[9],[0,"Person"],[10],[0,"\\n "],[7,"option"],[11,"value","organization"],[12,"selected",[27,"eq",[[23,["kind"]],"organization"],null]],[9],[0,"Organization"],[10],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[7,"label"],[11,"for","c-name"],[9],[0,"Name"],[10],[0,"\\n "],[1,[27,"input",null,[["name","type","value","placeholder","class","id"],["name","text",[23,["name"]],"Zero Cool",[27,"if",[[23,["isValidName"]],"valid",""],null],"c-name"]]],false],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[7,"label"],[11,"for","c-url"],[9],[0,"URL"],[10],[0,"\\n "],[1,[27,"input",null,[["name","type","value","placeholder","class","id"],["url","text",[23,["url"]],"http://zerocool.bit",[27,"if",[[23,["isValidURL"]],"valid",""],null],"c-url"]]],false],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[7,"label"],[11,"for","c-github-uid"],[9],[0,"GitHub UID"],[10],[0,"\\n "],[1,[27,"input",null,[["name","type","value","placeholder","class","id"],["github_uid","text",[23,["github_uid"]],"2342",[27,"if",[[23,["isValidGithubUID"]],"valid",""],null],"c-github-uid"]]],false],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[7,"label"],[11,"for","c-github-username"],[9],[0,"GitHub username"],[10],[0,"\\n "],[1,[27,"input",null,[["name","type","value","placeholder","class","id"],["github_username","text",[23,["github_username"]],"zerocool",[27,"if",[[23,["isValidGithubUsername"]],"valid",""],null],"c-github-username"]]],false],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[7,"label"],[11,"for","c-gitea-username"],[9],[0,"Gitea username"],[10],[0,"\\n "],[1,[27,"input",null,[["name","type","value","placeholder","class","id"],["gitea_username","text",[23,["gitea_username"]],"zerocool",[27,"if",[[23,["isValidGiteaUsername"]],"valid",""],null],"c-gitea-username"]]],false],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[7,"label"],[11,"for","c-wiki-username"],[9],[0,"Wiki username"],[10],[0,"\\n "],[1,[27,"input",null,[["name","type","value","placeholder","class","id"],["wiki_username","text",[23,["wiki_username"]],"ZeroCool",[27,"if",[[23,["isValidWikiUsername"]],"valid",""],null],"c-wiki-username"]]],false],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[11,"class","actions"],[9],[0,"\\n "],[1,[27,"input",null,[["type","disabled","value"],["submit",[23,["inProgress"]],[27,"if",[[23,["inProgress"]],"Processing","Save"],null]]]],false],[0,"\\n "],[10],[0,"\\n"],[3,"action",[[22,0,[]],"submit"],[["on"],["submit"]]],[10],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"kredits-web/components/add-contributor/template.hbs"}})
e.default=t}),define("kredits-web/components/add-proposal/component",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.Component.extend({attributes:null,contributors:Object.freeze([]),isValidContributor:Ember.computed.notEmpty("contributorId"),isValidAmount:Ember.computed("amount",function(){return parseInt(this.amount,10)>0}),isValidDescription:Ember.computed.notEmpty("description"),isValidUrl:Ember.computed.notEmpty("url"),isValid:Ember.computed.and("isValidContributor","isValidAmount","isValidDescription"),init:function(){this._super.apply(this,arguments),this.set("attributes",{contributorId:null,kind:"community",amount:null,description:null,url:null})},didInsertElement:function(){this._super.apply(this,arguments),this.reset()},reset:function(){this.setProperties(this.attributes)},actions:{submit:function(){var e=this
if(this.isValid){var t=Object.keys(this.attributes),n=this.getProperties(t),r=this.save(n)
this.set("inProgress",r),r.then(function(){e.reset(),window.scroll(0,0),window.alert("Proposal added.")})}else alert("Invalid data. Please review and try again.")}}})
e.default=t}),define("kredits-web/components/add-proposal/template",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.HTMLBars.template({id:"3DOgBCvD",block:'{"symbols":["contributor"],"statements":[[7,"form"],[9],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[7,"select"],[11,"required",""],[12,"onchange",[27,"action",[[22,0,[]],[27,"mut",[[23,["contributorId"]]],null]],[["value"],["target.value"]]]],[9],[0,"\\n "],[7,"option"],[11,"value",""],[11,"selected",""],[11,"disabled",""],[11,"hidden",""],[9],[0,"Contributor"],[10],[0,"\\n"],[4,"each",[[23,["contributors"]]],null,{"statements":[[0," "],[7,"option"],[12,"value",[22,1,["id"]]],[12,"selected",[27,"eq",[[23,["contributorId"]],[22,1,["id"]]],null]],[9],[1,[22,1,["github_username"]],false],[10],[0,"\\n"]],"parameters":[1]},null],[0," "],[10],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[7,"select"],[11,"required",""],[12,"onchange",[27,"action",[[22,0,[]],[27,"mut",[[23,["kind"]]],null]],[["value"],["target.value"]]]],[9],[0,"\\n "],[7,"option"],[11,"value","community"],[12,"selected",[27,"eq",[[23,["kind"]],"community"],null]],[9],[0,"Community"],[10],[0,"\\n "],[7,"option"],[11,"value","design"],[12,"selected",[27,"eq",[[23,["kind"]],"design"],null]],[9],[0,"Design"],[10],[0,"\\n "],[7,"option"],[11,"value","dev"],[12,"selected",[27,"eq",[[23,["kind"]],"dev"],null]],[9],[0,"Development"],[10],[0,"\\n "],[7,"option"],[11,"value","docs"],[12,"selected",[27,"eq",[[23,["kind"]],"docs"],null]],[9],[0,"Documentation"],[10],[0,"\\n "],[7,"option"],[11,"value","ops"],[12,"selected",[27,"eq",[[23,["kind"]],"ops"],null]],[9],[0,"IT Operations"],[10],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[1,[27,"input",null,[["type","placeholder","value","class"],["text","100",[23,["amount"]],[27,"if",[[23,["isValidAmount"]],"valid",""],null]]]],false],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[1,[27,"input",null,[["type","placeholder","value","class"],["text","Description",[23,["description"]],[27,"if",[[23,["isValidDescription"]],"valid",""],null]]]],false],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[9],[0,"\\n "],[1,[27,"input",null,[["type","placeholder","value","class"],["text","URL (optional)",[23,["url"]],[27,"if",[[23,["isValidUrl"]],"valid",""],null]]]],false],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[11,"class","actions"],[9],[0,"\\n "],[1,[27,"input",null,[["type","disabled","value"],["submit",[27,"is-pending",[[23,["inProgress"]]],null],[27,"if",[[27,"is-pending",[[23,["inProgress"]]],null],"Processing","Save"],null]]]],false],[0,"\\n "],[4,"link-to",["index"],null,{"statements":[[0,"Back"]],"parameters":[]},null],[0,"\\n "],[10],[0,"\\n"],[3,"action",[[22,0,[]],"submit"],[["on"],["submit"]]],[10],[0,"\\n\\n"]],"hasEval":false}',meta:{moduleName:"kredits-web/components/add-proposal/template.hbs"}})
e.default=t}),define("kredits-web/components/chart-contributions-by-type/component",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t="#fb6868",n="#fbe468",r="#e068fb",i="#97fb68",o="#8f68fb",s=Ember.Component.extend({contributions:null,chartOptions:Object.freeze({legend:{display:!1}}),chartData:Ember.computed("contributions",function(){var e=this.contributions.filterBy("vetoed",!1).map(function(e){return{kind:e.kind,amount:e.amount}}).reduce(function(e,t){return t.kind in e?e[t.kind]=e[t.kind]+t.amount:e[t.kind]=t.amount,e},{})
return{datasets:[{data:[e.community,e.design,e.dev,e.ops,e.docs],borderColor:[t,n,r,o,i],borderWidth:1}],labels:["Community","Design","Development","Operations & Infrastructure","Documentation"]}})})
e.default=s}),define("kredits-web/components/chart-contributions-by-type/template",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.HTMLBars.template({id:"knNRD8x3",block:'{"symbols":[],"statements":[[7,"div"],[11,"class","chart"],[9],[0,"\\n "],[1,[27,"ember-chart",null,[["type","data","options","width","height"],["doughnut",[23,["chartData"]],[23,["chartOptions"]],200,200]]],false],[0,"\\n"],[10]],"hasEval":false}',meta:{moduleName:"kredits-web/components/chart-contributions-by-type/template.hbs"}})
e.default=t}),define("kredits-web/components/contribution-list/component",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.Component.extend({tagName:"ul",classNames:["contribution-list"],actions:{veto:function(e){this.contractInteractionEnabled?this.vetoContribution(e):window.alert("Only members can veto contributions. Please ask someone to set you up.")}}})
e.default=t}),define("kredits-web/components/contribution-list/template",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.HTMLBars.template({id:"xYW3ZUYB",block:'{"symbols":["contribution"],"statements":[[4,"each",[[23,["contributions"]]],null,{"statements":[[0," "],[7,"li"],[12,"data-contribution-id",[22,1,["id"]]],[12,"class",[28,[[27,"contribution-status",[[22,1,[]]],null]," ",[27,"if",[[22,1,["vetoed"]],"vetoed"],null]]]],[9],[0,"\\n "],[7,"p"],[11,"class","meta"],[9],[0,"\\n "],[7,"span"],[11,"class","recipient"],[9],[1,[27,"user-avatar",null,[["contributor"],[[22,1,["contributor"]]]]],false],[10],[0,"\\n "],[7,"span"],[12,"class",[28,["category ",[22,1,["kind"]]]]],[9],[0,"("],[1,[22,1,["kind"]],false],[0,")"],[10],[0,"\\n "],[7,"span"],[11,"class","title"],[9],[0,"\\n"],[4,"if",[[22,1,["url"]]],null,{"statements":[[0," "],[7,"a"],[12,"href",[22,1,["url"]]],[11,"target","_blank"],[11,"rel","noopener"],[9],[1,[22,1,["description"]],false],[10],[0,"\\n"]],"parameters":[]},{"statements":[[0," "],[1,[22,1,["description"]],false],[0,"\\n"]],"parameters":[]}],[0," "],[10],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[11,"class","kredits-amount"],[9],[0,"\\n "],[7,"span"],[11,"class","amount"],[9],[1,[22,1,["amount"]],false],[10],[7,"span"],[11,"class","symbol"],[9],[0,"₭S"],[10],[0,"\\n "],[10],[0,"\\n"],[4,"unless",[[22,1,["vetoed"]]],null,{"statements":[[4,"unless",[[27,"is-confirmed-contribution",[[22,1,[]]],null]],null,{"statements":[[0," "],[7,"p"],[11,"class","voting"],[9],[0,"\\n "],[7,"button"],[11,"class","small danger"],[9],[0,"veto"],[3,"action",[[22,0,[]],"veto",[22,1,["id"]]]],[10],[0,"\\n "],[10],[0,"\\n"]],"parameters":[]},null]],"parameters":[]},null],[0," "],[10],[0,"\\n"]],"parameters":[1]},null]],"hasEval":false}',meta:{moduleName:"kredits-web/components/contribution-list/template.hbs"}})
e.default=t}),define("kredits-web/components/contributor-list/component",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.Component.extend({tagName:"table",classNames:"contributor-list",selectedContributor:null,actions:{toggleContributorInfo:function(e){e.showMetadata?e.set("showMetadata",!1):(this.contributorList.setEach("showMetadata",!1),e.set("showMetadata",!0))}}})
e.default=t}),define("kredits-web/components/contributor-list/template",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.HTMLBars.template({id:"1on37xaL",block:'{"symbols":["c"],"statements":[[7,"tbody"],[9],[0,"\\n"],[4,"each",[[23,["contributorList"]]],null,{"statements":[[0," "],[7,"tr"],[11,"role","button"],[12,"class",[27,"if",[[27,"is-current-user",[[22,1,["contributor"]]],null],"current-user"],null]],[9],[0,"\\n "],[7,"td"],[11,"class","person"],[9],[0,"\\n "],[1,[27,"user-avatar",null,[["contributor"],[[22,1,["contributor"]]]]],false],[0," "],[1,[22,1,["contributor","name"]],false],[0,"\\n "],[10],[0,"\\n "],[7,"td"],[11,"class","kredits"],[9],[0,"\\n "],[7,"span"],[11,"class","amount"],[9],[0,"\\n"],[4,"if",[[23,["showUnconfirmedKredits"]]],null,{"statements":[[0," "],[1,[22,1,["amountTotal"]],false],[0,"\\n"]],"parameters":[]},{"statements":[[0," "],[1,[22,1,["amountConfirmed"]],false],[0,"\\n"]],"parameters":[]}],[0," "],[10],[0,"\\n "],[7,"span"],[11,"class","symbol"],[9],[0,"₭S"],[10],[0,"\\n "],[10],[0,"\\n "],[3,"action",[[22,0,[]],"toggleContributorInfo",[22,1,[]]]],[10],[0,"\\n "],[7,"tr"],[12,"class",[28,["metadata ",[27,"if",[[27,"is-current-user",[[22,1,["contributor"]]],null],"current-user"],null]," ",[27,"if",[[22,1,["showMetadata"]],"visible"],null]]]],[9],[0,"\\n "],[7,"td"],[11,"colspan","2"],[9],[0,"\\n "],[7,"ul"],[9],[0,"\\n "],[7,"li"],[9],[0,"\\n "],[7,"a"],[12,"href",[28,["https://rinkeby.etherscan.io/address/",[22,1,["contributor","account"]]]]],[11,"target","_blank"],[11,"rel","noopener"],[9],[0,"Inspect Ethereum transactions"],[10],[0,"\\n "],[10],[0,"\\n"],[4,"if",[[22,1,["contributor","ipfsHash"]]],null,{"statements":[[0," "],[7,"li"],[9],[0,"\\n "],[7,"a"],[12,"href",[28,["https://ipfs.io/ipfs/",[22,1,["contributor","ipfsHash"]]]]],[11,"target","_blank"],[11,"rel","noopener"],[9],[0,"Inspect IPFS profile"],[10],[0,"\\n "],[10],[0,"\\n"]],"parameters":[]},null],[0," "],[7,"li"],[9],[0,"\\n "],[4,"link-to",["contributors.edit",[22,1,["contributor","id"]]],null,{"statements":[[0,"Edit profile"]],"parameters":[]},null],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n"],[4,"if",[[22,1,["showMetadata"]]],null,{"statements":[[0," "],[7,"pre"],[9],[1,[22,1,["contributor","ipfsData"]],false],[10],[0,""]],"parameters":[]},null],[0," "],[10],[0,"\\n "],[10],[0,"\\n"]],"parameters":[1]},null],[10],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"kredits-web/components/contributor-list/template.hbs"}})
e.default=t}),define("kredits-web/components/ember-chart",["exports","ember-cli-chart/components/ember-chart"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var n=t.default
e.default=n}),define("kredits-web/components/ember-flatpickr",["exports","ember-flatpickr/components/ember-flatpickr"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}})}),define("kredits-web/components/loading-spinner/component",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.Component.extend({classNames:["loading-spinner"]})
e.default=t}),define("kredits-web/components/loading-spinner/template",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.HTMLBars.template({id:"b6SWTOaj",block:'{"symbols":[],"statements":[[7,"p"],[9],[0,"\\n "],[7,"svg"],[11,"xmlns","http://www.w3.org/2000/svg","http://www.w3.org/2000/xmlns/"],[11,"xmlns:xlink","http://www.w3.org/1999/xlink","http://www.w3.org/2000/xmlns/"],[11,"version","1.1"],[11,"x","0px"],[11,"y","0px"],[11,"viewBox","0 0 132 100"],[11,"enable-background","new 0 0 100 100"],[11,"xml:space","preserve","http://www.w3.org/XML/1998/namespace"],[9],[0,"\\n "],[7,"path"],[11,"id","path-comet"],[11,"d","M79.062,24.173L79.062,24.173l-0.021-0.011c-0.068-0.03-0.137-0.062-0.204-0.093L42.392,7.337\\n c0,0,3.065,14.104,4.458,18.019l0,0c0,0-41.754-12.481-46.85-13.67c1.67,6.52,30.607,62.492,30.607,62.492\\n c5.848,11.873,19.394,18.485,33.522,18.485c19.811,0,35.87-16.059,35.87-35.869C100,42.313,91.418,29.837,79.062,24.173z"],[9],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n"],[10],[0,"\\n"],[7,"p"],[9],[0,"\\n Loading data...\\n"],[10],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"kredits-web/components/loading-spinner/template.hbs"}})
e.default=t}),define("kredits-web/components/proposal-list/component",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.Component.extend({tagName:"ul",classNames:["proposal-list"],actions:{confirm:function(e){this.contractInteractionEnabled?this.confirmProposal(e):window.alert("Only members can vote on proposals. Please ask someone to set you up.")}}})
e.default=t}),define("kredits-web/components/proposal-list/template",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.HTMLBars.template({id:"pZHMSOZc",block:'{"symbols":["proposal"],"statements":[[4,"each",[[23,["proposals"]]],null,{"statements":[[0," "],[7,"li"],[12,"data-proposal-id",[22,1,["id"]]],[12,"class",[27,"if",[[22,1,["isExecuted"]],"confirmed","unconfirmed"],null]],[9],[0,"\\n "],[7,"p"],[11,"class","meta"],[9],[0,"\\n "],[7,"span"],[12,"class",[28,["category ",[22,1,["kind"]]]]],[9],[0,"♥ ("],[1,[22,1,["kind"]],false],[0,")"],[10],[0,"\\n "],[7,"span"],[11,"class","recipient"],[9],[1,[22,1,["contributor","name"]],false],[0,":"],[10],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[11,"class","kredits-amount"],[9],[0,"\\n "],[7,"span"],[11,"class","amount"],[9],[1,[22,1,["amount"]],false],[10],[7,"span"],[11,"class","symbol"],[9],[0,"₭S"],[10],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[11,"class","description"],[9],[0,"\\n "],[7,"span"],[11,"class","description"],[9],[1,[22,1,["description"]],false],[10],[0,"\\n "],[10],[0,"\\n "],[7,"p"],[11,"class","voting"],[9],[0,"\\n"],[4,"unless",[[22,1,["isExecuted"]]],null,{"statements":[[0," "],[7,"span"],[11,"class","votes"],[9],[0,"("],[1,[22,1,["votesCount"]],false],[0,"/"],[1,[22,1,["votesNeeded"]],false],[0," votes)"],[10],[0,"\\n "],[7,"button"],[9],[0,"+1"],[3,"action",[[22,0,[]],"confirm",[22,1,["id"]]]],[10],[0,"\\n"]],"parameters":[]},null],[0," "],[10],[0,"\\n "],[10],[0,"\\n"]],"parameters":[1]},null]],"hasEval":false}',meta:{moduleName:"kredits-web/components/proposal-list/template.hbs"}})
e.default=t}),define("kredits-web/components/user-avatar/component",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.Component.extend({contributor:null,tagName:"img",classNames:["avatar"],attributeBindings:["src","title"],src:Ember.computed.alias("contributor.avatarURL"),title:Ember.computed.alias("contributor.name")})
e.default=t}),define("kredits-web/components/user-avatar/template",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.HTMLBars.template({id:"rnnAjEgP",block:'{"symbols":[],"statements":[],"hasEval":false}',meta:{moduleName:"kredits-web/components/user-avatar/template.hbs"}})
e.default=t}),define("kredits-web/controllers/application",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.Controller.extend({kredits:Ember.inject.service()})
e.default=t}),define("kredits-web/controllers/contributions/new",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.Controller.extend({kredits:Ember.inject.service(),contributors:Ember.computed.alias("kredits.contributors"),minedContributors:Ember.computed.filterBy("contributors","id"),contributorsSorting:Object.freeze(["name:asc"]),sortedContributors:Ember.computed.sort("minedContributors","contributorsSorting"),actions:{save:function(e){var t=this,n=this.contributors.findBy("id",e.contributorId)
return e.contributorIpfsHash=n.ipfsHash,this.kredits.addContribution(e).then(function(e){return t.transitionToRoute("index"),e})}}})
e.default=t}),define("kredits-web/controllers/contributors/edit",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.Controller.extend({kredits:Ember.inject.service(),actions:{save:function(e){var t=this
return this.kredits.updateContributor(this.model.id,e).then(function(){return t.transitionToRoute("index")})}}})
e.default=t}),define("kredits-web/controllers/contributors/new",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.Controller.extend({kredits:Ember.inject.service(),actions:{save:function(e){var t=this
return this.kredits.addContributor(e).then(function(){return t.transitionToRoute("index")})}}})
e.default=t}),define("kredits-web/controllers/index",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.Controller.extend({kredits:Ember.inject.service(),currentBlock:Ember.computed.alias("kredits.currentBlock"),contributions:Ember.computed.alias("kredits.contributions"),contributionsConfirmed:Ember.computed.alias("kredits.contributionsConfirmed"),contributionsUnconfirmed:Ember.computed.alias("kredits.contributionsUnconfirmed"),contributionsSorting:Object.freeze(["id:desc"]),contributionsUnconfirmedSorted:Ember.computed.sort("contributionsUnconfirmed","contributionsSorting"),contributionsConfirmedSorted:Ember.computed.sort("contributionsConfirmed","contributionsSorting"),kreditsByContributor:Ember.computed.alias("kredits.kreditsByContributor"),kreditsToplistSorting:Ember.computed("showUnconfirmedKredits",function(){return this.showUnconfirmedKredits?["amountTotal:desc"]:["amountConfirmed:desc"]}),kreditsToplist:Ember.computed.sort("kreditsByContributor","kreditsToplistSorting"),showUnconfirmedKredits:!0,hideUnconfirmedKredits:Ember.computed.not("showUnconfirmedKredits"),actions:{vetoContribution:function(e){this.kredits.veto(e).then(function(e){console.debug("[controllers:index] Veto submitted to Ethereum blockhain: "+e.hash)})},confirmProposal:function(e){this.kredits.vote(e).then(function(e){console.debug("[controllers:index] Vote submitted to Ethereum blockhain: "+e.hash)})}}})
e.default=t}),define("kredits-web/controllers/proposals/new",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.Controller.extend({kredits:Ember.inject.service(),contributors:Ember.computed.alias("kredits.contributors"),minedContributors:Ember.computed.filterBy("contributors","id"),actions:{save:function(e){var t=this,n=this.contributors.findBy("id",e.contributorId)
return e.contributorIpfsHash=n.get("ipfsHash"),this.kredits.addProposal(e).then(function(e){return t.transitionToRoute("index"),e})}}})
e.default=t}),define("kredits-web/helpers/and",["exports","ember-truth-helpers/helpers/and"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}}),Object.defineProperty(e,"and",{enumerable:!0,get:function(){return t.and}})}),define("kredits-web/helpers/app-version",["exports","kredits-web/config/environment","ember-cli-app-version/utils/regexp"],function(e,t,n){function r(e){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=t.default.APP.version,o=r.versionOnly||r.hideSha,s=r.shaOnly||r.hideVersion,u=null
return o&&(r.showExtended&&(u=i.match(n.versionExtendedRegExp)),u||(u=i.match(n.versionRegExp))),s&&(u=i.match(n.shaRegExp)),u?u[0]:i}Object.defineProperty(e,"__esModule",{value:!0}),e.appVersion=r,e.default=void 0
var i=Ember.Helper.helper(r)
e.default=i}),define("kredits-web/helpers/await",["exports","ember-promise-helpers/helpers/await"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}})})
define("kredits-web/helpers/contribution-status",["exports"],function(e){function t(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=[],r=!0,i=!1,o=void 0
try{for(var s,u=e[Symbol.iterator]();!(r=(s=u.next()).done)&&(n.push(s.value),!t||n.length!==t);r=!0);}catch(a){i=!0,o=a}finally{try{r||null==u.return||u.return()}finally{if(i)throw o}}return n}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var n=Ember.Helper.extend({kredits:Ember.inject.service(),currentBlock:Ember.computed.alias("kredits.currentBlock"),compute:function(e){var n=t(e,1)[0]
return n.vetoed?"vetoed":n.confirmedAt>this.currentBlock?"unconfirmed":"confirmed"}})
e.default=n}),define("kredits-web/helpers/eq",["exports","ember-truth-helpers/helpers/equal"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}}),Object.defineProperty(e,"equal",{enumerable:!0,get:function(){return t.equal}})}),define("kredits-web/helpers/gt",["exports","ember-truth-helpers/helpers/gt"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}}),Object.defineProperty(e,"gt",{enumerable:!0,get:function(){return t.gt}})}),define("kredits-web/helpers/gte",["exports","ember-truth-helpers/helpers/gte"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}}),Object.defineProperty(e,"gte",{enumerable:!0,get:function(){return t.gte}})}),define("kredits-web/helpers/is-array",["exports","ember-truth-helpers/helpers/is-array"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}}),Object.defineProperty(e,"isArray",{enumerable:!0,get:function(){return t.isArray}})}),define("kredits-web/helpers/is-confirmed-contribution",["exports"],function(e){function t(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=[],r=!0,i=!1,o=void 0
try{for(var s,u=e[Symbol.iterator]();!(r=(s=u.next()).done)&&(n.push(s.value),!t||n.length!==t);r=!0);}catch(a){i=!0,o=a}finally{try{r||null==u.return||u.return()}finally{if(i)throw o}}return n}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var n=Ember.Helper.extend({kredits:Ember.inject.service(),currentBlock:Ember.computed.alias("kredits.currentBlock"),compute:function(e){var n=t(e,1)[0]
return!n.vetoed&&n.confirmedAt<=this.currentBlock}})
e.default=n}),define("kredits-web/helpers/is-current-user",["exports"],function(e){function t(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=[],r=!0,i=!1,o=void 0
try{for(var s,u=e[Symbol.iterator]();!(r=(s=u.next()).done)&&(n.push(s.value),!t||n.length!==t);r=!0);}catch(a){i=!0,o=a}finally{try{r||null==u.return||u.return()}finally{if(i)throw o}}return n}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var n=Ember.Helper.extend({kredits:Ember.inject.service(),currentUser:Ember.computed.alias("kredits.currentUser"),compute:function(e){var n=t(e,1)[0]
return Ember.isPresent(n)&&Ember.isPresent(this.currentUser)&&n.account===this.currentUser.account}})
e.default=n}),define("kredits-web/helpers/is-equal",["exports","ember-truth-helpers/helpers/is-equal"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}}),Object.defineProperty(e,"isEqual",{enumerable:!0,get:function(){return t.isEqual}})}),define("kredits-web/helpers/is-fulfilled",["exports","ember-promise-helpers/helpers/is-fulfilled"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}}),Object.defineProperty(e,"isFulfilled",{enumerable:!0,get:function(){return t.isFulfilled}})}),define("kredits-web/helpers/is-pending",["exports","ember-promise-helpers/helpers/is-pending"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}}),Object.defineProperty(e,"isPending",{enumerable:!0,get:function(){return t.isPending}})}),define("kredits-web/helpers/is-rejected",["exports","ember-promise-helpers/helpers/is-rejected"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}}),Object.defineProperty(e,"isRejected",{enumerable:!0,get:function(){return t.isRejected}})}),define("kredits-web/helpers/lt",["exports","ember-truth-helpers/helpers/lt"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}}),Object.defineProperty(e,"lt",{enumerable:!0,get:function(){return t.lt}})}),define("kredits-web/helpers/lte",["exports","ember-truth-helpers/helpers/lte"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}}),Object.defineProperty(e,"lte",{enumerable:!0,get:function(){return t.lte}})}),define("kredits-web/helpers/not-eq",["exports","ember-truth-helpers/helpers/not-equal"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}}),Object.defineProperty(e,"notEq",{enumerable:!0,get:function(){return t.notEq}})}),define("kredits-web/helpers/not",["exports","ember-truth-helpers/helpers/not"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}}),Object.defineProperty(e,"not",{enumerable:!0,get:function(){return t.not}})}),define("kredits-web/helpers/or",["exports","ember-truth-helpers/helpers/or"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}}),Object.defineProperty(e,"or",{enumerable:!0,get:function(){return t.or}})}),define("kredits-web/helpers/promise-all",["exports","ember-promise-helpers/helpers/promise-all"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}}),Object.defineProperty(e,"promiseAll",{enumerable:!0,get:function(){return t.promiseAll}})}),define("kredits-web/helpers/promise-hash",["exports","ember-promise-helpers/helpers/promise-hash"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}}),Object.defineProperty(e,"promiseHash",{enumerable:!0,get:function(){return t.promiseHash}})}),define("kredits-web/helpers/promise-rejected-reason",["exports","ember-promise-helpers/helpers/promise-rejected-reason"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}})}),define("kredits-web/helpers/xor",["exports","ember-truth-helpers/helpers/xor"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}}),Object.defineProperty(e,"xor",{enumerable:!0,get:function(){return t.xor}})}),define("kredits-web/initializers/app-version",["exports","ember-cli-app-version/initializer-factory","kredits-web/config/environment"],function(e,t,n){var r,i
Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0,n.default.APP&&(r=n.default.APP.name,i=n.default.APP.version)
var o={name:"App Version",initialize:(0,t.default)(r,i)}
e.default=o}),define("kredits-web/initializers/container-debug-adapter",["exports","ember-resolver/resolvers/classic/container-debug-adapter"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var n={name:"container-debug-adapter",initialize:function(){var e=arguments[1]||arguments[0]
e.register("container-debug-adapter:main",t.default),e.inject("container-debug-adapter:main","namespace","application:main")}}
e.default=n}),define("kredits-web/initializers/export-application-global",["exports","kredits-web/config/environment"],function(e,t){function n(){var e=arguments[1]||arguments[0]
if(!1!==t.default.exportApplicationGlobal){var n
if("undefined"!=typeof window)n=window
else if("undefined"!=typeof global)n=global
else{if("undefined"==typeof self)return
n=self}var r,i=t.default.exportApplicationGlobal
r="string"==typeof i?i:Ember.String.classify(t.default.modulePrefix),n[r]||(n[r]=e,e.reopen({willDestroy:function(){this._super.apply(this,arguments),delete n[r]}}))}}Object.defineProperty(e,"__esModule",{value:!0}),e.initialize=n,e.default=void 0
var r={name:"export-application-global",initialize:n}
e.default=r}),define("kredits-web/models/contribution",["exports","kredits-web/utils/cps/bignumber"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var n=Ember.Object.extend({id:null,contributorId:null,amount:null,confirmedAt:(0,t.default)("confirmedAtBlock","toNumber"),vetoed:null,ipfsHash:null,creatorAccount:null,kind:null,description:null,details:null,url:null,ipfsData:"",init:function(){this._super.apply(this,arguments),this.set("details",{})}})
e.default=n}),define("kredits-web/models/contributor",["exports","kredits-web/utils/cps/bignumber","kredits-web/utils/cps/kredits"],function(e,t,n){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var r=Ember.Object.extend({id:(0,t.default)("idRaw","toString"),account:null,balance:(0,n.default)("balanceRaw"),totalKreditsEarned:(0,t.default)("totalKreditsEarnedRaw","toNumber"),contributionsCount:(0,t.default)("contributionsCountRaw","toNumber"),isCore:!1,ipfsHash:null,kind:null,name:null,url:null,github_username:null,github_uid:null,wiki_username:null,ipfsData:"",avatarURL:Ember.computed("github_uid",function(){var e=this.github_uid
if(e)return"https://avatars2.githubusercontent.com/u/".concat(e,"?v=3&s=128")})})
e.default=r}),define("kredits-web/models/proposal",["exports","kredits-web/utils/cps/bignumber"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var n=Ember.Object.extend({id:(0,t.default)("idRaw","toString"),creatorAccount:null,contributorId:(0,t.default)("contributorIdRaw","toString"),amount:(0,t.default)("amountRaw","toNumber"),votesCount:(0,t.default)("votesCountRaw","toNumber"),votesNeeded:(0,t.default)("votesNeededRaw","toNumber"),executed:null,ipfsHash:null,isExecuted:Ember.computed.alias("executed"),kind:null,description:null,details:null,url:null,ipfsData:"",init:function(){this._super.apply(this,arguments),this.set("details",{})}})
e.default=n}),define("kredits-web/resolver",["exports","ember-resolver"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var n=t.default
e.default=n}),define("kredits-web/router",["exports","kredits-web/config/environment"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var n=Ember.Router.extend({location:t.default.locationType,rootURL:t.default.rootURL})
n.map(function(){this.route("proposals",function(){this.route("new")}),this.route("contributions",function(){this.route("new")}),this.route("contributors",function(){this.route("new"),this.route("edit",{path:":id/edit"})})})
var r=n
e.default=r}),define("kredits-web/routes/application",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.Route.extend({kredits:Ember.inject.service(),beforeModel:function(e){var t=this.kredits
return t.setup().then(function(){t.get("kredits").preflightChecks().catch(function(e){console.error("Kredits preflight check failed!"),console.error(e)}),t.get("accountNeedsUnlock")&&confirm("It looks like you have an Ethereum wallet available. Please unlock your account.")&&e.retry()}).catch(function(e){console.log("Error initializing Kredits",e)})},afterModel:function(){var e=this
return this.kredits.loadInitialData().then(function(){e.kredits.addContractEventHandlers()})}})
e.default=t}),define("kredits-web/routes/contributors/edit",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.Route.extend({kredits:Ember.inject.service(),contributors:Ember.computed.alias("kredits.contributors"),model:function(e){return this.kredits.contributors.findBy("id",e.id)},setupController:function(e,t){this._super(e,t),e.set("attributes",{account:t.account,name:t.name,kind:t.kind,url:t.url,github_username:t.github_username,github_uid:t.github_uid,gitea_username:t.gitea_username,wiki_username:t.wiki_username})}})
e.default=t})
define("kredits-web/services/ajax",["exports","ember-ajax/services/ajax"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),Object.defineProperty(e,"default",{enumerable:!0,get:function(){return t.default}})}),define("kredits-web/services/kredits",["exports","npm:ethers","npm:kredits-contracts","kredits-web/utils/group-by","kredits-web/utils/format-kredits","kredits-web/config/environment","kredits-web/models/contributor","kredits-web/models/proposal","kredits-web/models/contribution"],function(e,t,n,r,i,o,s,u,a){function l(e,t,n,r,i,o,s){try{var u=e[o](s),a=u.value}catch(l){return void n(l)}u.done?t(a):Promise.resolve(a).then(r,i)}function d(e){return function(){var t=this,n=arguments
return new Promise(function(r,i){var o=e.apply(t,n)
function s(e){l(o,r,i,s,u,"next",e)}function u(e){l(o,r,i,s,u,"throw",e)}s(void 0)})}}Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var c=Ember.Service.extend({currentBlock:null,currentUserAccounts:null,currentUser:null,contributors:null,contributions:null,proposals:null,currentUserIsContributor:Ember.computed.notEmpty("currentUser"),currentUserIsCore:Ember.computed.alias("currentUser.isCore"),hasAccounts:Ember.computed.notEmpty("currentUserAccounts"),accountNeedsUnlock:Ember.computed("currentUserAccounts",function(){return this.currentUserAccounts&&Ember.isEmpty(this.currentUserAccounts)}),contributionsUnconfirmed:Ember.computed("contributions.[]","currentBlock",function(){var e=this
return this.contributions.filter(function(t){return t.confirmedAt>e.currentBlock})}),contributionsConfirmed:Ember.computed("contributions.[]","currentBlock",function(){var e=this
return this.contributions.filterBy("vetoed",!1).filter(function(t){return t.confirmedAt<=e.currentBlock})}),kreditsByContributor:Ember.computed("contributionsUnconfirmed.@each.vetoed","contributors.[]",function(){var e=this,t=this.contributionsUnconfirmed.filterBy("vetoed",!1),n=(0,r.default)(t,"contributorId"),i=n.map(function(e){return e.value.toString()}),o=this.contributors.reject(function(e){return i.includes(e.id)}),s=n.map(function(t){var n=t.items.mapBy("amount").reduce(function(e,t){return e+t}),r=e.contributors.findBy("id",t.value.toString())
return Ember.Object.create({contributor:r,amountUnconfirmed:n,amountConfirmed:r.totalKreditsEarned,amountTotal:r.totalKreditsEarned+n})})
return o.forEach(function(e){s.push(Ember.Object.create({contributor:e,amountUnconfirmed:0,amountConfirmed:e.totalKreditsEarned,amountTotal:e.totalKreditsEarned}))}),s}),init:function(){this._super.apply(this,arguments),this.set("contributors",[]),this.set("proposals",[]),this.set("contributions",[])},getEthProvider:function(){var e,n=this
return new Ember.RSVP.Promise(function(){var r=d(regeneratorRuntime.mark(function r(i){var s,u,a
return regeneratorRuntime.wrap(function(r){for(;;)switch(r.prev=r.next){case 0:if(a=function(){return(a=d(regeneratorRuntime.mark(function n(r,o){return regeneratorRuntime.wrap(function(n){for(;;)switch(n.prev=n.next){case 0:console.debug("[kredits] Using user-provided instance, e.g. from Mist browser or Metamask"),(e=new t.default.providers.Web3Provider(r)).listAccounts().then(function(t){o.set("currentUserAccounts",t)
var n=0===t.length?null:e.getSigner()
i({ethProvider:e,ethSigner:n})})
case 3:case"end":return n.stop()}},n)}))).apply(this,arguments)},u=function(e,t){return a.apply(this,arguments)},s=function(){console.debug("[kredits] Creating new instance from npm module class"),console.debug("[kredits] providerURL: ".concat(o.default.web3ProviderUrl)),e=new t.default.providers.JsonRpcProvider(o.default.web3ProviderUrl),i({ethProvider:e,ethSigner:null})},!window.ethereum){r.next=15
break}return r.prev=4,r.next=7,window.ethereum.enable()
case 7:u(window.ethereum,n),r.next=13
break
case 10:r.prev=10,r.t0=r.catch(4),s()
case 13:r.next=16
break
case 15:window.web3?u(window.web3.currentProvider,n):s()
case 16:case"end":return r.stop()}},r,null,[[4,10]])}))
return function(e){return r.apply(this,arguments)}}())},setup:function(){var e=this
return this.getEthProvider().then(function(t){return new n.default(t.ethProvider,t.ethSigner,{addresses:{Kernel:o.default.kreditsKernelAddress},apm:o.default.kreditsApmDomain,ipfsConfig:o.default.ipfs}).init().then(function(){var t=d(regeneratorRuntime.mark(function t(n){return regeneratorRuntime.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:return e.set("kredits",n),t.t0=e,t.next=4,n.provider.getBlockNumber()
case 4:return t.t1=t.sent,t.t0.set.call(t.t0,"currentBlock",t.t1),e.currentUserAccounts&&e.currentUserAccounts.length>0&&e.getCurrentUser.then(function(t){e.set("currentUser",t)}),t.abrupt("return",n)
case 8:case"end":return t.stop()}},t)}))
return function(e){return t.apply(this,arguments)}}())})},totalSupply:Ember.computed(function(){return this.kredits.Token.functions.totalSupply().then(function(e){return(0,i.default)(e)})}),totalKreditsEarned:Ember.computed(function(){return this.kredits.Contribution.functions.totalKreditsEarned(!0).then(function(e){return e.toNumber()})}),loadInitialData:function(){var e=this
return this.getContributors().then(function(t){return e.contributors.pushObjects(t)}).then(function(){return e.getContributions()}).then(function(t){return e.contributions.pushObjects(t)})},addContributor:function(e){if(e.github_uid){var t=parseInt(e.github_uid)
e.github_uid=t}return console.debug("[kredits] add contributor",e),this.kredits.Contributor.add(e,{gasLimit:35e4}).then(function(e){console.debug("[kredits] add contributor response",e)})},updateContributor:function(e,t){if(t.github_uid){var n=parseInt(t.github_uid)
t.github_uid=n}return console.debug("[kredits] update contributor",t),this.kredits.Contributor.updateProfile(e,t,{gasLimit:35e4}).then(function(e){console.debug("[kredits] updateProfile response",e)})},getContributors:function(){return this.kredits.Contributor.all().then(function(e){return e.map(function(e){return s.default.create(e)})})},addContribution:function(e){var t=this
return console.debug("[kredits] add contribution",e),this.kredits.Contribution.addContribution(e,{gasLimit:3e5}).then(function(n){console.debug("[kredits] add contribution response",n),e.contributor=t.contributors.findBy("id",e.contributorId)
var r=a.default.create(e)
return r.set("confirmedAtBlock",n.blockNumber+40320),t.contributions.pushObject(r),r})},addProposal:function(e){var t=this
return console.debug("[kredits] add proposal",e),this.kredits.Proposal.addProposal(e).then(function(n){return console.debug("[kredits] add proposal response",n),e.contributor=t.contributors.findBy("id",e.contributorId),u.default.create(e)})},getProposals:function(){var e=this
return this.kredits.Proposal.all().then(function(t){return t.map(function(t){return t.contributor=e.contributors.findBy("id",t.contributorId.toString()),u.default.create(t)})})},getContributions:function(){var e=this
return this.kredits.Contribution.all({page:{size:200}}).then(function(t){return t.map(function(t){return t.contributor=e.contributors.findBy("id",t.contributorId.toString()),a.default.create(t)})})},vote:function(e){return console.debug("[kredits] vote for",e),this.kredits.Proposal.functions.vote(e).then(function(e){return console.debug("[kredits] vote response",e),e})},veto:function(e){return console.debug("[kredits] veto against",e),this.kredits.Contribution.functions.veto(e,{gasLimit:3e5}).then(function(e){return console.debug("[kredits] veto response",e),e})},getCurrentUser:Ember.computed("kredits.provider",function(){var e=this
return Ember.isEmpty(this.currentUserAccounts)?Ember.RSVP.resolve():this.kredits.Contributor.functions.getContributorIdByAddress(this.get("currentUserAccounts.firstObject")).then(function(t){return 0===t?Ember.RSVP.resolve():e.kredits.Contributor.getById(t)})}),findProposalById:function(e){return this.proposals.findBy("id",e.toString())},addContractEventHandlers:function(){this.kredits.Contributor.on("ContributorProfileUpdated",this.handleContributorChange.bind(this)).on("ContributorAccountUpdated",this.handleContributorChange.bind(this)).on("ContributorAdded",this.handleContributorChange.bind(this)),this.kredits.Contribution.on("ContributionVetoed",this.handleContributionVetoed.bind(this)),this.kredits.Proposal.on("ProposalCreated",this.handleProposalCreated.bind(this)).on("ProposalVoted",this.handleProposalVoted.bind(this)).on("ProposalExecuted",this.handleProposalExecuted.bind(this)),this.kredits.Token.on("Transfer",this.handleTransfer.bind(this))},handleContributorChange:function(){var e=d(regeneratorRuntime.mark(function e(t){var n,r,i,o,u,a,l=arguments
return regeneratorRuntime.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:for(console.debug("[kredits] Contributor add/update event received for ID",t),n=l.length,r=new Array(n>1?n-1:0),i=1;i<n;i++)r[i-1]=l[i]
return console.debug("[kredits] Event data:",r),e.next=5,this.kredits.Contributor.getById(t)
case 5:o=e.sent,u=s.default.create(o),(a=this.contributors.findBy("id",t.toString()))&&(console.debug("[kredits] old contributor",a),this.contributors.removeObject(a)),console.debug("[kredits] new contributor",u),this.contributors.pushObject(u)
case 11:case"end":return e.stop()}},e,this)}))
return function(t){return e.apply(this,arguments)}}(),handleContributionVetoed:function(e){console.debug("[kredits] ContributionVetoed event received for ",e)
var t=this.contributions.findBy("id",e)
console.debug("[kredits] contribution",t),t&&t.set("vetoed",!0)},handleProposalCreated:function(e){var t=this
this.findProposalById(e)?console.debug("[events] proposal exists, not adding from event"):this.kredits.Proposal.getById(e).then(function(e){e.contributor=t.contributors.findBy("id",e.contributorId.toString()),t.proposals.pushObject(u.default.create(e))})},handleProposalVoted:function(e,t,n){var r=this.findProposalById(e)
r&&r.set("votesCount",n)},handleProposalExecuted:function(e,t,n){var r=this.findProposalById(e)
r.get("isExecuted")?console.debug("[events] proposal already executed, not adding from event"):(r.set("executed",!0),this.contributors.findBy("id",t.toString()).incrementProperty("balance",n))},handleTransfer:function(e,t,n){n=n.toNumber(),this.contributors.findBy("address",e).decrementProperty("balance",n),this.contributors.findBy("address",t).incrementProperty("balance",n)}})
e.default=c}),define("kredits-web/templates/application-loading",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.HTMLBars.template({id:"/K85jZFR",block:'{"symbols":[],"statements":[[1,[21,"loading-spinner"],false],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"kredits-web/templates/application-loading.hbs"}})
e.default=t}),define("kredits-web/templates/application",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.HTMLBars.template({id:"M6vaFJ5T",block:'{"symbols":[],"statements":[[7,"header"],[11,"id","topbar"],[9],[0,"\\n "],[7,"h1"],[9],[0,"Kosmos Kredits"],[10],[0,"\\n\\n "],[7,"section"],[11,"id","user-account"],[9],[0,"\\n"],[4,"if",[[23,["kredits","hasAccounts"]]],null,{"statements":[[4,"if",[[23,["kredits","currentUser"]]],null,{"statements":[[0," "],[1,[23,["kredits","currentUser","name"]],false],[0,"\\n "],[4,"if",[[23,["kredits","currentUserIsCore"]]],null,{"statements":[[0,"(core)"]],"parameters":[]},null],[0,"\\n"]],"parameters":[]},null]],"parameters":[]},{"statements":[[0," Anonymous\\n"]],"parameters":[]}],[0," "],[10],[0,"\\n"],[10],[0,"\\n\\n"],[1,[21,"outlet"],false],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"kredits-web/templates/application.hbs"}})
e.default=t}),define("kredits-web/templates/contributions/new",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.HTMLBars.template({id:"YPbtYII6",block:'{"symbols":[],"statements":[[7,"main"],[11,"class","center-column"],[9],[0,"\\n\\n "],[7,"section"],[11,"id","add-contribution"],[9],[0,"\\n "],[7,"header"],[9],[0,"\\n "],[7,"h2"],[9],[0,"Submit a contribution"],[10],[0,"\\n "],[10],[0,"\\n\\n "],[7,"div"],[11,"class","content"],[9],[0,"\\n "],[1,[27,"add-contribution",null,[["contributors","save"],[[23,["sortedContributors"]],[27,"action",[[22,0,[]],"save"],null]]]],false],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n\\n"],[10],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"kredits-web/templates/contributions/new.hbs"}})
e.default=t}),define("kredits-web/templates/contributors/edit",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.HTMLBars.template({id:"LZQyoYt+",block:'{"symbols":[],"statements":[[7,"main"],[11,"class","center-column"],[9],[0,"\\n\\n "],[7,"section"],[11,"id","add-contributor"],[9],[0,"\\n "],[7,"header"],[9],[0,"\\n "],[7,"h2"],[9],[0,"Update contributor profile"],[10],[0,"\\n "],[10],[0,"\\n\\n "],[7,"div"],[11,"class","content"],[9],[0,"\\n "],[1,[27,"add-contributor",null,[["attributes","save"],[[23,["attributes"]],[27,"action",[[22,0,[]],"save"],null]]]],false],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n\\n"],[10],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"kredits-web/templates/contributors/edit.hbs"}})
e.default=t}),define("kredits-web/templates/contributors/new",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.HTMLBars.template({id:"IoVi6fNU",block:'{"symbols":[],"statements":[[7,"main"],[11,"class","center-column"],[9],[0,"\\n\\n "],[7,"section"],[11,"id","add-contributor"],[9],[0,"\\n "],[7,"header"],[9],[0,"\\n "],[7,"h2"],[9],[0,"Add contributor profile"],[10],[0,"\\n "],[10],[0,"\\n\\n "],[7,"div"],[11,"class","content"],[9],[0,"\\n "],[1,[27,"add-contributor",null,[["save"],[[27,"action",[[22,0,[]],"save"],null]]]],false],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n\\n"],[10],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"kredits-web/templates/contributors/new.hbs"}})
e.default=t}),define("kredits-web/templates/index",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.HTMLBars.template({id:"kSDGlXXL",block:'{"symbols":[],"statements":[[7,"main"],[11,"id","index"],[9],[0,"\\n\\n "],[7,"div"],[11,"id","stats"],[9],[0,"\\n "],[7,"section"],[11,"id","people"],[9],[0,"\\n "],[7,"header"],[11,"class","with-nav"],[9],[0,"\\n "],[7,"h2"],[9],[0,"Contributors"],[10],[0,"\\n"],[4,"if",[[23,["kredits","hasAccounts"]]],null,{"statements":[[0," "],[7,"nav"],[9],[0,"\\n "],[4,"link-to",["contributors.new"],[["title","class"],["Add contributor profile","button small green"]],{"statements":[[0,"add"]],"parameters":[]},null],[0,"\\n "],[10],[0,"\\n"]],"parameters":[]},null],[0," "],[10],[0,"\\n "],[7,"div"],[11,"class","content"],[9],[0,"\\n "],[1,[27,"contributor-list",null,[["contributorList","showUnconfirmedKredits"],[[23,["kreditsToplist"]],[23,["showUnconfirmedKredits"]]]]],false],[0,"\\n\\n "],[7,"p"],[11,"class","stats"],[9],[0,"\\n "],[7,"span"],[11,"class","number"],[9],[1,[27,"await",[[23,["kredits","totalKreditsEarned"]]],null],false],[10],[0," kredits confirmed and issued to\\n "],[7,"span"],[11,"class","number"],[9],[1,[23,["contributorsWithKredits","length"]],false],[10],[0," contributors\\n "],[10],[0,"\\n "],[7,"p"],[11,"class","stats"],[9],[0,"\\n "],[1,[27,"input",null,[["type","id","checked"],["checkbox","hide-unnconfirmed-kredits",[23,["showUnconfirmedKredits"]]]]],false],[0,"\\n "],[7,"label"],[11,"for","hide-unnconfirmed-kredits"],[9],[0,"Show unconfirmed kredits in toplist"],[10],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n\\n "],[7,"section"],[11,"id","contributions-by-type"],[9],[0,"\\n "],[7,"header"],[9],[0,"\\n "],[7,"h2"],[9],[0,"Contributions by type"],[10],[0,"\\n "],[10],[0,"\\n "],[7,"div"],[11,"class","content"],[9],[0,"\\n "],[1,[27,"chart-contributions-by-type",null,[["contributions"],[[23,["contributions"]]]]],false],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n\\n "],[7,"div"],[11,"id","contributions"],[9],[0,"\\n"],[4,"if",[[23,["contributionsUnconfirmed"]]],null,{"statements":[[0," "],[7,"section"],[11,"id","contributions-unconfirmed"],[9],[0,"\\n "],[7,"header"],[11,"class","with-nav"],[9],[0,"\\n "],[7,"h2"],[9],[0,"Latest Contributions"],[10],[0,"\\n"],[4,"if",[[23,["kredits","hasAccounts"]]],null,{"statements":[[0," "],[7,"nav"],[9],[0,"\\n "],[4,"link-to",["contributions.new"],[["title","class"],["Submit a contribution","button small green"]],{"statements":[[0,"add"]],"parameters":[]},null],[0,"\\n "],[10],[0,"\\n"]],"parameters":[]},null],[0," "],[10],[0,"\\n "],[7,"div"],[11,"class","content"],[9],[0,"\\n"],[0," "],[1,[27,"contribution-list",null,[["contributions","vetoContribution","contractInteractionEnabled"],[[23,["contributionsUnconfirmedSorted"]],[27,"action",[[22,0,[]],"vetoContribution"],null],[23,["kredits","hasAccounts"]]]]],false],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n"]],"parameters":[]},null],[0,"\\n "],[7,"section"],[11,"id","contributions-confirmed"],[9],[0,"\\n "],[7,"header"],[9],[0,"\\n "],[7,"h2"],[9],[0,"Confirmed Contributions"],[10],[0,"\\n "],[10],[0,"\\n "],[7,"div"],[11,"class","content"],[9],[0,"\\n "],[1,[27,"contribution-list",null,[["contributions","vetoContribution"],[[23,["contributionsConfirmedSorted"]],[27,"action",[[22,0,[]],"vetoContribution"],null]]]],false],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n "],[10],[0,"\\n\\n"],[10],[0,"\\n"]],"hasEval":false}',meta:{moduleName:"kredits-web/templates/index.hbs"}})
e.default=t}),define("kredits-web/templates/proposals/new",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=void 0
var t=Ember.HTMLBars.template({id:"vauAEy3a",block:'{"symbols":[],"statements":[[7,"section"],[11,"id","add-proposal"],[9],[0,"\\n "],[7,"header"],[9],[0,"\\n "],[7,"h2"],[9],[0,"Add Proposal"],[10],[0,"\\n "],[10],[0,"\\n\\n "],[7,"div"],[11,"class","content"],[9],[0,"\\n "],[1,[27,"add-proposal",null,[["contributors","save"],[[23,["minedContributors"]],[27,"action",[[22,0,[]],"save"],null]]]],false],[0,"\\n "],[10],[0,"\\n"],[10],[0,"\\n\\n"]],"hasEval":false}',meta:{moduleName:"kredits-web/templates/proposals/new.hbs"}})
e.default=t}),define("kredits-web/utils/cps/bignumber",["exports","npm:ethers"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(e,n){return Ember.computed(e,{get:function(){var r=this.get(e)
return r&&t.default.utils.BigNumber.isBigNumber(r)?r[n]():r},set:function(r,i){var o=t.default.utils.bigNumberify(i)
return this.set(e,o),o[n]()}})}}),define("kredits-web/utils/cps/kredits",["exports","npm:ethers","kredits-web/utils/format-kredits"],function(e,t,n){Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(e){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{}
return Ember.computed(e,{get:function(){var t=this.get(e)
return(0,n.default)(t,r)},set:function(i,o){var s=t.default.utils.bigNumberify(o)
return this.set(e,s),(0,n.default)(s,r)}})}}),define("kredits-web/utils/format-kredits",["exports","npm:ethers"],function(e,t){Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=t.default.utils.formatEther(e)
n.decimals||(r=parseInt(r).toString())
return r}}),define("kredits-web/utils/group-by",["exports"],function(e){Object.defineProperty(e,"__esModule",{value:!0}),e.default=function(e,t){var n=Ember.A(),r=e
r&&r.forEach(function(e){var r=Ember.get(e,t),i=n.findBy("value",r)
Ember.isPresent(i)?Ember.get(i,"items").push(e):(i={property:t,value:r,items:[e]},n.push(i))})
return n}}),define("kredits-web/config/environment",[],function(){try{var e="kredits-web/config/environment",t=document.querySelector('meta[name="'+e+'"]').getAttribute("content"),n={default:JSON.parse(decodeURIComponent(t))}
return Object.defineProperty(n,"__esModule",{value:!0}),n}catch(r){throw new Error('Could not read config from meta tag with name "'+e+'".')}}),runningTests||require("kredits-web/app").default.create({name:"kredits-web",version:"1.1.0+afc5a5fe"})
//# sourceMappingURL=kredits-web-197c3a17a9acd491a566e77e46e50b52.map
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

Before

Width:  |  Height:  |  Size: 669 KiB

-9
View File
@@ -1,9 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1" x="0px" y="0px" viewBox="0 0 100 100"
enable-background="new 0 0 100 100" xml:space="preserve">
<path id="path-comet"
d="M79.062,24.173L79.062,24.173l-0.021-0.011c-0.068-0.03-0.137-0.062-0.204-0.093L42.392,7.337
c0,0,3.065,14.104,4.458,18.019l0,0c0,0-41.754-12.481-46.85-13.67c1.67,6.52,30.607,62.492,30.607,62.492
c5.848,11.873,19.394,18.485,33.522,18.485c19.811,0,35.87-16.059,35.87-35.869C100,42.313,91.418,29.837,79.062,24.173z">
</path>
</svg>

Before

Width:  |  Height:  |  Size: 590 B

-32
View File
@@ -1,32 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Kosmos Kredits</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="kredits-web/config/environment" content="%7B%22modulePrefix%22%3A%22kredits-web%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22auto%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%7D%7D%2C%22APP%22%3A%7B%22name%22%3A%22kredits-web%22%2C%22version%22%3A%221.1.0%2Bafc5a5fe%22%7D%2C%22browserify%22%3A%7B%22tests%22%3Atrue%2C%22transform%22%3A%5B%5B%22babelify%22%2C%7B%22presets%22%3A%5B%22es2015%22%5D%2C%22global%22%3Atrue%7D%5D%5D%7D%2C%22web3ProviderUrl%22%3A%22https%3A%2F%2Frinkeby.infura.io%2Fv3%2Fd4f788b7a6584f7db2fc3c268d4d09e9%22%2C%22ipfs%22%3A%7B%22host%22%3A%22ipfs.kosmos.org%22%2C%22port%22%3A%225444%22%2C%22protocol%22%3A%22https%22%7D%2C%22kreditsApmDomain%22%3A%22open.aragonpm.eth%22%2C%22exportApplicationGlobal%22%3Afalse%7D" />
<link integrity="" rel="stylesheet" href="/assets/vendor-179cf27a97ea5bbb0ce72403a401cc8c.css">
<link integrity="" rel="stylesheet" href="/assets/kredits-web-29d147f9bc6d79dbc7aff481f8ee5541.css">
<script>
window.addEventListener('load', function() {
window.windowLoadComplete = true;
});
</script>
</head>
<body>
<script src="/assets/vendor-801d0f45e82f8bef6ee0b28f728036e5.js" integrity="sha256-0rvoxLzxNRaodYFUkwv5D3zakixGtC+//xKSO9XtbKc= sha512-YNRAvmy8HT14rRH3MwaQciCOYPZwuuiDT5Bsi3aIXUWtADH2HNxR3K88BTGtNEbOXCCSewh0vpkiBt1o1eyTvg==" ></script>
<script src="/assets/kredits-web-4214f7a9448535607cb840171b47f23f.js" integrity="sha256-ZDOnvMGSGUvm5BddhSpT+oHY+rkOjBq1nWJQkwozOt8= sha512-KcJoyjiarr0oErrRwWFunNic60KNhjHl7WZqLElEz2D0Js11uvQOVIba61L4KnaxgZZ4NaOQz49faSCWA9c5Ew==" ></script>
</body>
</html>
-3
View File
@@ -1,3 +0,0 @@
# http://www.robotstxt.org
User-agent: *
Disallow:
+10 -22
View File
@@ -1,25 +1,13 @@
/*jshint node:true*/
module.exports = { module.exports = {
test_page: 'tests/index.html?hidepassed', "framework": "qunit",
disable_watching: true, "test_page": "tests/index.html?hidepassed",
launch_in_ci: [ "disable_watching": true,
'Chrome' "launch_in_ci": [
"PhantomJS"
], ],
launch_in_dev: [ "launch_in_dev": [
'Chrome' "PhantomJS",
], "Chrome"
browser_args: { ]
Chrome: {
ci: [
// --no-sandbox is needed when running Chrome inside a container
process.env.CI ? '--no-sandbox' : null,
'--headless',
'--disable-gpu',
'--disable-dev-shm-usage',
'--disable-software-rasterizer',
'--mute-audio',
'--remote-debugging-port=0',
'--window-size=1440,900'
].filter(Boolean)
}
}
}; };
+52
View File
@@ -0,0 +1,52 @@
{
"predef": [
"document",
"window",
"location",
"setTimeout",
"$",
"-Promise",
"define",
"console",
"visit",
"exists",
"fillIn",
"click",
"keyEvent",
"triggerEvent",
"find",
"findWithAssert",
"wait",
"DS",
"andThen",
"currentURL",
"currentPath",
"currentRouteName"
],
"node": false,
"browser": false,
"boss": true,
"curly": true,
"debug": false,
"devel": false,
"eqeqeq": true,
"evil": true,
"forin": false,
"immed": false,
"laxbreak": false,
"newcap": true,
"noarg": true,
"noempty": false,
"nonew": false,
"nomen": false,
"onevar": false,
"plusplus": false,
"regexp": false,
"undef": true,
"sub": true,
"strict": false,
"white": false,
"eqnull": true,
"esversion": 6,
"unused": true
}
-19
View File
@@ -1,19 +0,0 @@
import Model from 'kredits-web/models/contribution';
const items = [];
const data = [
{ id: 1, contributorId: 1, confirmedAtBlock: 1000, claimed: false, vetoed: false, amount: 1500 },
{ id: 2, contributorId: 1, confirmedAtBlock: 1000, claimed: false, vetoed: false, amount: 5000 },
{ id: 3, contributorId: 2, confirmedAtBlock: 1000, claimed: false, vetoed: false, amount: 1500 },
{ id: 4, contributorId: 2, confirmedAtBlock: 1000, claimed: false, vetoed: false, amount: 1500 },
{ id: 5, contributorId: 1, confirmedAtBlock: 1000, claimed: false, vetoed: false, amount: 5000 },
{ id: 6, contributorId: 1, confirmedAtBlock: 1000, claimed: false, vetoed: true, amount: 500 },
{ id: 7, contributorId: 3, confirmedAtBlock: 2000, claimed: false, vetoed: false, amount: 5000 },
{ id: 8, contributorId: 1, confirmedAtBlock: 2000, claimed: false, vetoed: false, amount: 1500 },
{ id: 9, contributorId: 3, confirmedAtBlock: 2000, claimed: false, vetoed: true, amount: 1500 },
];
data.forEach(attrs => items.push(Model.create(attrs)));
export default items;
-13
View File
@@ -1,13 +0,0 @@
import Contributor from 'kredits-web/models/contributor';
const contributors = [];
const data = [
{ id: 1, name: 'Bumi', totalKreditsEarned: 11500 },
{ id: 2, name: 'Râu Cao', totalKreditsEarned: 3000 },
{ id: 3, name: 'Manuel', totalKreditsEarned: 0 }
];
data.forEach(attrs => contributors.push(Contributor.create(attrs)));
export default contributors;
View File
+5
View File
@@ -0,0 +1,5 @@
import Ember from 'ember';
export default function destroyApp(application) {
Ember.run(application, 'destroy');
}
+23
View File
@@ -0,0 +1,23 @@
import { module } from 'qunit';
import Ember from 'ember';
import startApp from '../helpers/start-app';
import destroyApp from '../helpers/destroy-app';
const { RSVP: { Promise } } = Ember;
export default function(name, options = {}) {
module(name, {
beforeEach() {
this.application = startApp();
if (options.beforeEach) {
return options.beforeEach.apply(this, arguments);
}
},
afterEach() {
let afterEach = options.afterEach && options.afterEach.apply(this, arguments);
return Promise.resolve(afterEach).then(() => destroyApp(this.application));
}
});
}

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