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:
@@ -1,6 +1,7 @@
|
|||||||
import Component from '@ember/component';
|
import Component from '@ember/component';
|
||||||
import { computed } from '@ember/object';
|
import { computed } from '@ember/object';
|
||||||
import { and, notEmpty } from '@ember/object/computed';
|
import { and, notEmpty } from '@ember/object/computed';
|
||||||
|
import { isEmpty } from '@ember/utils';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
@@ -25,6 +26,7 @@ export default Component.extend({
|
|||||||
this.set('defaultDate', moment().startOf('hour').toDate());
|
this.set('defaultDate', moment().startOf('hour').toDate());
|
||||||
|
|
||||||
// Default attributes used by reset
|
// Default attributes used by reset
|
||||||
|
if (isEmpty(this.attributes)) {
|
||||||
this.set('attributes', {
|
this.set('attributes', {
|
||||||
contributorId: null,
|
contributorId: null,
|
||||||
kind: null,
|
kind: null,
|
||||||
@@ -32,7 +34,9 @@ export default Component.extend({
|
|||||||
amount: null,
|
amount: null,
|
||||||
description: null,
|
description: null,
|
||||||
url: null,
|
url: null,
|
||||||
|
details: null
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.reset();
|
this.reset();
|
||||||
},
|
},
|
||||||
@@ -67,7 +71,6 @@ export default Component.extend({
|
|||||||
window.alert('Something went wrong. Check the browser console for details.');
|
window.alert('Something went wrong. Check the browser console for details.');
|
||||||
})
|
})
|
||||||
.finally(() => this.set('inProgress', false));
|
.finally(() => this.set('inProgress', false));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,17 @@
|
|||||||
</p>
|
</p>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
{{#if details}}
|
||||||
|
<label>
|
||||||
|
<p class="label">Details:</p>
|
||||||
|
<p>
|
||||||
|
<pre>
|
||||||
|
{{details}}
|
||||||
|
</pre>
|
||||||
|
</p>
|
||||||
|
</label>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
<p class="actions">
|
<p class="actions">
|
||||||
{{input type="submit"
|
{{input type="submit"
|
||||||
disabled=inProgress
|
disabled=inProgress
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import Component from '@ember/component';
|
||||||
|
|
||||||
|
export default Component.extend({
|
||||||
|
tagName: ""
|
||||||
|
});
|
||||||
@@ -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()
|
||||||
|
|
||||||
|
});
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import EmberObject, { computed } from '@ember/object';
|
import EmberObject, { computed } from '@ember/object';
|
||||||
|
import { isEmpty } from '@ember/utils';
|
||||||
import bignumber from 'kredits-web/utils/cps/bignumber';
|
import bignumber from 'kredits-web/utils/cps/bignumber';
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
export default EmberObject.extend({
|
export default EmberObject.extend({
|
||||||
|
|
||||||
@@ -24,11 +26,15 @@ export default EmberObject.extend({
|
|||||||
|
|
||||||
init () {
|
init () {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.set('details', {});
|
if (isEmpty(this.details)) this.set('details', {});
|
||||||
},
|
},
|
||||||
|
|
||||||
iso8601Date: computed('date', 'time', function() {
|
iso8601Date: computed('date', 'time', function() {
|
||||||
return this.time ? `${this.date}T${this.time}` : this.date;
|
return this.time ? `${this.date}T${this.time}` : this.date;
|
||||||
|
}),
|
||||||
|
|
||||||
|
jsDate: computed('iso8601Date', function() {
|
||||||
|
return moment(this.iso8601Date).toDate();
|
||||||
})
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ Router.map(function() {
|
|||||||
});
|
});
|
||||||
this.route('contributions', function() {
|
this.route('contributions', function() {
|
||||||
this.route('new');
|
this.route('new');
|
||||||
|
this.route('resubmit', { path: ':id/resubmit' });
|
||||||
});
|
});
|
||||||
this.route('contributors', function() {
|
this.route('contributors', function() {
|
||||||
this.route('new');
|
this.route('new');
|
||||||
|
|||||||
@@ -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
@@ -225,33 +225,36 @@ export default Service.extend({
|
|||||||
console.debug('[kredits] add contribution response', data);
|
console.debug('[kredits] add contribution response', data);
|
||||||
attributes.contributor = this.contributors.findBy('id', attributes.contributorId);
|
attributes.contributor = this.contributors.findBy('id', attributes.contributorId);
|
||||||
const contribution = Contribution.create(attributes);
|
const contribution = Contribution.create(attributes);
|
||||||
// TODO receive from wrapper
|
|
||||||
contribution.set('confirmedAtBlock', data.blockNumber + 40320);
|
contribution.set('confirmedAtBlock', data.blockNumber + 40320);
|
||||||
this.contributions.pushObject(contribution);
|
this.contributions.pushObject(contribution);
|
||||||
return contribution;
|
return contribution;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
addProposal (attributes) {
|
//
|
||||||
console.debug('[kredits] add proposal', attributes);
|
// TODO Implement proposals with voting
|
||||||
|
//
|
||||||
|
|
||||||
return this.kredits.Proposal.addProposal(attributes)
|
// addProposal (attributes) {
|
||||||
.then((data) => {
|
// console.debug('[kredits] add proposal', attributes);
|
||||||
console.debug('[kredits] add proposal response', data);
|
//
|
||||||
attributes.contributor = this.contributors.findBy('id', attributes.contributorId);
|
// return this.kredits.Proposal.addProposal(attributes)
|
||||||
return Proposal.create(attributes);
|
// .then((data) => {
|
||||||
});
|
// console.debug('[kredits] add proposal response', data);
|
||||||
},
|
// attributes.contributor = this.contributors.findBy('id', attributes.contributorId);
|
||||||
|
// return Proposal.create(attributes);
|
||||||
|
// });
|
||||||
|
// },
|
||||||
|
|
||||||
getProposals () {
|
// getProposals () {
|
||||||
return this.kredits.Proposal.all()
|
// return this.kredits.Proposal.all()
|
||||||
.then((proposals) => {
|
// .then(proposals => {
|
||||||
return proposals.map((proposal) => {
|
// return proposals.map(proposal => {
|
||||||
proposal.contributor = this.contributors.findBy('id', proposal.contributorId.toString());
|
// proposal.contributor = this.contributors.findBy('id', proposal.contributorId.toString());
|
||||||
return Proposal.create(proposal);
|
// return Proposal.create(proposal);
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
},
|
// },
|
||||||
|
|
||||||
getContributions () {
|
getContributions () {
|
||||||
return this.kredits.Contribution.all({page: {size: 200}})
|
return this.kredits.Contribution.all({page: {size: 200}})
|
||||||
@@ -311,6 +314,7 @@ export default Service.extend({
|
|||||||
.on('ContributorAdded', this.handleContributorChange.bind(this))
|
.on('ContributorAdded', this.handleContributorChange.bind(this))
|
||||||
|
|
||||||
this.kredits.Contribution
|
this.kredits.Contribution
|
||||||
|
.on('ContributionAdded', this.handleContributionAdded.bind(this))
|
||||||
.on('ContributionVetoed', this.handleContributionVetoed.bind(this))
|
.on('ContributionVetoed', this.handleContributionVetoed.bind(this))
|
||||||
|
|
||||||
this.kredits.Proposal
|
this.kredits.Proposal
|
||||||
@@ -338,6 +342,24 @@ export default Service.extend({
|
|||||||
this.contributors.pushObject(newContributor);
|
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) {
|
handleContributionVetoed (contributionId) {
|
||||||
console.debug('[kredits] ContributionVetoed event received for ', contributionId);
|
console.debug('[kredits] ContributionVetoed event received for ', contributionId);
|
||||||
const contribution = this.contributions.findBy('id', contributionId);
|
const contribution = this.contributions.findBy('id', contributionId);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ section#contribution-details {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a:not(.button) {
|
||||||
color: $primary-color;
|
color: $primary-color;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
|
||||||
@@ -54,4 +54,35 @@ section#contribution-details {
|
|||||||
.actions {
|
.actions {
|
||||||
text-align: center;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<section id="contribution-details">
|
<section id="contribution-details" class={{if model.vetoed "vetoed"}}>
|
||||||
<header class="with-nav">
|
<header class="with-nav">
|
||||||
<h2>Contribution #{{model.id}}</h2>
|
<h2>Contribution #{{model.id}}</h2>
|
||||||
<nav>
|
<nav>
|
||||||
@@ -32,12 +32,26 @@
|
|||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
{{/if}}
|
{{/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>
|
||||||
|
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<p>
|
<p>
|
||||||
{{#if model.ipfsHash}}
|
{{#if model.ipfsHash}}
|
||||||
<a href="https://ipfs.io/ipfs/{{model.ipfsHash}}"
|
<a href="{{ipfsGatewayUrl}}/{{model.ipfsHash}}"
|
||||||
class="button small" target="_blank" rel="noopener">
|
class="button small" target="_blank" rel="noopener">
|
||||||
Inspect IPFS data
|
Inspect IPFS data
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -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
@@ -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 |
Reference in New Issue
Block a user