Compare commits

...

5 Commits

Author SHA1 Message Date
basti c30637ec7e Update dependencies
Fixes batch voting missing from the contracts ABI, plus a whole bunch of
security issues reported by npm.
2018-06-15 10:39:22 +02:00
basti f152fb1382 Clean up form styles a bit, style batch button 2018-06-15 10:38:38 +02:00
fsmanuel 0e66765f1d Reset selectedProposals after confirmation 2018-06-15 09:07:13 +02:00
fsmanuel cb4d20cf81 Implement batch voting 2018-06-15 09:07:13 +02:00
fsmanuel 1945074db6 Create proposal-list/item component 2018-06-15 09:07:13 +02:00
13 changed files with 914 additions and 1478 deletions
+21 -11
View File
@@ -1,20 +1,30 @@
import Component from '@ember/component';
import { inject } from '@ember/service';
import { empty } from '@ember/object/computed';
export default Component.extend({
kredits: inject(),
tagName: 'ul',
classNames: ['proposal-list'],
selectedProposals: [],
submitButtonDisabled: empty('selectedProposals'),
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.');
}
}
}
confirm() {
this.confirmProposals(this.selectedProposals)
.then(() => {
this.selectedProposals = [];
});
},
toggleSelect(proposalId, selected) {
if (selected) {
this.selectedProposals.removeObject(proposalId);
} else {
this.selectedProposals.addObject(proposalId);
}
},
}
});
@@ -0,0 +1,29 @@
import Component from '@ember/component';
import tag from 'ember-awesome-macros/tag';
import { computed } from '@ember/object';
import { reads } from '@ember/object/computed';
import { inject } from '@ember/service';
export default Component.extend({
kredits: inject(),
tagName: 'li',
classNames: ['proposal-list-item'],
attributeBindings: ['data-proposal-id', 'title'],
title: tag`(${'proposal.kind'}) ${'proposal.description'}`,
'data-proposal-id': reads('proposal.id'),
canBeVoted: computed('voterIds.[]', 'kredits.currentUser', function() {
let { isExecuted, voterIds } = this.proposal;
let { currentUser } = this.kredits;
voterIds = voterIds.map((id) => id.toString());
return currentUser.isCore && !isExecuted && !voterIds.includes(currentUser.id);
}),
selected: computed('selectedProposals.[]', function() {
return this.selectedProposals.includes(this.proposal.id);
})
});
@@ -0,0 +1,8 @@
<span class="category {{proposal.kind}}">♥</span>
<span class="amount">{{proposal.amount}}</span><span class="symbol">₭S</span>
for <span class="recipient">{{proposal.contributor.name}}</span>
<span class="votes">({{proposal.votesCount}}/{{proposal.votesNeeded}} votes)</span>
{{#if canBeVoted}}
<button {{action toggleSelect proposal.id selected}} class="{{if selected 'selected' ''}}">+1</button>
{{/if}}
+12 -10
View File
@@ -1,12 +1,14 @@
{{#each proposals as |proposal|}}
<li data-proposal-id={{proposal.id}} title="({{proposal.kind}}) {{proposal.description}}">
<span class="category {{proposal.kind}}">♥</span>
<span class="amount">{{proposal.amount}}</span><span class="symbol">₭S</span>
for <span class="recipient">{{proposal.contributor.name}}</span>
<span class="votes">({{proposal.votesCount}}/{{proposal.votesNeeded}} votes)</span>
{{#unless proposal.isExecuted}}
<button {{action "confirm" proposal.id}}>+1</button>
{{/unless}}
</li>
{{proposal-list/item
proposal=proposal
selectedProposals=selectedProposals
toggleSelect=(action 'toggleSelect')
}}
{{/each}}
{{#if confirmProposals}}
<p class="actions">
<input type="submit" disabled={{submitButtonDisabled}}
value="Confirm selected" {{action 'confirm'}}>
</p>
{{/if}}
+10 -2
View File
@@ -1,6 +1,7 @@
import Controller from '@ember/controller';
import { alias, filter, filterBy, sort } from '@ember/object/computed';
import { inject as injectService } from '@ember/service';
import RSVP from 'rsvp';
export default Controller.extend({
kredits: injectService(),
@@ -20,10 +21,17 @@ export default Controller.extend({
proposalsOpenSorted: sort('proposalsOpen', 'proposalsSorting'),
actions: {
confirmProposal(proposalId) {
this.kredits.vote(proposalId).then(transaction => {
confirmProposals(proposalIds) {
if (this.kredits.currentUser.isCore) {
return this.kredits.batchVote(proposalIds)
.then((transaction) => {
window.confirm('Vote submitted to Ethereum blockhain: '+transaction.hash);
return transaction;
});
} else {
window.alert('Only members can vote on proposals. Please ask someone to set you up.');
return RSVP.reject();
}
},
save(contributor) {
+6 -7
View File
@@ -4,7 +4,7 @@ import RSVP from 'rsvp';
import Service from '@ember/service';
import { computed } from '@ember/object';
import { alias, notEmpty } from '@ember/object/computed';
import { notEmpty } from '@ember/object/computed';
import { isEmpty } from '@ember/utils';
import config from 'kredits-web/config/environment';
@@ -16,8 +16,6 @@ export default Service.extend({
currentUserAccounts: null, // default to not having an account. this is the wen web3 is loaded.
currentUser: null,
currentUserIsContributor: notEmpty('currentUser'),
currentUserIsCore: alias('currentUser.isCore'),
hasAccounts: notEmpty('currentUserAccounts'),
accountNeedsUnlock: computed('currentUserAccounts', function() {
return this.currentUserAccounts && isEmpty(this.currentUserAccounts);
@@ -72,7 +70,7 @@ export default Service.extend({
this.set('kredits', kredits);
if (this.currentUserAccounts && this.currentUserAccounts.length > 0) {
this.getCurrentUser.then((contributorData) => {
this.set('currentUser', contributorData);
this.set('currentUser', Contributor.create(contributorData));
});
}
return kredits;
@@ -134,10 +132,11 @@ export default Service.extend({
});
},
vote(proposalId) {
console.debug('[kredits] vote for', proposalId);
batchVote(proposalIds) {
proposalIds = proposalIds.map((id) => parseInt(id))
console.debug('[kredits] vote for', proposalIds);
return this.kredits.Operator.functions.vote(proposalId)
return this.kredits.Operator.functions.batchVote(proposalIds)
.then((data) => {
console.debug('[kredits] vote response', data);
return data;
+91
View File
@@ -0,0 +1,91 @@
button, input[type=submit] {
display: inline-block;
border: 1px solid rgba(22, 21, 40, 1);
background-color: rgba(22, 21, 40, 0.6);
color: $primaryColor;
border-radius: 3px;
font-weight: 500;
text-transform: uppercase;
cursor: pointer;
letter-spacing: 0.1em;
&:hover {
background-color: rgba(22, 21, 40, 0.8);
}
&:disabled {
cursor: not-allowed;
background-color: transparent;
}
}
input[type=submit] {
padding: 0.6rem 2rem;
}
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;
&:focus, &.valid {
background-color: rgba(22, 21, 40, 0.6);
}
@include placeholder {
color: rgba(238, 238, 238, 0.5);
}
}
select {
-webkit-appearance: none;
-moz-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=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;
}
}
+1 -15
View File
@@ -84,21 +84,7 @@ section {
}
}
button, input[type=submit] {
display: inline-block;
border: 1px solid rgba(22, 21, 40, 1);
background-color: rgba(22, 21, 40, 0.6);
color: $primaryColor;
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 "forms";
@import "components/loading-spinner";
@import "components/contributor-list";
@@ -1,7 +1,6 @@
section#add-contributor, section#add-proposal {
form {
p {
margin-bottom: 1rem;
@@ -14,81 +13,6 @@ section#add-contributor, section#add-proposal {
}
}
}
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;
&:focus, &.valid {
background-color: rgba(22, 21, 40, 0.6);
}
@include placeholder {
color: rgba(238, 238, 238, 0.5);
}
}
select {
-webkit-appearance: none;
-moz-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;
}
}
}
}
@@ -46,6 +46,10 @@ ul.proposal-list {
height: 2rem;
line-height: 2rem;
padding: 0 0.6rem;
&.selected {
background-color: rgba(224,104,251, 0.6);
}
}
}
+3 -5
View File
@@ -2,7 +2,7 @@
<section id="user-account">
{{#if kredits.currentUser }}
{{ kredits.currentUser.name }}
{{#if kredits.currentUserIsCore }}
{{#if kredits.currentUser.isCore }}
(core)
{{/if}}
Account: {{kredits.currentUser.account}}
@@ -32,8 +32,7 @@
<div class="content">
{{!-- TODO: We need a better naming for kredits.hasAccounts --}}
{{proposal-list proposals=proposalsOpenSorted
confirmProposal=(action "confirmProposal")
contractInteractionEnabled=kredits.hasAccounts}}
confirmProposals=(action 'confirmProposals')}}
{{!-- TODO: We need a better naming --}}
{{#if kredits.hasAccounts}}
@@ -50,8 +49,7 @@
<h2>Closed Proposals</h2>
</header>
<div class="content">
{{proposal-list proposals=proposalsClosedSorted
confirmProposal=(action "confirmProposal")}}
{{proposal-list proposals=proposalsClosedSorted}}
{{!-- TODO: We need a better naming --}}
{{#if kredits.hasAccounts}}
+726 -1349
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -27,7 +27,7 @@
"ember-ajax": "^3.0.0",
"ember-awesome-macros": "0.41.0",
"ember-browserify": "^1.1.13",
"ember-cli": "~3.1.2",
"ember-cli": "^3.1.4",
"ember-cli-app-version": "^3.0.0",
"ember-cli-babel": "^6.6.0",
"ember-cli-dependency-checker": "^2.0.0",
@@ -39,7 +39,7 @@
"ember-cli-sass": "^7.2.0",
"ember-cli-sri": "^2.1.0",
"ember-cli-uglify": "^2.0.0",
"ember-cli-update": "^0.21.2",
"ember-cli-update": "^0.21.4",
"ember-export-application-global": "^2.0.0",
"ember-load-initializers": "^1.0.0",
"ember-macro-helpers": "0.17.0",
@@ -51,7 +51,7 @@
"eslint-plugin-ember": "^5.0.0",
"ethers": "3.0.15",
"kosmos-schemas": "^1.1.2",
"kredits-contracts": "^3.x",
"kredits-contracts": "^3.0.2",
"loader.js": "^4.2.3",
"tv4": "^1.3.0"
},