Merge pull request #155 from 67P/feature/resubmit_vetoed_contribution

Re-submit vetoed contributions
This commit was merged in pull request #155.
This commit is contained in:
2019-09-10 16:53:36 +02:00
committed by GitHub
16 changed files with 306 additions and 32 deletions
+12 -9
View File
@@ -1,6 +1,7 @@
import Component from '@ember/component';
import { computed } from '@ember/object';
import { and, notEmpty } from '@ember/object/computed';
import { isEmpty } from '@ember/utils';
import moment from 'moment';
export default Component.extend({
@@ -25,14 +26,17 @@ export default Component.extend({
this.set('defaultDate', moment().startOf('hour').toDate());
// Default attributes used by reset
this.set('attributes', {
contributorId: null,
kind: null,
date: this.defaultDate,
amount: null,
description: null,
url: null,
});
if (isEmpty(this.attributes)) {
this.set('attributes', {
contributorId: null,
kind: null,
date: this.defaultDate,
amount: null,
description: null,
url: null,
details: null
});
}
this.reset();
},
@@ -67,7 +71,6 @@ export default Component.extend({
window.alert('Something went wrong. Check the browser console for details.');
})
.finally(() => this.set('inProgress', false));
}
}
@@ -63,6 +63,17 @@
</p>
</label>
{{#if details}}
<label>
<p class="label">Details:</p>
<p>
<pre>
{{details}}
</pre>
</p>
</label>
{{/if}}
<p class="actions">
{{input type="submit"
disabled=inProgress
+5
View File
@@ -0,0 +1,5 @@
import Component from '@ember/component';
export default Component.extend({
tagName: ""
});
+15
View File
@@ -0,0 +1,15 @@
<svg width="60px" height="60px" version="1.1" viewBox="0 0 60 60" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<g fill="none" fill-rule="evenodd">
<g transform="translate(-479,-238)" stroke="#fbe468" stroke-linecap="round" stroke-linejoin="round" stroke-width="1">
<g transform="translate(482,244)">
<a transform="translate(0,2)">
<polygon id="Triangle-58" points="0.15321 44 27 0 53.847 44"/>
</a>
<rect x="25" y="13" width="4" height="21"/>
<a transform="translate(0,2)">
<circle cx="27" cy="38" r="2"/>
</a>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 750 B

@@ -0,0 +1,7 @@
import ContributionsNewController from 'kredits-web/controllers/contributions/new';
export default ContributionsNewController.extend({
attributes: null,
});
@@ -0,0 +1,12 @@
import Controller from '@ember/controller';
import { computed } from '@ember/object';
import config from 'kredits-web/config/environment';
export default Controller.extend({
ipfsGatewayUrl: computed(function() {
return config.ipfs.gatewayUrl;
}).volatile()
});
+7 -1
View File
@@ -1,5 +1,7 @@
import EmberObject, { computed } from '@ember/object';
import { isEmpty } from '@ember/utils';
import bignumber from 'kredits-web/utils/cps/bignumber';
import moment from 'moment';
export default EmberObject.extend({
@@ -24,11 +26,15 @@ export default EmberObject.extend({
init () {
this._super(...arguments);
this.set('details', {});
if (isEmpty(this.details)) this.set('details', {});
},
iso8601Date: computed('date', 'time', function() {
return this.time ? `${this.date}T${this.time}` : this.date;
}),
jsDate: computed('iso8601Date', function() {
return moment(this.iso8601Date).toDate();
})
});
+1
View File
@@ -21,6 +21,7 @@ Router.map(function() {
});
this.route('contributions', function() {
this.route('new');
this.route('resubmit', { path: ':id/resubmit' });
});
this.route('contributors', function() {
this.route('new');
+25
View File
@@ -0,0 +1,25 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default Route.extend({
kredits: service(),
model(params) {
const contribution = this.kredits.contributions.findBy('id', parseInt(params.id));
contribution.contributorId = contribution.contributorId.toString();
return contribution;
},
setupController (controller, model) {
this._super(controller, model);
controller.set('attributes', model.getProperties([
'kind', 'amount', 'description', 'url', 'details'
]));
controller.set('attributes.contributorId', model.contributorId.toString());
controller.set('attributes.date', model.jsDate);
}
});
+41 -19
View File
@@ -225,33 +225,36 @@ export default Service.extend({
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);
//
// TODO Implement proposals with voting
//
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);
});
},
// 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);
});
});
},
// 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}})
@@ -311,6 +314,7 @@ export default Service.extend({
.on('ContributorAdded', this.handleContributorChange.bind(this))
this.kredits.Contribution
.on('ContributionAdded', this.handleContributionAdded.bind(this))
.on('ContributionVetoed', this.handleContributionVetoed.bind(this))
this.kredits.Proposal
@@ -338,6 +342,24 @@ export default Service.extend({
this.contributors.pushObject(newContributor);
},
async handleContributionAdded (id, contributorId, amount) {
console.debug('[kredits] ContributionAdded event received', { id, contributorId, amount });
const pendingContribution = this.contributions.find(c => {
return (c.id === null) &&
(c.contributorId.toString() === contributorId.toString()) &&
(c.amount.toString() === amount.toString());
});
if (pendingContribution) {
const attributes = await this.kredits.Contribution.getById(id);
attributes.contributor = this.contributors.findBy('id', attributes.contributorId.toString());
const newContribution = Contribution.create(attributes);
this.contributions.addObject(newContribution);
this.contributions.removeObject(pendingContribution);
}
},
handleContributionVetoed (contributionId) {
console.debug('[kredits] ContributionVetoed event received for ', contributionId);
const contribution = this.contributions.findBy('id', contributionId);
@@ -41,7 +41,7 @@ section#contribution-details {
}
}
a {
a:not(.button) {
color: $primary-color;
text-decoration: none;
@@ -54,4 +54,35 @@ section#contribution-details {
.actions {
text-align: center;
}
&.vetoed {
.content {
h3 {
text-decoration: line-through;
}
}
}
.hint.vetoed {
overflow: auto;
margin-top: 2rem;
padding-top: 2rem;
border-top: 1px solid rgba(255,255,255,0.2);
font-size: 1.2rem;
.icon {
display: inline-block;
width: 40px;
height: 40px;
float: left;
margin-right: 1rem;
margin-bottom: 1rem;
svg {
width: 100%;
height: auto;
}
}
}
}
+13
View File
@@ -0,0 +1,13 @@
<main class="center-column">
<section id="add-contribution">
<header>
<h2>Re-submit contribution #{{model.id}}</h2>
</header>
<div class="content">
{{add-contribution attributes=attributes contributors=sortedContributors save=(action "save")}}
</div>
</section>
</main>
+16 -2
View File
@@ -1,4 +1,4 @@
<section id="contribution-details">
<section id="contribution-details" class={{if model.vetoed "vetoed"}}>
<header class="with-nav">
<h2>Contribution #{{model.id}}</h2>
<nav>
@@ -32,12 +32,26 @@
</a>
</p>
{{/if}}
{{#if model.vetoed}}
<div class="hint vetoed">
<div class="icon">
{{icon-warning}}
</div>
<p>
This contribution has been vetoed, meaning no
kredits will be issued.
</p>
<p>
{{link-to "Re-submit contribution …" "contributions.resubmit" model class="button small green"}}.
</p>
</div>
{{/if}}
</div>
<div class="actions">
<p>
{{#if model.ipfsHash}}
<a href="https://ipfs.io/ipfs/{{model.ipfsHash}}"
<a href="{{ipfsGatewayUrl}}/{{model.ipfsHash}}"
class="button small" target="_blank" rel="noopener">
Inspect IPFS data
</a>
+27
View File
@@ -0,0 +1,27 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import Contribution from 'kredits-web/models/contribution';
module('Unit | Model | contribution', function(hooks) {
setupTest(hooks);
test('iso8601Date', function(assert) {
const model = Contribution.create({
date: '2019-09-10'
});
assert.equal(model.iso8601Date, '2019-09-10');
model.set('time', '09:33:00.141Z');
assert.equal(model.iso8601Date, '2019-09-10T09:33:00.141Z');
});
test('jsDate', function(assert) {
const model = Contribution.create({
date: '2019-09-10',
time: '09:33:00.141Z'
});
assert.ok(model.jsDate instanceof Date);
assert.equal(model.jsDate.toISOString(), '2019-09-10T09:33:00.141Z');
});
});
@@ -0,0 +1,11 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Route | contributions/resubmit', function(hooks) {
setupTest(hooks);
test('it exists', function(assert) {
let route = this.owner.lookup('route:contributions/resubmit');
assert.ok(route);
});
});
+71
View File
@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
id="svg15"
version="1.1"
viewBox="0 0 60 60"
height="60px"
width="60px">
<metadata
id="metadata19">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Warning</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->
<title
id="title2">Warning</title>
<desc
id="desc4">Created with Sketch.</desc>
<defs
id="defs6" />
<g
style="fill:none;fill-rule:evenodd;stroke:none;stroke-width:1"
sketch:type="MSPage"
id="stroked">
<g
style="stroke:#535353;stroke-width:2;stroke-linecap:round;stroke-linejoin:round"
transform="translate(-479,-238)"
sketch:type="MSLayerGroup"
id="Transport">
<g
sketch:type="MSShapeGroup"
transform="translate(482,244)"
id="Warning">
<a
transform="translate(0,2)"
id="a4529">
<polygon
id="Triangle-58"
points="0.15321248,44 27,0 53.846787,44 " />
</a>
<rect
height="21"
width="4"
y="13"
x="25"
id="Rectangle-1700" />
<a
transform="translate(0,2)"
id="a4532">
<circle
id="Oval-1484"
cx="27"
cy="38"
r="2" />
</a>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB