From 33e81a766803bbeff87bbbb71f14529923cda565 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Mon, 5 Jun 2017 21:58:46 +0200 Subject: [PATCH 01/23] Store proper contributor profile in IPFS --- app/components/add-contributor/component.js | 74 ++++++++++++--------- app/components/add-contributor/template.hbs | 60 ++++++++++++----- app/models/contributor.js | 47 ++++++++++--- app/routes/index.js | 4 +- app/services/kredits.js | 15 ++--- app/templates/index.hbs | 4 +- config/environment.js | 1 + package.json | 2 + tests/unit/models/contributor-test.js | 19 +++++- 9 files changed, 154 insertions(+), 72 deletions(-) diff --git a/app/components/add-contributor/component.js b/app/components/add-contributor/component.js index 75398c2..cd2bdca 100644 --- a/app/components/add-contributor/component.js +++ b/app/components/add-contributor/component.js @@ -1,41 +1,58 @@ import Ember from 'ember'; +import Contributor from 'kredits-web/models/contributor'; -export default Ember.Component.extend({ +const { + Component, + isPresent, + inject: { + service + }, + computed +} = Ember; - id: null, - realName: null, - address: null, - ipfsHash: null, - isCore: false, +export default Component.extend({ + kredits: service(), + + newContributor: null, inProgress: false, - isValidId: function() { - return Ember.isPresent(this.get('id')); - }.property('id'), - - isValidRealName: function() { - return Ember.isPresent(this.get('realName')); - }.property('realName'), - isValidAddress: function() { - return this.get('kredits.web3Instance').isAddress(this.get('address')); - }.property('address'), + return this.get('kredits.web3Instance') + .isAddress(this.get('newContributor.address')); + }.property('newContributor.address'), - isValid: function() { - return this.get('isValidId') && this.get('isValidRealName') && this.get('isValidAddress'); - }.property('isValidAddress', 'isValidId', 'isValidRealName'), + isValidName: function() { + return isPresent(this.get('newContributor.name')); + }.property('newContributor.name'), + + isValidURL: function() { + return isPresent(this.get('newContributor.url')); + }.property('newContributor.name'), + + isValidGithubUID: function() { + return isPresent(this.get('newContributor.github_uid')); + }.property('newContributor.github_uid'), + + isValidGithubUsername: function() { + return isPresent(this.get('newContributor.github_username')); + }.property('newContributor.github_username'), + + isValidWikiUsername: function() { + return isPresent(this.get('newContributor.wiki_username')); + }.property('newContributor.wiki_username'), + + isValid: computed.and( + 'isValidAddress', + 'isValidName', + 'isValidGithubUID' + ), reset: function() { this.setProperties({ - id: null, - realName: null, - address: null, - ipfsHash: null, - isCore: true, + newContributor: Contributor.create({ kind: 'person' }), inProgress: false }); - }, actions: { @@ -49,12 +66,7 @@ export default Ember.Component.extend({ if (this.get('isValid')) { this.set('inProgress', true); - this.get('kredits').addContributor( - this.get('address'), - this.get('realName'), - this.get('isCore'), - this.get('id') - ).then(contributor => { + this.get('kredits').addContributor(this.get('newContributor')).then(contributor => { this.reset(); this.get('contributors').pushObject(contributor); window.scroll(0,0); diff --git a/app/components/add-contributor/template.hbs b/app/components/add-contributor/template.hbs index 076156e..397e8dc 100644 --- a/app/components/add-contributor/template.hbs +++ b/app/components/add-contributor/template.hbs @@ -1,31 +1,59 @@
+ newContributor: {{newContributor.kredits}}

- {{input type="checkbox" name="is-core" id="is-core" checked=isCore}} + {{input type="checkbox" name="is-core" id="is-core" checked=newContributor.isCore}}

-

- {{input name="id" - type="text" - placeholder="GitHub UID (123)" - value=id - class=(if isValidId 'valid' '')}} -

-

- {{input name="realname" - type="text" - placeholder="GitHub username" - value=realName - class=(if isValidRealName 'valid' '')}} -

{{input name="address" type="text" placeholder="0xF18E631Ea191aE4ebE70046Fcb01a436554421BA4" - value=address + value=newContributor.address class=(if isValidAddress 'valid' '')}}

+

+ +

+

+ {{input name="name" + type="text" + placeholder="Name" + value=newContributor.name + class=(if isValidName 'valid' '')}} +

+

+ {{input name="url" + type="text" + placeholder="URL" + value=newContributor.url + class=(if isValidURL 'valid' '')}} +

+

+ {{input name="github_uid" + type="text" + placeholder="GitHub UID (123)" + value=newContributor.github_uid + class=(if isValidGithubUID 'valid' '')}} +

+

+ {{input name="github_username" + type="text" + placeholder="GitHub username" + value=newContributor.github_username + class=(if isValidGithubUsername 'valid' '')}} +

+

+ {{input name="wiki_username" + type="text" + placeholder="Wiki Username" + value=newContributor.wiki_username + class=(if isValidWikiUsername 'valid' '')}} +

{{input type="submit" value=(if inProgress 'Processing' 'Save') disabled=inProgress}}

diff --git a/app/models/contributor.js b/app/models/contributor.js index 386d757..fcb859d 100644 --- a/app/models/contributor.js +++ b/app/models/contributor.js @@ -3,8 +3,12 @@ import Ember from 'ember'; export default Ember.Object.extend({ address: null, + name: null, + kind: null, + url: null, github_username: null, github_uid: null, + wiki_username: null, ipfsHash: null, kredits: null, isCore: false, @@ -14,18 +18,39 @@ export default Ember.Object.extend({ return `https\:\/\/avatars2.githubusercontent.com/u/${this.get('github_uid')}?v=3&s=128`; }.property('github_uid'), + toJSON() { + let contributor = { + "@context": "https://schema.kosmos.org", + "@type": "Contributor", + "kind": this.get('kind'), + "name": this.get('name'), + "accounts": [] + }; + + if (Ember.isPresent(this.get('url'))) { + contributor["url"] = this.get('url'); + } + if (Ember.isPresent(this.get('github_uid'))) { + contributor.accounts.push({ + "site": "github.com", + "uid": this.get('github_uid'), + "username": this.get('github_username'), + "url": `https://github.com/${this.get('github_username')}` + }); + } + if (Ember.isPresent(this.get('wiki_username'))) { + contributor.accounts.push({ + "site": "wiki.kosmos.org", + "username": this.get('wiki_username'), + "url": `https://wiki.kosmos.org/User:${this.get('wiki_username')}` + }); + } + + return contributor; + }, + serialize() { - return JSON.stringify({ - profiles: { - 'github.com': { - uid: this.get('github_uid'), - username: this.get('github_username'), - } - // 'wiki.kosmos.org': { - // username: this.get('wiki_username') - // } - } - }); + return JSON.stringify(this.toJSON()); } }); diff --git a/app/routes/index.js b/app/routes/index.js index ada98a1..b60d8d5 100644 --- a/app/routes/index.js +++ b/app/routes/index.js @@ -1,4 +1,5 @@ import Ember from 'ember'; +import Contributor from 'kredits-web/models/contributor'; export default Ember.Route.extend({ @@ -10,7 +11,8 @@ export default Ember.Route.extend({ return Ember.RSVP.hash({ contributors: kredits.getContributors(), totalSupply: kredits.getValueFromContract('tokenContract', 'totalSupply'), - proposals: kredits.getProposals() + proposals: kredits.getProposals(), + newContributor: Contributor.create({ kind: 'person' }) }); } diff --git a/app/services/kredits.js b/app/services/kredits.js index a44da20..aca0665 100644 --- a/app/services/kredits.js +++ b/app/services/kredits.js @@ -175,23 +175,18 @@ export default Service.extend({ }); }, - addContributor(address, name, isCore, id) { - Ember.Logger.debug('[kredits] add contributor', name, address); + addContributor(contributor) { + Ember.Logger.debug('[kredits] add contributor', contributor); - let contributor = Contributor.create({ - address: address, - github_username: name, - github_uid: id, + contributor.setProperties({ kredits: 0, - isCore: isCore, - isCurrentUser: this.get('currentUserAccounts').includes(address) + isCurrentUser: this.get('currentUserAccounts').includes(contributor.address) }); return new Ember.RSVP.Promise((resolve, reject) => { this.get('ipfs').storeFile(contributor.serialize()).then(ipfsHash => { contributor.set('ipfsHash', ipfsHash); - Ember.Logger.debug('ADD', address, name, ipfsHash, isCore, id); - this.get('kreditsContract').addContributor(address, name, ipfsHash, isCore, id, (err, data) => { + this.get('kreditsContract').addContributor(contributor.address, contributor.name, contributor.ipfsHash, contributor.isCore, contributor.github_uid, (err, data) => { if (err) { reject(err); return; } Ember.Logger.debug('[kredits] add contributor response', data); resolve(contributor); diff --git a/app/templates/index.hbs b/app/templates/index.hbs index 656d766..23f9a8a 100644 --- a/app/templates/index.hbs +++ b/app/templates/index.hbs @@ -54,8 +54,8 @@
- {{add-contributor kredits=kredits - contributors=model.contributors + {{add-contributor contributors=model.contributors + newContributor=model.newContributor contractInteractionEnabled=contractInteractionEnabled}}
diff --git a/config/environment.js b/config/environment.js index b1278ca..1e673a5 100644 --- a/config/environment.js +++ b/config/environment.js @@ -23,6 +23,7 @@ module.exports = function(environment) { }, browserify: { + tests: true, transform: [ ["babelify", { presets: ["es2015"], diff --git a/package.json b/package.json index 87c5cf3..ee0112c 100644 --- a/package.json +++ b/package.json @@ -55,8 +55,10 @@ "ember-resolver": "^2.0.3", "ember-truth-helpers": "1.3.0", "ipfs-api": "^12.1.7", + "kosmos-schemas": "~1.1.0", "kredits-contracts": "^2.4.0", "loader.js": "^4.0.10", + "tv4": "^1.3.0", "web3": "^0.18.2" }, "engines": { diff --git a/tests/unit/models/contributor-test.js b/tests/unit/models/contributor-test.js index 2a7dbe4..39651f1 100644 --- a/tests/unit/models/contributor-test.js +++ b/tests/unit/models/contributor-test.js @@ -1,9 +1,26 @@ import { moduleFor, test } from 'ember-qunit'; +import schemas from 'npm:kosmos-schemas'; +import tv4 from 'npm:tv4'; moduleFor('model:contributor', 'Unit | Model | contributor'); -test('avatarURL returns correct URL', function(assert) { +test('#avatarURL() returns correct URL', function(assert) { let model = this.subject(); model.set('github_uid', '318'); + assert.equal(model.get('avatarURL'), 'https://avatars2.githubusercontent.com/u/318?v=3&s=128'); }); + +test('#toJSON() returns a valid JSON-LD representation of the model', function(assert) { + let model = this.subject(); + + model.setProperties({ + name: 'Satoshi Nakamoto', + kind: 'person', + github_uid: 123, + github_username: 'therealsatoshi', + wiki_username: 'Satoshi', + }); + + assert.ok(tv4.validate(model.toJSON(), schemas['contributor'])); +}); From 240d446b9715a8e45a8316d630ceea37cac46197 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Mon, 5 Jun 2017 22:08:13 +0200 Subject: [PATCH 02/23] Remove obsolete output --- app/components/add-contributor/template.hbs | 1 - 1 file changed, 1 deletion(-) diff --git a/app/components/add-contributor/template.hbs b/app/components/add-contributor/template.hbs index 397e8dc..eaa5818 100644 --- a/app/components/add-contributor/template.hbs +++ b/app/components/add-contributor/template.hbs @@ -1,5 +1,4 @@ - newContributor: {{newContributor.kredits}}

{{input type="checkbox" name="is-core" id="is-core" checked=newContributor.isCore}}

+

+ +

{{input type="text" placeholder="100" @@ -15,15 +24,15 @@

{{input type="text" - placeholder="URL" - value=proposal.url - class=(if isValidUrl 'valid' '')}} + placeholder="Description" + value=proposal.description + class=(if isValidDescription 'valid' '')}}

{{input type="text" - placeholder="IPFS Hash" - value=proposal.ipfsHash - class=(if isValidIpfsHash 'valid' '')}} + placeholder="URL (optional)" + value=proposal.url + class=(if isValidUrl 'valid' '')}}

{{input type="submit" value=(if inProgress 'Processing' 'Save') disabled=inProgress}} diff --git a/app/models/proposal.js b/app/models/proposal.js index 1ac4b1c..ea59765 100644 --- a/app/models/proposal.js +++ b/app/models/proposal.js @@ -1,16 +1,69 @@ import Ember from 'ember'; +const { + isPresent, + isEmpty, +} = Ember; + export default Ember.Object.extend({ id: null, creatorAddress: null, recipientAddress: null, recipientName: null, + recipientProfile: null, votesCount: null, votesNeeded: null, amount: null, executed: null, + contribution: null, + kind: null, + description: null, url: null, - ipfsHash: null + details: null, + ipfsHash: null, + + /** + * Creates a JSON-LD object of the contribution, according to + * https://github.com/67P/kosmos-schemas/blob/master/schemas/contribution.json + * + * @method + * @public + */ + contributionToJSON() { + if (isEmpty(this.get('recipientProfile'))) { + throw new Error('IPFS hash for recipient profile missing from proposal object'); + } + if (isEmpty(this.get('kind')) || isEmpty(this.get('description'))) { + throw new Error('Missing one or more required properties: kind, description'); + } + + let contribution = { + "@context": "https://schema.kosmos.org", + "@type": "Contribution", + "contributor": { + "ipfs": this.get('recipientProfile') + }, + "kind": this.get('kind'), + "description": this.get('description'), + "details": {} + }; + + if (isPresent(this.get('url'))) { + contribution["url"] = this.get('url'); + } + + return contribution; + }, + + /** + * Returns the JSON-LD representation of the contribution as a string + * + * @method + * @public + */ + serializeContribution() { + return JSON.stringify(this.contributionToJSON()); + } }); diff --git a/app/routes/proposals/new.js b/app/routes/proposals/new.js index 26b77a5..f5870d9 100644 --- a/app/routes/proposals/new.js +++ b/app/routes/proposals/new.js @@ -18,6 +18,7 @@ export default Route.extend({ recipientAddress: params.recipient, amount: params.amount, url: params.url, + kind: params.kind || 'dev', ipfsHash: params.ipfsHash }); diff --git a/app/services/kredits.js b/app/services/kredits.js index b6014ba..e133093 100644 --- a/app/services/kredits.js +++ b/app/services/kredits.js @@ -102,6 +102,8 @@ export default Service.extend({ this.getValueFromContract('kreditsContract', 'contributorAddresses', i).then(address => { this.getValueFromContract('kreditsContract', 'contributors', address).then(person => { this.getValueFromContract('tokenContract', 'balanceOf', address).then(balance => { + Ember.Logger.debug('[kredits] person', address, person); + let contributor = Contributor.create({ address: address, ipfsHash: person[2], @@ -203,14 +205,15 @@ export default Service.extend({ const { recipientAddress, amount, - url, - ipfsHash - } = proposal.getProperties('recipientAddress', 'amount', 'url', 'ipfsHash'); + url + } = proposal.getProperties('recipientAddress', 'amount', 'url'); - this.get('kreditsContract').addProposal(recipientAddress, amount, url, ipfsHash, (err, data) => { - if (err) { reject(err); return; } - Ember.Logger.debug('[kredits] add proposal response', data); - resolve(); + this.get('ipfs').storeFile(proposal.serializeContribution()).then(ipfsHash => { + this.get('kreditsContract').addProposal(recipientAddress, amount, url, ipfsHash, (err, data) => { + if (err) { reject(err); return; } + Ember.Logger.debug('[kredits] add proposal response', data); + resolve(); + }); }); }); }, diff --git a/tests/unit/models/proposal-test.js b/tests/unit/models/proposal-test.js index d91008f..023708b 100644 --- a/tests/unit/models/proposal-test.js +++ b/tests/unit/models/proposal-test.js @@ -1,9 +1,49 @@ import { moduleFor, test } from 'ember-qunit'; +import schemas from 'npm:kosmos-schemas'; +import tv4 from 'npm:tv4'; moduleFor('model:proposal', 'Unit | Model | proposal'); -test('it exists', function(assert) { +test('#toJSON() requires a recipient profile IPFS hash to be set', function(assert) { let model = this.subject(); - // let store = this.store(); - assert.ok(!!model); + + model.setProperties({ + recipientAddress: '0xd4a64570b12da659ee4bbd41c3509b7b1f9c51ac' + }); + + try { + let json = model.contributionToJSON(); + assert.notOk(json, true); + } catch(e) { + assert.ok(e.message.match(/IPFS hash .* missing/i)); + } +}); + +test('#toJSON() requires kind and description to be set', function(assert) { + let model = this.subject(); + + model.setProperties({ + recipientProfile: 'QmT2A7rY4e7uoKktkcFHQNN7BD1oXdZTgd8wNkr1u9nNVE' + }); + + try { + let json = model.contributionToJSON(); + assert.notOk(json, true); + } catch(e) { + assert.ok(e.message.match(/Missing .* kind.*description/i)); + } +}); + +test('#toJSON() returns a valid JSON-LD representation of the model', function(assert) { + let model = this.subject(); + + model.setProperties({ + recipientAddress: '0xd4a64570b12da659ee4bbd41c3509b7b1f9c51ac', + kind: 'design', + description: 'New logo design', + url: 'http://opensourcedesign.org', + recipientProfile: 'QmT2A7rY4e7uoKktkcFHQNN7BD1oXdZTgd8wNkr1u9nNVE' + }); + + assert.ok(tv4.validate(model.contributionToJSON(), schemas['contribution'])); }); From a918719b8f1474bee4dc3539ff7ddb9d0d02b04c Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Wed, 7 Jun 2017 10:35:36 +0200 Subject: [PATCH 12/23] Decrease overall UI size a bit --- app/styles/app.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/styles/app.scss b/app/styles/app.scss index d8f2e8a..bac84aa 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -23,7 +23,7 @@ body { background-repeat: none; background-attachment: fixed; font-family: $font-family-sans; - font-size: 16px; + font-size: 14px; font-weight: 300; color: #fff; } From 1f41dbcae58ce8b489705795b80407a2126d2627 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Wed, 7 Jun 2017 10:35:57 +0200 Subject: [PATCH 13/23] Load contribution details from IPFS --- app/models/proposal.js | 33 +++++++++++++++++++++++++++++++++ app/services/kredits.js | 12 ++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/app/models/proposal.js b/app/models/proposal.js index ea59765..6d01d27 100644 --- a/app/models/proposal.js +++ b/app/models/proposal.js @@ -23,6 +23,39 @@ export default Ember.Object.extend({ details: null, ipfsHash: null, + /** + * Loads the contribution details from IPFS and sets local instance + * properties from it + * + * @method + * @public + */ + loadContribution(ipfs) { + let promise = new Ember.RSVP.Promise((resolve, reject) => { + ipfs.getFile(this.get('ipfsHash')).then(content => { + let contributionJSON = JSON.parse(content); + let contribution = Ember.Object.create(contributionJSON); + + this.setProperties({ + kind: contribution.get('kind'), + description: contribution.get('description'), + url: contribution.get('url') + }); + + // TODO load details + // let details = profile.get('accounts'); + + Ember.Logger.debug('[proposal] loaded contribution details', contributionJSON); + resolve(); + }).catch((err) => { + Ember.Logger.error('[proposal] error trying to load contribution details', this.get('ipfsHash'), err); + reject(err); + }); + }); + + return promise; + }, + /** * Creates a JSON-LD object of the contribution, according to * https://github.com/67P/kosmos-schemas/blob/master/schemas/contribution.json diff --git a/app/services/kredits.js b/app/services/kredits.js index e133093..7a844f2 100644 --- a/app/services/kredits.js +++ b/app/services/kredits.js @@ -148,8 +148,16 @@ export default Service.extend({ url : p[6], ipfsHash : p[7] }); - Ember.Logger.debug('[kredits] proposal', proposal); - resolve(proposal); + + if (proposal.get('ipfsHash')) { + proposal.loadContribution(this.get('ipfs')).then( + () => resolve(proposal), + err => reject(err) + ); + } else { + Ember.Logger.warn('[kredits] proposal from blockchain is missing IPFS hash', proposal); + resolve(proposal); + } }).catch(err => reject(err)); }); return promise; From c98a50cd4297884db84ad9a3255699137a9c9e60 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Wed, 7 Jun 2017 11:11:01 +0200 Subject: [PATCH 14/23] Fix mobile layout Unfortunately also breaks the animation when opening contributor details for now. Couldn't get it to work again. --- app/components/contributor-list/template.hbs | 10 ++--- app/components/proposal-list/template.hbs | 3 +- app/styles/components/_contributor-list.scss | 46 +++++++------------- app/styles/components/_proposal-list.scss | 2 +- 4 files changed, 22 insertions(+), 39 deletions(-) diff --git a/app/components/contributor-list/template.hbs b/app/components/contributor-list/template.hbs index 6d6f80f..86062ac 100644 --- a/app/components/contributor-list/template.hbs +++ b/app/components/contributor-list/template.hbs @@ -12,14 +12,12 @@ -

-
Ethereum address
-
{{contributor.address}}
+
+ {{/each}} diff --git a/app/components/proposal-list/template.hbs b/app/components/proposal-list/template.hbs index 0418dfb..a41518f 100644 --- a/app/components/proposal-list/template.hbs +++ b/app/components/proposal-list/template.hbs @@ -1,9 +1,8 @@ {{#each proposals as |proposal|}}
  • #{{proposal.id}} - Issue{{#if proposal.executed}}d{{/if}} {{proposal.amount}}₭S - to {{proposal.recipientName}} + for {{proposal.recipientName}} ({{proposal.votesCount}}/{{proposal.votesNeeded}} votes) {{#unless proposal.executed}}{{/unless}} diff --git a/app/styles/components/_contributor-list.scss b/app/styles/components/_contributor-list.scss index 63554e9..49e24f9 100644 --- a/app/styles/components/_contributor-list.scss +++ b/app/styles/components/_contributor-list.scss @@ -15,10 +15,10 @@ table.contributor-list { &.metadata { height: 0; + transition: all 0.2s ease-out; td { padding: 0 1.2rem; - transition: all 0.2s ease-out; } a { @@ -28,41 +28,27 @@ table.contributor-list { } } - dl { + ul { + list-style: none; display: block; - width: 100%; - font-size: 1rem; - dt, dd { - display: inline-block; - overflow: hidden; - height: 0; - line-height: 1.6rem; - transition: all 0.2s ease-out; - } - dt { - clear: both; - float: left; - width: 30%; - } - dd { - float: right; - width: 70%; - text-align: right; - } - } + overflow: hidden; + height: 0; + transition: all 0.2s ease-out; - &.visible { - td { - padding: 1rem 1.2rem; - } - - dl { - dt, dd { - height: auto; + li { + display: inline; + &+li { + margin-left: 1rem; } } } + &.visible { + height: auto; + ul { + height: auto; + } + } } td { diff --git a/app/styles/components/_proposal-list.scss b/app/styles/components/_proposal-list.scss index 8c7a1aa..72e231e 100644 --- a/app/styles/components/_proposal-list.scss +++ b/app/styles/components/_proposal-list.scss @@ -32,7 +32,7 @@ ul.proposal-list { .votes { font-size: 1rem; color: lightblue; - padding-left: 1rem; + padding-left: 0.5rem; } button { From 33072900e95fd1564e2a8d8b343c44ab6c9fc144 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Wed, 7 Jun 2017 12:45:30 +0200 Subject: [PATCH 15/23] Use contributor's display name for proposal list --- app/controllers/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/index.js b/app/controllers/index.js index 2c85b02..ed7c0c5 100644 --- a/app/controllers/index.js +++ b/app/controllers/index.js @@ -23,7 +23,7 @@ export default Ember.Controller.extend({ let proposals = this.get('model.proposals') .filterBy('executed', false) .map(p => { - p.set('recipientName', this.findContributorByAddress(p.get('recipientAddress')).github_username); + p.set('recipientName', this.findContributorByAddress(p.get('recipientAddress')).name); return p; }); return proposals; @@ -33,7 +33,7 @@ export default Ember.Controller.extend({ let proposals = this.get('model.proposals') .filterBy('executed', true) .map(p => { - p.set('recipientName', this.findContributorByAddress(p.get('recipientAddress')).github_username); + p.set('recipientName', this.findContributorByAddress(p.get('recipientAddress')).name); return p; }); return proposals; From cbb15f4d6f61534f3eff6e86da35c3315ddcdc91 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Wed, 7 Jun 2017 12:46:03 +0200 Subject: [PATCH 16/23] Fix mobile layout, add contribution kind to props --- app/components/proposal-list/template.hbs | 4 ++-- app/styles/_colors.scss | 8 ++++++++ app/styles/app.scss | 11 ++++++----- app/styles/components/_add-contributor.scss | 2 +- app/styles/components/_contributor-list.scss | 2 +- app/styles/components/_loading-spinner.scss | 4 ++-- app/styles/components/_proposal-list.scss | 11 ++++++++--- 7 files changed, 28 insertions(+), 14 deletions(-) create mode 100644 app/styles/_colors.scss diff --git a/app/components/proposal-list/template.hbs b/app/components/proposal-list/template.hbs index a41518f..ba22f18 100644 --- a/app/components/proposal-list/template.hbs +++ b/app/components/proposal-list/template.hbs @@ -1,6 +1,6 @@ {{#each proposals as |proposal|}} -
  • - #{{proposal.id}} +
  • + {{proposal.amount}}₭S for {{proposal.recipientName}} ({{proposal.votesCount}}/{{proposal.votesNeeded}} votes) diff --git a/app/styles/_colors.scss b/app/styles/_colors.scss new file mode 100644 index 0000000..9578f1d --- /dev/null +++ b/app/styles/_colors.scss @@ -0,0 +1,8 @@ +$blue: #68d7fb; +$purple: #8f68fb; +$pink: #e068fb; +$green: #97fb68; +$yellow: #fbe468; +$red: #fb6868; + +$primaryColor: $blue; diff --git a/app/styles/app.scss b/app/styles/app.scss index bac84aa..afca809 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -15,6 +15,7 @@ @import "neat"; @import "settings/breakpoints"; @import "layout"; +@import "colors"; $font-family-sans: 'Open Sans', sans-serif; @@ -43,7 +44,7 @@ h1, h2, h3, h4, h5, input, button { section { h2 { font-size: 2.8rem; - color: lightblue; + color: $primaryColor; @include media($mobile) { font-size: 2rem; } @@ -54,7 +55,7 @@ section { p.stats { padding-top: 3rem; font-size: 1rem; - color: lightblue; + color: white; text-align: center; span.number { font-weight: 600; @@ -70,14 +71,14 @@ section { .actions { padding-top: 3rem; font-size: 1rem; - color: lightblue; + color: $primaryColor; text-align: center; @include media($mobile) { padding-top: 2rem; } a { - color: lightblue; + color: $primaryColor; } } } @@ -87,7 +88,7 @@ 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; + color: $primaryColor; border-radius: 3px; font-weight: 500; text-transform: uppercase; diff --git a/app/styles/components/_add-contributor.scss b/app/styles/components/_add-contributor.scss index 6e5fe5a..379b91e 100644 --- a/app/styles/components/_add-contributor.scss +++ b/app/styles/components/_add-contributor.scss @@ -9,7 +9,7 @@ section#add-contributor, section#add-proposal { padding-top: 1rem; text-align: center; a { - color: lightblue; + color: $primaryColor; margin-left: 1rem; } } diff --git a/app/styles/components/_contributor-list.scss b/app/styles/components/_contributor-list.scss index 49e24f9..4e9158f 100644 --- a/app/styles/components/_contributor-list.scss +++ b/app/styles/components/_contributor-list.scss @@ -22,7 +22,7 @@ table.contributor-list { } a { - color: lightblue; + color: $primaryColor; &:hover, &:active { color: #fff; } diff --git a/app/styles/components/_loading-spinner.scss b/app/styles/components/_loading-spinner.scss index 17ed468..6ba4057 100644 --- a/app/styles/components/_loading-spinner.scss +++ b/app/styles/components/_loading-spinner.scss @@ -11,7 +11,7 @@ margin-top: 12rem; text-align: center; font-size: 1.4rem; - color: lightblue; + color: $primaryColor; @include media($mobile) { margin-top: 6rem; @@ -23,7 +23,7 @@ margin-bottom: 2rem; #path-comet { - fill: lightblue; + fill: $primaryColor; opacity: 0.1; animation-name: pulse; diff --git a/app/styles/components/_proposal-list.scss b/app/styles/components/_proposal-list.scss index 72e231e..a35f17c 100644 --- a/app/styles/components/_proposal-list.scss +++ b/app/styles/components/_proposal-list.scss @@ -14,9 +14,14 @@ ul.proposal-list { border-top: 1px solid rgba(255,255,255,0.2); } - .id { - color: lightblue; + .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; @@ -31,7 +36,7 @@ ul.proposal-list { } .votes { font-size: 1rem; - color: lightblue; + color: $primaryColor; padding-left: 0.5rem; } From 2011636173fb4b69fc9b0f93a6f56becce4866a3 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Wed, 7 Jun 2017 13:01:35 +0200 Subject: [PATCH 17/23] Add contribution details as title --- app/components/proposal-list/template.hbs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/components/proposal-list/template.hbs b/app/components/proposal-list/template.hbs index ba22f18..f346830 100644 --- a/app/components/proposal-list/template.hbs +++ b/app/components/proposal-list/template.hbs @@ -1,8 +1,8 @@ {{#each proposals as |proposal|}} -
  • +
  • {{proposal.amount}}₭S - for {{proposal.recipientName}} + for {{proposal.recipientName}} ({{proposal.votesCount}}/{{proposal.votesNeeded}} votes) {{#unless proposal.executed}}{{/unless}} From 3571cc633eb9a87cfed9d68bb5d34695f7642666 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 8 Jun 2017 16:41:03 +0200 Subject: [PATCH 18/23] Improve computed-property dependency --- app/components/add-contributor/component.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/components/add-contributor/component.js b/app/components/add-contributor/component.js index cd2bdca..95ee3be 100644 --- a/app/components/add-contributor/component.js +++ b/app/components/add-contributor/component.js @@ -18,9 +18,9 @@ export default Component.extend({ inProgress: false, isValidAddress: function() { - return this.get('kredits.web3Instance') + return this.get('kredits.web3') .isAddress(this.get('newContributor.address')); - }.property('newContributor.address'), + }.property('kredits.web3', 'newContributor.address'), isValidName: function() { return isPresent(this.get('newContributor.name')); From 7f2f781a770551224e2e08f2946212c95dc0f02b Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 8 Jun 2017 16:41:53 +0200 Subject: [PATCH 19/23] Don't try to save proposal when invalid --- app/components/add-proposal/component.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/components/add-proposal/component.js b/app/components/add-proposal/component.js index 06605f1..ec59433 100644 --- a/app/components/add-proposal/component.js +++ b/app/components/add-proposal/component.js @@ -41,6 +41,7 @@ export default Component.extend({ save() { if (! this.get('isValid')) { alert('Invalid data. Please review and try again.'); + return false; } this.set('inProgress', true); let proposal = this.get('proposal'); From 99e921c302f1b190ebd449a8bcad090a07e27fc6 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 8 Jun 2017 16:42:16 +0200 Subject: [PATCH 20/23] Throw error when file couldn't be fetched from IPFS --- app/services/ipfs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/ipfs.js b/app/services/ipfs.js index 6ef5a33..df41fb7 100644 --- a/app/services/ipfs.js +++ b/app/services/ipfs.js @@ -28,7 +28,7 @@ export default Ember.Service.extend({ return res.toString(); }, err => { Ember.Logger.error('[ipfs] error trying to fetch file', hash, err); - return err; + throw err; }); } From 6263254a1b945e7208f5ea6df9b20f71f5449225 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 8 Jun 2017 16:53:40 +0200 Subject: [PATCH 21/23] Specify radix parameter for parsing amount --- app/components/add-proposal/component.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/add-proposal/component.js b/app/components/add-proposal/component.js index ec59433..8abf03c 100644 --- a/app/components/add-proposal/component.js +++ b/app/components/add-proposal/component.js @@ -22,7 +22,7 @@ export default Component.extend({ }), isValidAmount: computed('proposal.amount', function() { - return parseInt(this.get('proposal.amount')) > 0; + return parseInt(this.get('proposal.amount'), 10) > 0; }), isValidUrl: computed('proposal.url', function() { From 918ae5b2d143fdfb61177d1bb4a3885e140f1b5d Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 8 Jun 2017 17:06:19 +0200 Subject: [PATCH 22/23] Fix property dep --- app/components/add-contributor/component.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/add-contributor/component.js b/app/components/add-contributor/component.js index 95ee3be..6aee5b6 100644 --- a/app/components/add-contributor/component.js +++ b/app/components/add-contributor/component.js @@ -28,7 +28,7 @@ export default Component.extend({ isValidURL: function() { return isPresent(this.get('newContributor.url')); - }.property('newContributor.name'), + }.property('newContributor.url'), isValidGithubUID: function() { return isPresent(this.get('newContributor.github_uid')); From 510f7de6934ef51b5dd8b663174df3fada3af74d Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 8 Jun 2017 23:56:43 +0200 Subject: [PATCH 23/23] Use HTTPS for production IPFS --- config/environment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/environment.js b/config/environment.js index 1e673a5..74323b9 100644 --- a/config/environment.js +++ b/config/environment.js @@ -39,7 +39,7 @@ module.exports = function(environment) { ipfs: { host: 'ipfs.kosmos.org', port: '5444', - protocol: 'http' + protocol: 'https' } };