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 41144 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.
*/
"disableAnalytics": true
"disableAnalytics": false
}
-21
View File
@@ -1,21 +0,0 @@
# unconventional js
/blueprints/*/files/
/vendor/
# compiled output
/dist/
/tmp/
/release/
# 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.
# compiled output
/dist/
/tmp/
/dist
/tmp
# dependencies
/bower_components/
/node_modules/
/node_modules
/bower_components
# misc
/.env*
/.pnp*
/.sass-cache
/connect.lock
/coverage/
/coverage/*
/libpeerconnection.log
/npm-debug.log*
/testem.log
/yarn-error.log
.tm_properties
# ember-try
/.node_modules.ember-try/
/bower.json.ember-try
/package.json.ember-try
npm-debug.log*
testem.log
+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
node_js:
- "10"
- "6"
sudo: false
dist: xenial
addons:
chrome: stable
cache:
directories:
- $HOME/.npm
env:
global:
# See https://git.io/vdao3 for details.
- JOBS=1
- $HOME/.cache # includes bowers cache
before_install:
- 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:
- npm run lint:hbs
- npm run lint:js
- 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.
* [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/)
* [Google Chrome](https://google.com/chrome/)
* [PhantomJS](http://phantomjs.org/)
## Installation
* `git clone git@github.com:67P/kredits-web.git` this repository
* `git clone <repository-url>` this repository
* `cd kredits-web`
* `npm install`
* `bower install`
## Running / Development
* `ember serve` - by default kredits-web connects to the Ethreum Kovan network
* `ember serve`
* 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
@@ -38,12 +36,6 @@ Make use of the many generators for code, try `ember help generate` for more det
* `ember test`
* `ember test --server`
### Linting
* `npm run lint:hbs`
* `npm run lint:js`
* `npm run lint:js -- --fix`
### Building
* `ember build` (development)
@@ -51,66 +43,11 @@ Make use of the many generators for code, try `ember help generate` for more det
### Deploying
_(You need collaborator permissions on the 5apps Deploy project.)_
`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"]'
Specify what it takes to deploy your app.
## Further Reading / Useful Links
* [ember.js](https://emberjs.com/)
* [ember.js](http://emberjs.com/)
* [ember-cli](https://ember-cli.com/)
* Development Browser Extensions
* [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 loadInitializers from 'ember-load-initializers';
import config from './config/environment';
const App = Application.extend({
let App;
Ember.MODEL_FACTORY_INJECTIONS = true;
App = Ember.Application.extend({
modulePrefix: config.modulePrefix,
podModulePrefix: config.podModulePrefix,
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.name}}</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 "special"}}>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 { and, notEmpty } from '@ember/object/computed';
import { inject as service } from '@ember/service';
import { isPresent } from '@ember/utils';
import Ember from 'ember';
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
isValidAccount: notEmpty('account'),
isValidName: notEmpty('name'),
isValidURL: notEmpty('url'),
isValidGithubUID: notEmpty('github_uid'),
isValidGithubUsername: notEmpty('github_username'),
isValidGiteaUsername: notEmpty('gitea_username'),
isValidWikiUsername: notEmpty('wiki_username'),
isValid: and(
'isValidAccount',
'isValidName',
'isValidGithubUID'
),
classRealName: function() {
let value = this.get('realName');
return (Ember.isEmpty(value)) ? null : 'valid';
}.property('realName'),
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: {
submit () {
if (!this.isValid) {
alert('Invalid data. Please review and try again.');
return;
}
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);
});
save() {
console.log('id', this.get('id'));
console.log('realName', this.get('realName'));
console.log('address', this.get('address'));
}
}
+20 -44
View File
@@ -1,50 +1,26 @@
<form {{action "submit" on="submit"}}>
<form {{action "save" on="submit"}}>
<p>
<label for="c-account">Ethereum account</label>
{{input name="account" id="c-account"
type="text" value=account
{{input name="id"
type="text"
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"
class=(if isValidAccount "valid" "")}}
</p>
<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"}}
value=address
class=classAddress}}
</p>
<p class="actions">
{{input type="submit" disabled=inProgress
value=(if inProgress "Processing" "Save")}}
<input type="submit" value="Save">
</p>
</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',
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);
}
}
}
classNames: 'contributor-list'
});
+5 -30
View File
@@ -1,39 +1,14 @@
<tbody>
{{#each contributorList as |c|}}
<tr role="button" class={{if (is-current-user c.contributor) "current-user"}} {{action "toggleContributorInfo" c}}>
{{#each contributors as |contributor|}}
<tr>
<td class="person">
{{user-avatar contributor=c.contributor}} {{c.contributor.name}}
<img class="avatar" src={{contributor.avatarURL}}>
{{contributor.github_username}}
</td>
<td class="kredits">
<span class="amount">
{{#if showUnconfirmedKredits}}
{{c.amountTotal}}
{{else}}
{{c.amountConfirmed}}
{{/if}}
</span>
<span class="amount">{{contributor.kredits}}</span>
<span class="symbol">₭S</span>
</td>
</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}}
</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']
+2 -2
View File
@@ -2,7 +2,7 @@
<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"
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
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">
@@ -10,5 +10,5 @@
</svg>
</p>
<p>
Loading data...
Loading data from Ethereum...
</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',
classNames: ['proposal-list'],
@@ -8,11 +8,7 @@ export default Component.extend({
actions: {
confirm(proposalId) {
if (this.contractInteractionEnabled) {
this.confirmProposal(proposalId);
} else {
window.alert('Only members can vote on proposals. Please ask someone to set you up.');
}
this.sendAction('confirmAction', proposalId);
}
}
+8 -17
View File
@@ -1,20 +1,11 @@
{{#each proposals as |proposal|}}
<li data-proposal-id={{proposal.id}} class={{if proposal.isExecuted "confirmed" "unconfirmed"}}>
<p class="meta">
<span class="category {{proposal.kind}}">♥ ({{proposal.kind}})</span>
<span class="recipient">{{proposal.contributor.name}}:</span>
</p>
<p class="kredits-amount">
<span class="amount">{{proposal.amount}}</span><span class="symbol">₭S</span>
</p>
<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>
<span class="id">#{{proposal.id}}</span>
Issue{{#if proposal.executed}}d{{/if}}
<span class="amount">{{proposal.amount}}</span><span class="symbol">₭S</span>
to <span class="recipient" title="{{proposal.recipientAddress}}">{{proposal.recipientName}}</span>
<span class="votes">({{proposal.votesCount}}/{{proposal.votesNeeded}} votes)</span>
{{#unless proposal.executed}}<button {{action "confirm" proposal.id}}>+1</button>{{/unless}}
</li>
{{/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 { inject as service } from '@ember/service';
import Ember from 'ember';
export default Controller.extend({
kredits: service(),
export default Ember.Controller.extend({
});
-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 { computed } from '@ember/object';
import { alias, not, sort } from '@ember/object/computed';
import { inject as service } from '@ember/service';
import Ember from 'ember';
const {
computed,
inject: {
service
}
} = Ember;
export default Ember.Controller.extend({
export default Controller.extend({
kredits: service(),
currentBlock: alias('kredits.currentBlock'),
contributions: alias('kredits.contributions'),
contributionsConfirmed: alias('kredits.contributionsConfirmed'),
contributionsUnconfirmed: alias('kredits.contributionsUnconfirmed'),
contractInteractionEnabled: computed.alias('kredits.web3Provided'),
contributionsSorting: Object.freeze(['id:desc']),
contributionsUnconfirmedSorted: sort('contributionsUnconfirmed', 'contributionsSorting'),
contributionsConfirmedSorted: sort('contributionsConfirmed', 'contributionsSorting'),
findContributorByAddress(address) {
return this.get('model.contributors')
.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(){
return this.showUnconfirmedKredits ? ['amountTotal:desc'] : ['amountConfirmed:desc'];
}),
kreditsToplist: sort('kreditsByContributor', 'kreditsToplistSorting'),
proposalsClosed: function() {
let proposals = this.get('model.proposals')
.filterBy('executed', true)
.map(p => {
p.recipientName = this.findContributorByAddress(p.recipientAddress).github_username;
return p;
});
return proposals;
}.property('model.proposals.[]', 'model.contributors.[]'),
showUnconfirmedKredits: true,
hideUnconfirmedKredits: not('showUnconfirmedKredits'),
proposalsSorting: ['id:desc'],
proposalsClosedSorted: Ember.computed.sort('proposalsClosed', 'proposalsSorting'),
proposalsOpenSorted: Ember.computed.sort('proposalsOpen', 'proposalsSorting'),
contributorsSorting: ['kredits:desc'],
contributorsSorted: Ember.computed.sort('model.contributors', 'contributorsSorting'),
actions: {
vetoContribution (contributionId) {
this.kredits.veto(contributionId).then(transaction => {
console.debug('[controllers:index] Veto submitted to Ethereum blockhain: '+transaction.hash);
});
},
confirmProposal (proposalId) {
this.kredits.vote(proposalId).then(transaction => {
console.debug('[controllers:index] Vote submitted to Ethereum blockhain: '+transaction.hash);
confirmProposal(proposalId) {
this.get('kredits').vote(proposalId).then(transactionId => {
window.confirm('Vote submitted to Ethereum blockhain: '+transactionId);
});
}
}
});
-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>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Kosmos Kredits</title>
<title>KreditsWeb</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
{{content-for "head"}}
<link integrity="" rel="stylesheet" href="{{rootURL}}assets/vendor.css">
<link integrity="" rel="stylesheet" href="{{rootURL}}assets/kredits-web.css">
<link rel="stylesheet" href="{{rootURL}}assets/vendor.css">
<link rel="stylesheet" href="{{rootURL}}assets/kredits-web.css">
{{content-for "head-footer"}}
<script>
window.addEventListener('load', function() {
window.windowLoadComplete = true;
});
</script>
</head>
<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 EmberObject from '@ember/object';
import bignumber from 'kredits-web/utils/cps/bignumber';
import kreditsValue from 'kredits-web/utils/cps/kredits';
import Ember from 'ember';
export default EmberObject.extend({
// Contract
id: bignumber('idRaw', 'toString'),
account: null,
balance: kreditsValue('balanceRaw'),
totalKreditsEarned: bignumber('totalKreditsEarnedRaw', 'toNumber'),
contributionsCount: bignumber('contributionsCountRaw', 'toNumber'),
isCore: false,
ipfsHash: null,
export default Ember.Object.extend({
// IPFS
kind: null,
name: null,
url: null,
github_username: null,
github_uid: null,
wiki_username: null,
ipfsData: '',
kredits: null,
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 { alias } from '@ember/object/computed';
import bignumber from 'kredits-web/utils/cps/bignumber';
import Ember from 'ember';
export default EmberObject.extend({
export default Ember.Object.extend({
// Contract
id: bignumber('idRaw', 'toString'),
creatorAccount: null,
contributorId: bignumber('contributorIdRaw', 'toString'),
amount: bignumber('amountRaw', 'toNumber'),
votesCount: bignumber('votesCountRaw', 'toNumber'),
votesNeeded: bignumber('votesNeededRaw', 'toNumber'),
id: null,
creator: null,
recipient: null,
votesCount: null,
votesNeeded: null,
amount: null,
executed: null,
ipfsHash: null,
// Shortcuts
isExecuted: alias('executed'),
// IPFS
kind: null,
description: null,
details: null,
url: null,
ipfsData: '',
init () {
this._super(...arguments);
this.set('details', {});
}
ipfsHash: null
});
+3 -12
View File
@@ -1,22 +1,13 @@
import EmberRouter from '@ember/routing/router';
import Ember from 'ember';
import config from './config/environment';
const Router = EmberRouter.extend({
const Router = Ember.Router.extend({
location: config.locationType,
rootURL: config.rootURL
});
Router.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' });
});
this.route('spinner');
});
export default Router;
+2 -29
View File
@@ -1,31 +1,4 @@
import { inject as service } from '@ember/service';
import Route from '@ember/routing/route';
import Ember from 'ember';
export default 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();
});
}
export default Ember.Route.extend({
});
-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 Kredits from 'npm:kredits-contracts';
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 Ember from 'ember';
import Web3 from 'npm:web3';
import config from 'kredits-web/config/environment';
import Contributor from 'kredits-web/models/contributor'
import Proposal from 'kredits-web/models/proposal'
import Contribution from 'kredits-web/models/contribution'
import Contributor from 'kredits-web/models/contributor';
import Proposal from 'kredits-web/models/proposal';
import kreditsContracts from 'npm:kredits-contracts';
export default Service.extend({
export default Ember.Service.extend({
currentBlock: null,
currentUserAccounts: null, // default to not having an account. this is the wen web3 is loaded.
currentUser: null,
contributors: null,
contributions: null,
proposals: null,
web3Instance: null,
web3Provided: false, // Web3 provided (using Mist Browser, Metamask et al.)
currentUserIsContributor: notEmpty('currentUser'),
currentUserIsCore: alias('currentUser.isCore'),
hasAccounts: notEmpty('currentUserAccounts'),
web3: function() {
if (this.get('web3Instance')) {
return this.get('web3Instance');
}
accountNeedsUnlock: computed('currentUserAccounts', function() {
return this.currentUserAccounts && isEmpty(this.currentUserAccounts);
}),
let web3Instance;
contributionsUnconfirmed: computed('contributions.[]', 'currentBlock', function() {
return this.contributions.filter(contribution => {
return contribution.confirmedAt > this.currentBlock;
if (typeof window.web3 !== 'undefined') {
Ember.Logger.debug('[kredits] Using user-provided instance, e.g. from Mist browser or Metamask');
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
// initialized before everything else, and we can rely on the ethProvider and
// the potential currentUserAccounts to be available
getEthProvider () {
let ethProvider;
return new RSVP.Promise(async (resolve) => {
function instantiateWithoutAccount () {
console.debug('[kredits] Creating new instance from npm module class');
console.debug(`[kredits] providerURL: ${config.web3ProviderUrl}`);
ethProvider = new ethers.providers.JsonRpcProvider(config.web3ProviderUrl);
resolve({
ethProvider: ethProvider,
ethSigner: null
});
}
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
getContributorData(i) {
let promise = new Ember.RSVP.Promise((resolve, reject) => {
this.getValueFromContract('contributorAddresses', i).then(address => {
this.getValueFromContract('contributors', address).then(person => {
this.getValueFromContract('balanceOf', address).then(balance => {
let contributor = Contributor.create({
address: address,
github_username: person[1],
github_uid: person[0],
ipfsHash: person[3],
kredits: balance.toNumber()
});
Ember.Logger.debug('[kredits] contributor', contributor);
resolve(contributor);
});
});
}).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) {
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();
}
return Ember.RSVP.all(contributors);
});
},
setup () {
return this.getEthProvider().then((providerAndSigner) => {
let kredits = new Kredits(providerAndSigner.ethProvider, providerAndSigner.ethSigner, {
addresses: { Kernel: config.kreditsKernelAddress },
apm: config.kreditsApmDomain,
ipfsConfig: config.ipfs
});
return kredits
.init()
.then(async (kredits) => {
this.set('kredits', kredits);
this.set('currentBlock', await kredits.provider.getBlockNumber());
if (this.currentUserAccounts && this.currentUserAccounts.length > 0) {
this.getCurrentUser.then((contributorData) => {
this.set('currentUser', contributorData);
});
}
return kredits;
getProposalData(i) {
let promise = new Ember.RSVP.Promise((resolve, reject) => {
this.getValueFromContract('proposals', i).then(p => {
let proposal = Proposal.create({
id : i,
creatorAddress : p[0],
recipientAddress : p[1],
votesCount : p[2].toNumber(),
votesNeeded : p[3].toNumber(),
amount : p[4].toNumber(),
executed : p[5],
url : p[6],
ipfsHash : p[7]
});
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() {
return this.kredits.Token.functions.totalSupply().then(total => {
return formatKredits(total);
})
}),
totalKreditsEarned: computed(function() {
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);
vote(proposalId) {
Ember.Logger.debug('[kredits] vote for', proposalId);
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);
resolve(data);
});
});
},
updateContributor (id, attributes) {
if (attributes.github_uid) {
const uidInt = parseInt(attributes.github_uid);
attributes.github_uid = uidInt;
}
logKreditsContract: function() {
Ember.Logger.debug('[kredits] kreditsContract', this.get('kreditsContract'));
}.on('init')
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 {
padding: 1rem 2rem;
@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;
section {
@include outer-container;
margin-bottom: 8rem;
&:first-of-type {
margin-top: 2rem;
margin-top: 6rem;
}
@include media-max(small) {
@include media($mobile) {
margin-bottom: 5rem;
&:first-of-type {
margin-top: 2rem;
}
}
header {
margin-bottom: 3rem;
@include span-columns(12);
padding-bottom: 3rem;
text-align: center;
// background-color: purple;
&.with-nav {
display: grid;
grid-template-columns: auto 5rem;
grid-template-areas:
"title" "actions";
@include media($mobile) {
@include span-columns(10);
@include shift(1);
padding-bottom: 2rem;
}
h2 {
display: inline-block;
// padding-left: 1.2rem;
}
nav {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
}
@include media-max(small) {
margin-bottom: 2rem;
div.content {
@include span-columns(12);
}
}
}
-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;
padding: 0;
box-sizing: border-box;
font-size: 14px;
}
*:hover, *:active, *:focus {
@@ -11,19 +10,22 @@
-webkit-tap-highlight-color: transparent;
}
@import "mediaqueries";
@import "bourbon";
@import "settings/neat";
@import "neat";
@import "settings/breakpoints";
@import "layout";
@import "colors";
$font-family-sans: 'Open Sans', sans-serif;
body {
font-family: $font-family-sans;
font-weight: 300;
background-image: linear-gradient(to bottom, rgba(22, 21, 40, .4), rgba(0, 0, 0, .75)), url('/img/bg.jpg');
background-image: url('/img/bg.jpg');
background-repeat: none;
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) {
@@ -40,66 +42,48 @@ h1, h2, h3, h4, h5, input, button {
section {
h2 {
font-size: 1.4rem;
color: $primary-color;
font-size: 2.8rem;
color: lightblue;
@include media($mobile) {
font-size: 2rem;
}
}
&#people {
&#contributors {
.content {
p.stats {
margin-bottom: 1rem;
padding-top: 3rem;
font-size: 1rem;
color: white;
color: lightblue;
text-align: center;
span.number {
font-weight: 600;
}
}
}
}
&#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;
@include media($mobile) {
padding-top: 2rem;
}
}
}
}
}
@media (min-width: 550px) {
section {
h2 {
font-size: 2rem;
}
button, input[type=submit] {
display: inline-block;
border: 1px solid rgba(22, 21, 40, 1);
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/contributor-list";
@import "components/add-contributor";
@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 {
width: 100%;
border-collapse: collapse;
margin-bottom: 1.5rem;
tr {
border-bottom: 1px solid rgba(255,255,255,0.2);
&:first-of-type {
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);
&.current-user {
background-color: rgba(255,255,255,0.2);
}
&.metadata {
height: 0;
visibility: hidden;
&: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;
}
&.person {
text-align: left;
font-size: 1.4rem;
img.avatar {
width: 2rem;
height: 2rem;
vertical-align: middle;
margin-right: 0.2rem;
border-radius: 1rem;
}
}
td {
padding: 0 1.2rem;
line-height: 3.6rem;
&.person {
text-align: left;
font-size: 1.2rem;
img.avatar {
margin-right: 0.2rem;
}
&.kredits {
text-align: right;
.amount {
font-size: 1.4rem;
}
&.kredits {
text-align: right;
.amount {
font-size: 1.2rem;
font-weight: 500;
}
.symbol {
font-size: 0.8rem;
padding-left: 0.2rem;
}
}
pre {
line-height: 1rem;
padding-bottom: 1rem;
.symbol {
font-size: 1rem;
padding-left: 0.2rem;
}
}
}
+3 -3
View File
@@ -11,9 +11,9 @@
margin-top: 12rem;
text-align: center;
font-size: 1.4rem;
color: $primary-color;
color: lightblue;
@include media-max(small) {
@include media($mobile) {
margin-top: 6rem;
}
@@ -23,7 +23,7 @@
margin-bottom: 2rem;
#path-comet {
fill: $primary-color;
fill: lightblue;
opacity: 0.1;
animation-name: pulse;
+16 -83
View File
@@ -4,111 +4,44 @@ ul.proposal-list {
list-style: none;
li {
display: grid;
grid-template-columns: auto 5rem;
grid-row-gap: 0.5rem;
padding: 1rem 1.2rem;
// display: block;
padding: 0 1.2rem;
line-height: 4.2rem;
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);
&:first-of-type {
border-top: 1px solid rgba(255,255,255,0.2);
}
p {
align-self: center;
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;
.id {
color: lightblue;
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: 1rem;
font-weight: 500;
padding-left: 0.2rem;
}
.recipient {
font-weight: 500;
}
.votes {
font-size: 1rem;
color: $primary-color;
margin-right: 0.5rem;
color: lightblue;
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">
<h1>Kosmos Kredits</h1>
<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}}
<main>
{{outlet}}
</main>
-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">
<section id="people">
<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}}
<div class="content">
{{contributor-list contributors=contributorsSorted}}
<p class="stats">
<span class="number">{{await kredits.totalKreditsEarned}}</span> kredits confirmed and issued to
<span class="number">{{contributorsWithKredits.length}}</span> contributors
</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>
<p class="stats">
<span class="number">{{model.totalSupply}}</span> kredits issued and distributed among
<span class="number">{{model.contributorsCount}}</span> contributors.
</p>
</div>
</section>
<div id="contributions">
{{#if contributionsUnconfirmed}}
<section id="contributions-unconfirmed">
<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">
{{#if contractInteractionEnabled}}
{{#if proposalsOpen}}
<section id="proposals-open">
<header>
<h2>Confirmed Contributions</h2>
<h2>Open Proposals</h2>
</header>
<div class="content">
{{contribution-list contributions=contributionsConfirmedSorted
vetoContribution=(action "vetoContribution")}}
{{proposal-list proposals=proposalsOpenSorted confirmAction="confirmProposal"}}
</div>
</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 */
'use strict';
module.exports = function(environment) {
let ENV = {
var ENV = {
modulePrefix: 'kredits-web',
environment,
environment: environment,
rootURL: '/',
locationType: 'auto',
EmberENV: {
FEATURES: {
// Here you can enable experimental features on an ember canary build
@@ -23,40 +19,16 @@ module.exports = function(environment) {
APP: {
// Here you can pass flags/options to your application instance
// 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') {
ENV.web3ProviderUrl = "http://139.59.248.169:8545";
// ENV.APP.LOG_RESOLVER = true;
// ENV.APP.LOG_ACTIVE_GENERATION = true;
// ENV.APP.LOG_TRANSITIONS = true;
// ENV.APP.LOG_TRANSITIONS_INTERNAL = 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') {
@@ -68,22 +40,9 @@ module.exports = function(environment) {
ENV.APP.LOG_VIEW_LOOKUPS = false;
ENV.APP.rootElement = '#ember-testing';
ENV.APP.autoboot = false;
}
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;
-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';
const EmberApp = require('ember-cli/lib/broccoli/ember-app');
/*jshint node:true*/
/* global require, module */
var EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
let app = new EmberApp(defaults, {
// sassOptions: {
// includePaths: [
// 'node_modules/bourbon/app/assets/stylesheets'
// ]
// },
sourcemaps: {
enabled: true,
extensions: ['js']
var app = new EmberApp(defaults, {
// Add options here
sassOptions: {
includePaths: [
'bower_components/bourbon/app/assets/stylesheets',
'bower_components/neat/app/assets/stylesheets'
]
}
});
-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",
"version": "1.1.1",
"private": true,
"description": "Contribution dashboard of the Kosmos project",
"repository": "https://github.com/67P/kredits-web",
"version": "0.0.0",
"description": "Small description for kredits-web goes here",
"license": "MIT",
"author": "Kosmos Contributors <mail@kosmos.org>",
"author": "",
"directories": {
"doc": "doc",
"test": "tests"
},
"repository": "",
"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-prod": "rm -rf release/* && ember build -prod --output-path release",
"preversion": "npm test",
"version": "npm run build-prod && git add release/",
"deploy": "git push 5apps master"
"start": "ember server",
"test": "ember test"
},
"devDependencies": {
"@ember/jquery": "^0.5.2",
"@ember/optional-features": "^0.6.3",
"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",
"broccoli-asset-rev": "^2.4.5",
"ember-ajax": "^2.4.1",
"ember-browserify": "^1.1.13",
"ember-cli": "~3.8.1",
"ember-cli-app-version": "^3.2.0",
"ember-cli-babel": "^7.1.2",
"ember-cli-chart": "^3.4.0",
"ember-cli-dependency-checker": "^3.1.0",
"ember-cli-eslint": "^4.2.3",
"ember-cli-htmlbars": "^3.0.0",
"ember-cli-htmlbars-inline-precompile": "^1.0.3",
"ember-cli-inject-live-reload": "^1.8.2",
"ember-cli-sass": "^7.2.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-template-lint": "^1.0.0-beta.1",
"ember-cli-uglify": "^2.1.0",
"ember-cli-update": "^0.21.2",
"ember-export-application-global": "^2.0.0",
"ember-flatpickr": "^2.14.0",
"ember-load-initializers": "^1.1.0",
"ember-macro-helpers": "0.17.0",
"ember-maybe-import-regenerator": "^0.1.6",
"ember-promise-helpers": "1.0.6",
"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"
"ember-cli": "2.10.0",
"ember-cli-app-version": "^2.0.0",
"ember-cli-babel": "^5.1.7",
"ember-cli-dependency-checker": "^1.3.0",
"ember-cli-htmlbars": "^1.0.10",
"ember-cli-htmlbars-inline-precompile": "^0.3.3",
"ember-cli-inject-live-reload": "^1.4.1",
"ember-cli-jshint": "^2.0.1",
"ember-cli-qunit": "^3.0.1",
"ember-cli-release": "^0.2.9",
"ember-cli-sass": "6.1.1",
"ember-cli-sri": "^2.1.0",
"ember-cli-test-loader": "^1.1.0",
"ember-cli-uglify": "^1.2.0",
"ember-export-application-global": "^1.0.5",
"ember-load-initializers": "^0.5.1",
"ember-resolver": "^2.0.3",
"loader.js": "^4.0.10",
"web3": "^0.18.2",
"kredits-contracts": "67P/kredits-contracts"
},
"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>
@@ -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:"U4IJj1aB",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,["name"]],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"]],"special"],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.1+3d20bce5"})
//# sourceMappingURL=kredits-web-1e5bc32bd8740d3a09726b1832ae7bb3.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
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.1%2B3d20bce5%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-52d5f6bf94bb7c55a57f040633eff664.js" integrity="sha256-m3mYiYmoFPuiuPbo3QDH4RMxQVt991VZsVPFlGrNGyE= sha512-DnE+rQP6eeEFZc6McUzK6B0tU3kP0MuTp7Zqz6zxlaZmxpeNLYOcyR0L5q3R8gxxrQPu0MBvXsMrYQ3ogC3L5Q==" ></script>
<script src="/assets/kredits-web-0b61f6b8d49ba0d083a77eb2d2cf77aa.js" integrity="sha256-w4JAVavDPeI40BiCp8gRmuRS6hwBYTmuor0DBOpawqE= sha512-YqDPQM5vn1y1pz45CYu4bgT2Jmle7DQfY2zo62McS53RzQoufxcWEmZxbYc75U5w1CgX59i/qhyu23Zeaa2KOg==" ></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 = {
test_page: 'tests/index.html?hidepassed',
disable_watching: true,
launch_in_ci: [
'Chrome'
"framework": "qunit",
"test_page": "tests/index.html?hidepassed",
"disable_watching": true,
"launch_in_ci": [
"PhantomJS"
],
launch_in_dev: [
'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)
}
}
"launch_in_dev": [
"PhantomJS",
"Chrome"
]
};
+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