Compare commits

..

79 Commits

Author SHA1 Message Date
basti c57d4162d7 1.16.0 2020-05-16 11:28:23 +02:00
basti 41cc37d3eb Merge pull request #186 from 67P/chore/upgrade_ember_and_deps
Upgrade Ember and deps to 3.18/Octane
2020-05-11 13:18:58 +02:00
basti 081584a508 Remove obsolete file 2020-05-11 13:15:47 +02:00
basti 3cc01cce4e Fix some minor template issues 2020-05-11 13:15:17 +02:00
basti cedbe3cb3d Formatting 2020-05-11 13:03:46 +02:00
basti b8da04c145 Re-add contribution status class 2020-05-11 13:03:46 +02:00
galfert 009caa53e5 Fix typo in contribution-status helper
The wrong property name caused an exception when trying to remove the observer.
2020-05-11 12:18:07 +02:00
basti 9a1f543921 Mark remaining template-lint issues as pending
These need more updates outside of the templates, like e.g. Glimmer
components and such.
2020-05-11 10:24:38 +02:00
basti 22300c2980 Fix actions, etc. 2020-05-11 10:21:23 +02:00
basti 018132034d Fix github icon filename 2020-05-11 10:21:23 +02:00
basti f5d7916556 Turn on warnings for observer usage 2020-05-11 10:21:23 +02:00
basti 12df28f7fd Fix ESLint errors 2020-05-11 10:21:22 +02:00
basti 2f4f350a93 WIP Octanify the templates 2020-05-11 10:21:18 +02:00
basti 4946b3311d Remove all proposal-related code
We're not using proposals at the moment, so it's just in the way.
2020-05-10 10:25:06 +02:00
basti cc2f91afce Do not lint icon templates 2020-05-09 17:39:54 +02:00
basti aa351cbe17 Move icon templates out of pod directory
Glimmer components don't have extra markup around them, so we don't need
the component JS files anymore. Also, we can easily ignore the icon
templates when linting now.
2020-05-09 17:37:58 +02:00
basti 065c635580 Upgrade to latest Ember, etc. 2020-05-09 17:07:35 +02:00
basti 67e3c9a7c3 Merge pull request #185 from 67P/dependabot/npm_and_yarn/jquery-3.5.0
Bump jquery from 3.4.1 to 3.5.0
2020-04-30 19:54:31 +02:00
dependabot[bot] 4f4b3c5c17 Bump jquery from 3.4.1 to 3.5.0
Bumps [jquery](https://github.com/jquery/jquery) from 3.4.1 to 3.5.0.
- [Release notes](https://github.com/jquery/jquery/releases)
- [Commits](https://github.com/jquery/jquery/compare/3.4.1...3.5.0)

Signed-off-by: dependabot[bot] <support@github.com>
2020-04-30 16:18:08 +00:00
basti 4f6bafa31e Merge pull request #184 from 67P/dependabot/npm_and_yarn/acorn-5.7.4
Bump acorn from 5.7.3 to 5.7.4
2020-03-16 10:50:11 -05:00
dependabot[bot] 94846c6e00 Bump acorn from 5.7.3 to 5.7.4
Bumps [acorn](https://github.com/acornjs/acorn) from 5.7.3 to 5.7.4.
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/5.7.3...5.7.4)

Signed-off-by: dependabot[bot] <support@github.com>
2020-03-16 12:37:30 +00:00
basti 45d553866e Remove obsolete file 2019-12-14 16:35:13 +01:00
basti 8ac6e3ad3c 1.15.0 2019-12-14 12:06:28 +01:00
basti 215ad1d640 Merge pull request #180 from 67P/feature/add_contribution_with_params
Add "give kredits" button to contributor profiles
2019-12-13 17:33:18 +01:00
basti 3f4cc39067 Refactor assignment
Co-authored-by: Garret Alfert <alfert@wevelop.de>
2019-12-13 17:04:52 +01:00
basti 0a6b6180b9 Add "give kredits" button to contributor profiles
closes #172
2019-12-12 17:33:08 +01:00
basti 536868002f Support query params for adding contribution
Just contributor ID, kind, and amount for now.
2019-12-10 18:16:54 +01:00
basti 04a7f9139d Allow partial override of contribution attributes 2019-12-10 13:40:08 +03:00
basti 863b542e3e Add failing test for partial attribute override
Currently the default attributes are only set correctly when either none
or all attributes are handed to the component
2019-12-10 13:18:21 +03:00
basti 23d86f1502 Add unit test for add-contribution component 2019-12-10 13:09:30 +03:00
basti 314cf58c29 1.14.0 2019-12-02 15:59:30 +01:00
basti 9c063b82f1 Merge pull request #169 from 67P/feature/163-small_screen_details_new
Show contributor/contribution details on mobile
2019-12-02 15:57:22 +01:00
basti b397e4faf6 Merge pull request #168 from 67P/bugfix/ios_button_styling
Reset iOS button styling
2019-11-29 21:07:35 +01:00
galfert 256197094e Don't show intro text on details page 2019-11-29 18:06:32 +01:00
galfert 9898d4bb1d Show contributor/contribution details on mobile
Refs #163

On small screens, when selecting a contribution or contributor, the
lists are hidden and only the details are shown.
2019-11-29 18:05:52 +01:00
galfert c321dc51b0 Reset iOS button styling
Removes the pill shaped, shaded button styling on iOS.
2019-11-29 17:44:22 +01:00
basti 8c759601ca 1.13.0 2019-11-27 15:22:02 +01:00
galfert 15e5d3c2fb Merge pull request #166 from 67P/feature/welcome_text
Add intro, fix topbar on mobile, fix filter button
2019-11-27 13:50:31 +01:00
basti 47b7a6501b Add intro text for new users
closes #164
2019-11-27 12:39:49 +01:00
basti 42304a8e27 Fix account panel breaking out of topbar on mobile
refs #163
2019-11-27 11:55:08 +01:00
basti 9a4db6daf6 Do not require account for filtering contributions 2019-11-27 11:00:10 +01:00
basti 26dc78f553 1.12.0 2019-11-22 12:30:20 +01:00
galfert 5a618f7ef9 Merge pull request #165 from 67P/feature/161-copy_contribution
Add copy/re-submit button to all contribution details
2019-11-22 11:55:03 +01:00
basti 5d29bd9604 Add copy/re-submit button to all contribution details
We can in fact just use the exact same re-submission as for vetoed
contributions. So all that is needed is a new button in the UI.

closes #161
2019-11-21 21:13:42 +01:00
basti 97cc71024f Merge pull request #160 from 67P/bugfix/remove_redundant_pending_status
Remove redundant pending status from contribution-status helper
2019-11-15 16:59:50 +01:00
galfert 58f1382df1 Fix helper test filename
Files that don't end with '-test', will not be run.
2019-11-15 16:23:28 +01:00
galfert 6c5406c0b9 Remove redundant pending status from contribution-status helper 2019-11-15 15:28:46 +01:00
basti b2457421be 1.11.0 2019-10-18 17:38:50 +02:00
basti 134eb7d355 Update deps
Fixes security vulns
2019-10-18 17:36:55 +02:00
basti 1dc1a9767e Merge pull request #159 from 67P/feature/pending_changes
Gracefully handle pending changes for contributions
2019-10-18 17:31:41 +02:00
galfert 243a41db88 Remove volatile() property modifier
The modifier got deprecated and wasn't actually needed in any of the used cases.
2019-10-18 16:39:10 +02:00
galfert 523d4524b5 Make contribution-status helper detect pending changes 2019-10-18 16:37:44 +02:00
galfert c21613f20a Merge branch 'master' into feature/pending_changes 2019-10-18 15:17:41 +02:00
basti 12b127c75d Merge pull request #158 from 67P/feature/recompute_helper
Make contribution-status helper recompute
2019-10-18 09:56:50 +02:00
basti a7dd058d21 Remove obsolete parens 2019-10-18 09:52:38 +02:00
basti de6606b29d Merge pull request #156 from 67P/feature/profile_zoom
Add support for Zoom display name in profiles
2019-09-20 23:51:35 +02:00
basti ec701b3130 Update lockfile 2019-09-20 23:45:33 +02:00
galfert 8e7430ebb9 Make contribution-status helper recompute
When any of the depending properties of the contribution changes, the helper recomputes its output.
2019-09-20 18:27:40 +02:00
basti 1deecafee7 Handle pending changes for contributions
This adds the pending tx data to pending contributions (after adding or
vetoing, until the tx is mined). It also disables the veto button while
pending.
2019-09-20 15:43:34 +02:00
basti 51d8b6c8c1 Respect disabled button color for all buttons 2019-09-20 15:40:22 +02:00
bumi b28f6e6bd7 Use official kredits-contracts npm release 2019-09-20 11:17:38 +02:00
basti 4ab28016a3 Depend on contracts master
PR has been merged
2019-09-18 09:38:10 +02:00
basti 6995b67a22 Add support for Zoom display name in profiles 2019-09-18 09:35:24 +02:00
basti 0076d59a42 Remove obsolete ID from icon markup 2019-09-18 09:35:06 +02:00
basti 36b92d97ca Use configured IPFS gateway URL on contributor profile 2019-09-18 09:34:11 +02:00
basti f272bcfcbc Prevent transition abortion on contributor save 2019-09-18 09:32:57 +02:00
basti 985e1673ac Add Zoom icon 2019-09-18 09:31:58 +02:00
basti fe4af46852 1.10.0 2019-09-10 17:01:23 +02:00
basti 7b9659e22f Update deps
Fixes security vulns
2019-09-10 16:59:20 +02:00
basti 8be18fc27c Merge pull request #155 from 67P/feature/resubmit_vetoed_contribution
Re-submit vetoed contributions
2019-09-10 16:53:36 +02:00
basti 7e518780c5 Merge pull request #154 from 67P/feature/sign_in
Improve account connect/loading, check network
2019-09-10 16:48:55 +02:00
basti 89391c1543 Update details of pending contribution when mined
Fetches complete details of new contributions and replaces any potential
pending, incomplete objects in the collection.
2019-09-10 15:21:50 +02:00
basti 05e3118a0c Re-submit vetoed contributions 2019-09-10 11:47:07 +02:00
basti 494b5d9bdd Use configured IPFS gateway URL for button 2019-09-05 11:53:20 +02:00
basti f8f1ad644c WIP: vetoed contribution details
Adds a blurb and resubmit button to the detail view for vetoed
contributions.
2019-09-05 11:36:50 +02:00
basti 5a5051bac6 Check required network before using user provider
closes #82
2019-09-04 18:51:49 +02:00
basti 304c0ac8d0 Only use user wallet if it's already open/connected 2019-09-04 18:29:25 +02:00
basti cae13ed662 Sign in button to connect account 2019-09-04 18:22:48 +02:00
basti 729110f8d1 Remove obsolete APM domains 2019-09-04 17:04:18 +02:00
105 changed files with 19600 additions and 12988 deletions
-1
View File
@@ -4,7 +4,6 @@
root = true root = true
[*] [*]
end_of_line = lf end_of_line = lf
charset = utf-8 charset = utf-8
+12 -4
View File
@@ -1,8 +1,14 @@
'use strict';
module.exports = { module.exports = {
root: true, root: true,
parser: 'babel-eslint',
parserOptions: { parserOptions: {
ecmaVersion: 2018, ecmaVersion: 2018,
sourceType: 'module' sourceType: 'module',
ecmaFeatures: {
legacyDecorators: true
}
}, },
globals: { globals: {
console: true console: true
@@ -19,7 +25,10 @@ module.exports = {
}, },
rules: { rules: {
'ember/avoid-leaking-state-in-ember-objects': 'warn', 'ember/avoid-leaking-state-in-ember-objects': 'warn',
'no-console': 'off' 'no-console': 'off',
'ember/no-jquery': 'error',
'ember/require-computed-property-dependencies': 'warn',
'ember/no-observers': 'warn'
}, },
overrides: [ overrides: [
// node files // node files
@@ -35,8 +44,7 @@ module.exports = {
'server/**/*.js' 'server/**/*.js'
], ],
parserOptions: { parserOptions: {
sourceType: 'script', sourceType: 'script'
ecmaVersion: 2015
}, },
env: { env: {
browser: false, browser: false,
+85 -2
View File
@@ -1,10 +1,93 @@
'use strict'; 'use strict';
module.exports = { module.exports = {
extends: 'recommended', extends: 'octane',
rules: { rules: {
'simple-unless': false, 'simple-unless': false,
'no-nested-interactive': false 'no-nested-interactive': false
} },
ignore: [
'kredits-web/templates/components/**',
'app/templates/components/**'
],
pending: [
{
"moduleId": "app/templates/dashboard",
"only": [
"no-action"
]
},
{
"moduleId": "app/components/add-contribution/template",
"only": [
"no-action",
"no-curly-component-invocation"
]
},
{
"moduleId": "app/components/add-contributor/template",
"only": [
"no-action",
"no-curly-component-invocation"
]
},
{
"moduleId": "app/components/contribution-list/template",
"only": [
"no-action",
"no-curly-component-invocation"
]
},
{
"moduleId": "app/components/contributor-list/template",
"only": [
"no-action"
]
},
{
"moduleId": "app/components/topbar-account-panel/template",
"only": [
"no-action"
]
},
{
"moduleId": "app/templates/contributions/new",
"only": [
"no-action"
]
},
{
"moduleId": "app/templates/contributions/resubmit",
"only": [
"no-action"
]
},
{
"moduleId": "app/templates/contributors/edit",
"only": [
"no-action"
]
},
{
"moduleId": "app/templates/contributors/new",
"only": [
"no-action"
]
},
{
"moduleId": "app/templates/signup/eth-account",
"only": [
"no-action"
]
},
{
"moduleId": "app/templates/signup/index",
"only": [
"no-action"
]
}
]
}; };
+4 -2
View File
@@ -23,7 +23,9 @@ env:
# See https://git.io/vdao3 for details. # See https://git.io/vdao3 for details.
- JOBS=1 - JOBS=1
branches:
only:
- master
script: script:
- npm run lint:hbs
- npm run lint:js
- npm test - npm test
+6 -8
View File
@@ -1,14 +1,12 @@
import Application from '@ember/application'; import Application from '@ember/application';
import Resolver from './resolver'; import Resolver from 'ember-resolver';
import loadInitializers from 'ember-load-initializers'; import loadInitializers from 'ember-load-initializers';
import config from './config/environment'; import config from './config/environment';
const App = Application.extend({ export default class App extends Application {
modulePrefix: config.modulePrefix, modulePrefix = config.modulePrefix;
podModulePrefix: config.podModulePrefix, podModulePrefix = config.podModulePrefix;
Resolver Resolver = Resolver;
}); }
loadInitializers(App, config.modulePrefix); loadInitializers(App, config.modulePrefix);
export default App;
+8 -5
View File
@@ -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 { assign } from '@ember/polyfills';
import moment from 'moment'; import moment from 'moment';
export default Component.extend({ export default Component.extend({
@@ -23,17 +24,18 @@ export default Component.extend({
init () { init () {
this._super(...arguments); this._super(...arguments);
this.set('defaultDate', moment().startOf('hour').toDate()); this.set('defaultDate', moment().startOf('hour').toDate());
this.set('defaultAttr', {
// Default attributes used by reset
this.set('attributes', {
contributorId: null, contributorId: null,
kind: null, kind: null,
date: this.defaultDate, date: this.defaultDate,
amount: null, amount: null,
description: null, description: null,
url: null, url: null,
details: null
}); });
this.set('attributes', assign({}, this.defaultAttr, this.attributes));
this.reset(); this.reset();
}, },
@@ -43,7 +45,9 @@ export default Component.extend({
actions: { actions: {
submit () { submit (evt) {
evt.preventDefault();
if (!this.isValid) { if (!this.isValid) {
alert('Invalid data. Please review and try again.'); alert('Invalid data. Please review and try again.');
return; return;
@@ -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));
} }
} }
+34 -23
View File
@@ -1,11 +1,11 @@
<form {{action "submit" on="submit"}}> <form onsubmit={{action "submit"}}>
<label> <label>
<p class="label">Contributor:</p> <p class="label">Contributor:</p>
<p> <p>
<select required onchange={{action (mut contributorId) value="target.value"}}> <select required onchange={{action (mut this.contributorId) value="target.value"}}>
<option value="" selected disabled hidden></option> <option value="" selected disabled hidden></option>
{{#each contributors as |contributor|}} {{#each @contributors as |contributor|}}
<option value={{contributor.id}} selected={{eq contributorId contributor.id}}>{{contributor.name}}</option> <option value={{contributor.id}} selected={{eq this.contributorId contributor.id}}>{{contributor.name}}</option>
{{/each}} {{/each}}
</select> </select>
</p> </p>
@@ -13,14 +13,14 @@
<label> <label>
<p class="label">Kind:</p> <p class="label">Kind:</p>
<p> <p>
<select required onchange={{action (mut kind) value="target.value"}}> <select required onchange={{action (mut this.kind) value="target.value"}}>
<option value="" selected disabled hidden></option> <option value="" selected disabled hidden></option>
<option value="community" selected={{eq kind "community"}}>Community</option> <option value="community" selected={{eq this.kind "community"}}>Community</option>
<option value="design" selected={{eq kind "design"}}>Design</option> <option value="design" selected={{eq this.kind "design"}}>Design</option>
<option value="dev" selected={{eq kind "dev"}}>Development</option> <option value="dev" selected={{eq this.kind "dev"}}>Development</option>
<option value="docs" selected={{eq kind "docs"}}>Documentation</option> <option value="docs" selected={{eq this.kind "docs"}}>Documentation</option>
<option value="ops" selected={{eq kind "ops"}}>IT Operations</option> <option value="ops" selected={{eq this.kind "ops"}}>IT Operations</option>
<option value="special" selected={{eq kind "special"}}>Special</option> <option value="special" selected={{eq this.kind "special"}}>Special</option>
</select> </select>
</p> </p>
</label> </label>
@@ -28,12 +28,12 @@
<p class="label">Date:</p> <p class="label">Date:</p>
<p> <p>
{{ember-flatpickr {{ember-flatpickr
date=date date=this.date
defaultDate=defaultDate defaultDate=this.defaultDate
maxDate=defaultDate maxDate=this.defaultDate
enableTime=true enableTime=true
time_24hr=true time_24hr=true
onChange=(action (mut date)) onChange=(action (mut this.date))
}} }}
</p> </p>
</label> </label>
@@ -42,31 +42,42 @@
<p> <p>
{{input type="text" {{input type="text"
placeholder="500" placeholder="500"
value=amount value=this.amount
class=(if isValidAmount "valid" "")}} class=(if this.isValidAmount "valid" "")}}
</p> </p>
</label> </label>
<label> <label>
<p class="label">Description:</p> <p class="label">Description:</p>
<p> <p>
{{input type="text" {{input type="text"
value=description value=this.description
class=(if isValidDescription "valid" "")}} class=(if this.isValidDescription "valid" "")}}
</p> </p>
</label> </label>
<label> <label>
<p class="label">URL (optional):</p> <p class="label">URL (optional):</p>
<p> <p>
{{input type="text" {{input type="text"
value=url value=this.url
class=(if isValidUrl "valid" "")}} class=(if this.isValidUrl "valid" "")}}
</p> </p>
</label> </label>
{{#if this.details}}
<label>
<p class="label">Details:</p>
<p>
<pre>
{{this.details}}
</pre>
</p>
</label>
{{/if}}
<p class="actions"> <p class="actions">
{{input type="submit" {{input type="submit"
disabled=inProgress disabled=this.inProgress
value=(if inProgress "Processing" "Save")}} value=(if this.inProgress "Processing" "Save")}}
</p> </p>
</form> </form>
+13 -3
View File
@@ -7,6 +7,7 @@ import { isAddress } from 'web3-utils';
export default Component.extend({ export default Component.extend({
router: service(),
kredits: service(), kredits: service(),
attributes: null, attributes: null,
@@ -21,6 +22,7 @@ export default Component.extend({
isValidGithubUsername: notEmpty('github_username'), isValidGithubUsername: notEmpty('github_username'),
isValidGiteaUsername: notEmpty('gitea_username'), isValidGiteaUsername: notEmpty('gitea_username'),
isValidWikiUsername: notEmpty('wiki_username'), isValidWikiUsername: notEmpty('wiki_username'),
isValidZoomDisplayName: notEmpty('zoom_display_name'),
isValid: and( isValid: and(
'isValidAccount', 'isValidAccount',
@@ -47,7 +49,8 @@ export default Component.extend({
github_username: null, github_username: null,
github_uid: null, github_uid: null,
gitea_username: null, gitea_username: null,
wiki_username: null wiki_username: null,
zoom_display_name: null
}); });
}, },
@@ -57,9 +60,15 @@ export default Component.extend({
actions: { actions: {
submit () { submit (evt) {
evt.preventDefault();
if (!this.kredits.currentUserIsCore) {
window.alert('Only core team members can edit profiles. Please ask someone to set you up.');
return;
}
if (!this.isValid) { if (!this.isValid) {
alert('Invalid data. Please review and try again.'); window.alert('Invalid data. Please review and try again.');
return; return;
} }
@@ -75,6 +84,7 @@ export default Component.extend({
window.alert('Something went wrong. Please check the browser console.'); window.alert('Something went wrong. Please check the browser console.');
}).finally(() => { }).finally(() => {
this.set('inProgress', false); this.set('inProgress', false);
this.router.transitionTo('dashboard');
}); });
} }
+28 -22
View File
@@ -1,50 +1,56 @@
<form {{action "submit" on="submit"}}> <form onsubmit={{action "submit"}}>
<p> <p>
<label for="c-account">Ethereum account</label> <label for="c-account">Ethereum account</label>
{{input name="account" id="c-account" <Input @type="text"
type="text" value=account @value={{this.account}}
placeholder="0xF18E631Ea191aE4ebE70046Fcb01a436554421BA4" name="account" id="c-account"
class=(if isValidAccount "valid" "")}} placeholder="0xF18E631Ea191aE4ebE70046Fcb01a436554421BA4"
class={{if this.isValidAccount "valid" ""}} />
</p> </p>
<p> <p>
<label for="c-kind">Kind</label> <label for="c-kind">Kind</label>
<select required onchange={{action (mut kind) value="target.value"}} id="c-kind"> <select required onchange={{action (mut this.kind) value="target.value"}} id="c-kind">
<option value="person" selected={{eq kind "person"}}>Person</option> <option value="person" selected={{eq this.kind "person"}}>Person</option>
<option value="organization" selected={{eq kind "organization"}}>Organization</option> <option value="organization" selected={{eq this.kind "organization"}}>Organization</option>
</select> </select>
</p> </p>
<p> <p>
<label for="c-name">Name</label> <label for="c-name">Name</label>
{{input name="name" type="text" value=name placeholder="Zero Cool" {{input name="name" type="text" value=this.name placeholder="Zero Cool"
class=(if isValidName "valid" "") id="c-name"}} class=(if this.isValidName "valid" "") id="c-name"}}
</p> </p>
<p> <p>
<label for="c-url">URL</label> <label for="c-url">URL</label>
{{input name="url" type="text" value=url placeholder="http://zerocool.bit" {{input name="url" type="text" value=this.url placeholder="http://zerocool.bit"
class=(if isValidURL "valid" "") id="c-url"}} class=(if this.isValidURL "valid" "") id="c-url"}}
</p> </p>
<p> <p>
<label for="c-github-uid">GitHub UID</label> <label for="c-github-uid">GitHub UID</label>
{{input name="github_uid" type="text" value=github_uid placeholder="2342" {{input name="github_uid" type="text" value=this.github_uid placeholder="2342"
class=(if isValidGithubUID "valid" "") id="c-github-uid"}} class=(if this.isValidGithubUID "valid" "") id="c-github-uid"}}
</p> </p>
<p> <p>
<label for="c-github-username">GitHub username</label> <label for="c-github-username">GitHub username</label>
{{input name="github_username" type="text" value=github_username placeholder="zerocool" {{input name="github_username" type="text" value=this.github_username placeholder="zerocool"
class=(if isValidGithubUsername "valid" "") id="c-github-username"}} class=(if this.isValidGithubUsername "valid" "") id="c-github-username"}}
</p> </p>
<p> <p>
<label for="c-gitea-username">Gitea username</label> <label for="c-gitea-username">Gitea username</label>
{{input name="gitea_username" type="text" value=gitea_username placeholder="zerocool" {{input name="gitea_username" type="text" value=this.gitea_username placeholder="zerocool"
class=(if isValidGiteaUsername "valid" "") id="c-gitea-username"}} class=(if this.isValidGiteaUsername "valid" "") id="c-gitea-username"}}
</p> </p>
<p> <p>
<label for="c-wiki-username">Wiki username</label> <label for="c-wiki-username">Wiki username</label>
{{input name="wiki_username" type="text" value=wiki_username placeholder="ZeroCool" {{input name="wiki_username" type="text" value=this.wiki_username placeholder="ZeroCool"
class=(if isValidWikiUsername "valid" "") id="c-wiki-username"}} class=(if this.isValidWikiUsername "valid" "") id="c-wiki-username"}}
</p>
<p>
<label for="c-zoom-display-name">Zoom display name</label>
{{input name="zoom_display_name" type="text" value=this.zoom_display_name placeholder="Zero Cool"
class=(if this.isValidZoomDisplayName "valid" "") id="c-zoom-display-name"}}
</p> </p>
<p class="actions"> <p class="actions">
{{input type="submit" disabled=inProgress {{input type="submit" disabled=this.inProgress
value=(if inProgress "Processing" "Save")}} value=(if this.inProgress "Processing" "Save")}}
</p> </p>
</form> </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,7 +1,6 @@
<div class="chart"> <div class="chart">
{{ember-chart type="doughnut" <EmberChart @type="doughnut"
data=chartData @data={{this.chartData}}
options=chartOptions @options={{this.chartOptions}}
width=200 @width="200" @height="200" />
height=200}}
</div> </div>
@@ -24,12 +24,10 @@ export default Component.extend({
contributors: sort('kredits.contributors', 'contributorsSorting'), contributors: sort('kredits.contributors', 'contributorsSorting'),
contributorsActive: computed('contributors.[]', 'contributions', function() { contributorsActive: computed('contributors.[]', 'contributions', function() {
let activeIds = this.contributions.mapBy('contributorId') const activeIds = new Set(this.contributions.mapBy('contributorId')
.map(id => id.toString()) .map(id => id.toString()));
.uniq();
return this.contributors.filter(c => { return this.contributors.filter(c => activeIds.has(c.id.toString()));
return activeIds.includes(c.id.toString());
});
}), }),
contributionKinds: computed('contributions.[]', function() { contributionKinds: computed('contributions.[]', function() {
+16 -14
View File
@@ -1,28 +1,28 @@
{{#if showQuickFilter}} {{#if @showQuickFilter}}
<div class="quick-filter"> <div class="quick-filter">
<p> <p>
<label class="filter-contributor"> <label class="filter-contributor">
Contributor: Contributor:
<select onchange={{action (mut contributorId) value="target.value"}}> <select onchange={{action (mut this.contributorId) value="target.value"}}>
<option value="" selected>all</option> <option value="" selected>all</option>
{{#each contributorsActive as |contributor|}} {{#each this.contributorsActive as |contributor|}}
<option value={{contributor.id}} selected={{eq contributorId contributor.id}}>{{contributor.name}}</option> <option value={{contributor.id}} selected={{eq this.contributorId contributor.id}}>{{contributor.name}}</option>
{{/each}} {{/each}}
</select> </select>
</label> </label>
<label class="filter-contribution-kind"> <label class="filter-contribution-kind">
Kind: Kind:
<select onchange={{action (mut contributionKind) value="target.value"}}> <select onchange={{action (mut this.contributionKind) value="target.value"}}>
<option value="" selected>all</option> <option value="" selected>all</option>
{{#each contributionKinds as |kind|}} {{#each this.contributionKinds as |kind|}}
<option value={{kind}} selected={{eq contributionKind kind}}>{{capitalize-string kind}}</option> <option value={{kind}} selected={{eq this.contributionKind kind}}>{{capitalize-string kind}}</option>
{{/each}} {{/each}}
</select> </select>
</label> </label>
<label class="filter-contribution-size"> <label class="filter-contribution-size">
{{input type="checkbox" checked=hideSmallContributions}} <Input @type="checkbox" @checked={{this.hideSmallContributions}} />
Hide small contributions Hide small contributions
</label> </label>
</p> </p>
@@ -30,12 +30,12 @@
{{/if}} {{/if}}
<ul class="contribution-list"> <ul class="contribution-list">
{{#each contributionsFiltered as |contribution|}} {{#each this.contributionsFiltered as |contribution|}}
<li role="button" {{action "openContributionDetails" contribution}} <li role="button" data-contribution-id={{contribution.id}}
data-contribution-id={{contribution.id}} {{action "openContributionDetails" contribution}}
class="{{contribution-status contribution}}{{if contribution.vetoed " vetoed"}}{{if (eq contribution.id selectedContributionId) " selected"}}"> class="{{contribution-status contribution}}{{if (eq contribution.id @selectedContributionId) " selected"}}">
<p class="meta"> <p class="meta">
<span class="recipient">{{user-avatar contributor=contribution.contributor}}</span> <span class="recipient"><UserAvatar @contributor={{contribution.contributor}} /></span>
<span class="category {{contribution.kind}}">({{contribution.kind}})</span> <span class="category {{contribution.kind}}">({{contribution.kind}})</span>
<span class="title">{{contribution.description}}</span> <span class="title">{{contribution.description}}</span>
</p> </p>
@@ -45,7 +45,9 @@
{{#unless contribution.vetoed}} {{#unless contribution.vetoed}}
{{#unless (is-confirmed-contribution contribution)}} {{#unless (is-confirmed-contribution contribution)}}
<p class="voting"> <p class="voting">
<button {{action "veto" contribution.id}} class="small danger">veto</button> {{input type="button" class="button small danger" value="veto"
click=(action "veto" contribution.id)
disabled=contribution.hasPendingChanges}}
</p> </p>
{{/unless}} {{/unless}}
{{/unless}} {{/unless}}
+6 -5
View File
@@ -1,13 +1,14 @@
<tbody> <tbody>
{{#each contributorList as |c|}} {{#each @contributorList as |c|}}
<tr role="button" {{action "openContributorDetails" c.contributor}} <tr role="button"
class="{{if (is-current-user c.contributor) "current-user"}} {{if (eq c.contributor.id selectedContributorId) "selected"}}"> onclick={{action "openContributorDetails" c.contributor}}
class="{{if (is-current-user c.contributor) "current-user"}} {{if (eq c.contributor.id @selectedContributorId) "selected"}}">
<td class="person"> <td class="person">
{{user-avatar contributor=c.contributor}} {{c.contributor.name}} <UserAvatar @contributor={{c.contributor}} /> {{c.contributor.name}}
</td> </td>
<td class="kredits"> <td class="kredits">
<span class="amount"> <span class="amount">
{{#if showUnconfirmedKredits}} {{#if @showUnconfirmedKredits}}
{{c.amountTotal}} {{c.amountTotal}}
{{else}} {{else}}
{{c.amountConfirmed}} {{c.amountConfirmed}}
@@ -6,7 +6,7 @@ export default Component.extend({
account: null, account: null,
iconComponentName: computed('account.site', function() { iconComponentName: computed('account.site', function() {
if (this.account.site.match(/github|gitea|wiki/)) { if (this.account.site.match(/github|gitea|wiki|zoom/)) {
return 'icon-account-' + this.account.site.replace(/\./g, '-'); return 'icon-account-' + this.account.site.replace(/\./g, '-');
} else { } else {
return 'icon-web-globe'; return 'icon-web-globe';
@@ -1,4 +1,5 @@
<a href={{account.url}} target="_blank" rel="noopener" title="{{account.username}} on {{account.site}}"> <a href={{this.account.url}} target="_blank" rel="noopener noreferrer"
<span class="site">{{account.site}}</span> title="{{this.account.username}} on {{this.account.site}}">
{{component iconComponentName}} <span class="site">{{this.account.site}}</span>
{{component this.iconComponentName}}
</a> </a>
@@ -1,5 +0,0 @@
import Component from '@ember/component';
export default Component.extend({
tagName: ""
});
@@ -1,5 +0,0 @@
import Component from '@ember/component';
export default Component.extend({
tagName: ""
});
@@ -1,5 +0,0 @@
import Component from '@ember/component';
export default Component.extend({
tagName: ""
});
@@ -1,5 +0,0 @@
import Component from '@ember/component';
export default Component.extend({
tagName: ""
});
-20
View File
@@ -1,20 +0,0 @@
import Component from '@ember/component';
export default Component.extend({
tagName: 'ul',
classNames: ['proposal-list'],
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.');
}
}
}
});
-20
View File
@@ -1,20 +0,0 @@
{{#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>
{{/each}}
@@ -1,5 +1,7 @@
import Component from '@ember/component'; import Component from '@ember/component';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import { computed } from '@ember/object';
import { isPresent } from '@ember/utils';
export default Component.extend({ export default Component.extend({
@@ -8,10 +10,35 @@ export default Component.extend({
kredits: service(), kredits: service(),
router: service(), router: service(),
setupInProgress: false,
userHasEthereumWallet: computed(function() {
return isPresent(window.ethereum);
}),
showConnectButton: computed('userHasEthereumWallet',
'kredits.hasAccounts', function() {
return this.userHasEthereumWallet &&
!this.kredits.hasAccounts;
}),
actions: { actions: {
signup() { signup() {
this.router.transitionTo('signup'); this.router.transitionTo('signup');
},
async connectAccount() {
try {
await window.ethereum.enable();
this.set('setupInProgress', true);
await this.kredits.setup();
this.set('setupInProgress', false);
this.router.transitionTo('dashboard');
} catch (error) {
this.set('setupInProgress', false);
console.log('Opening Ethereum wallet failed:', error);
}
} }
} }
@@ -1,11 +1,18 @@
<section id="user-account"> <section id="user-account">
{{#if (and kredits.hasAccounts kredits.currentUser)}} {{#if this.setupInProgress}}
{{kredits.currentUser.name}} Connecting account...
{{#if kredits.currentUserIsCore}}
<span class="core-flag">(core)</span>
{{/if}}
{{else}} {{else}}
Anonymous {{#if (and this.kredits.hasAccounts this.kredits.currentUser)}}
<button {{action "signup"}} class="small green">Sign up</button> {{this.kredits.currentUser.name}}
{{#if this.kredits.currentUserIsCore}}
<span class="core-flag">(core)</span>
{{/if}}
{{else}}
<span class="anonymous">Anonymous</span>
<button onclick={{action "signup"}} class="small" type="button">Sign up</button>
{{#if this.showConnectButton}}
<button onclick={{action "connectAccount"}} class="small green" type="button">Connect account</button>
{{/if}}
{{/if}}
{{/if}} {{/if}}
</section> </section>
+3
View File
@@ -24,6 +24,9 @@ export default Component.extend({
if (github_uid) { if (github_uid) {
return `https://avatars2.githubusercontent.com/u/${github_uid}?v=3&s=${SIZES[this.size]}`; return `https://avatars2.githubusercontent.com/u/${github_uid}?v=3&s=${SIZES[this.size]}`;
} else {
// TODO use custom avatar
return '';
} }
}) })
+2
View File
@@ -6,6 +6,8 @@ export default Controller.extend({
kredits: service(), kredits: service(),
queryParams: ['contributorId', 'kind', 'amount'],
contributors: alias('kredits.contributors'), contributors: alias('kredits.contributors'),
minedContributors: filterBy('contributors', 'id'), minedContributors: filterBy('contributors', 'id'),
@@ -0,0 +1,7 @@
import ContributionsNewController from 'kredits-web/controllers/contributions/new';
export default ContributionsNewController.extend({
attributes: null,
});
+1 -3
View File
@@ -8,9 +8,7 @@ export default Controller.extend({
actions: { actions: {
save (attributes) { save (attributes) {
return this.kredits return this.kredits.updateContributor(this.model.id, attributes);
.updateContributor(this.model.id, attributes)
.then(() => this.transitionToRoute('index'))
} }
} }
+1 -3
View File
@@ -8,9 +8,7 @@ export default Controller.extend({
actions: { actions: {
save (contributor) { save (contributor) {
return this.kredits return this.kredits.addContributor(contributor);
.addContributor(contributor)
.then(() => this.transitionToRoute('index'))
} }
} }
+4 -6
View File
@@ -33,6 +33,10 @@ export default Controller.extend({
showQuickFilterUnconfirmed: false, showQuickFilterUnconfirmed: false,
showQuickFilterConfirmed: false, showQuickFilterConfirmed: false,
showIntroText: computed('kredits.{hasAccounts,currentUser}', function(){
return (!this.kredits.hasAccounts || !this.kredits.currentUser);
}),
actions: { actions: {
vetoContribution (contributionId) { vetoContribution (contributionId) {
@@ -41,12 +45,6 @@ export default Controller.extend({
}); });
}, },
confirmProposal (proposalId) {
this.kredits.vote(proposalId).then(transaction => {
console.debug('[controllers:index] Vote submitted to Ethereum blockhain: '+transaction.hash);
});
},
toggleQuickFilterUnconfirmed () { toggleQuickFilterUnconfirmed () {
this.toggleProperty('showQuickFilterUnconfirmed'); this.toggleProperty('showQuickFilterUnconfirmed');
}, },
@@ -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;
})
});
@@ -1,5 +1,6 @@
import Controller from '@ember/controller'; import Controller from '@ember/controller';
import { computed } from '@ember/object'; import { computed } from '@ember/object';
import config from 'kredits-web/config/environment';
export default Controller.extend({ export default Controller.extend({
@@ -7,6 +8,10 @@ export default Controller.extend({
if (this.model.isCore) return 'Core Contributor'; if (this.model.isCore) return 'Core Contributor';
if (this.model.totalKreditsEarned <= 5000) return 'Newcomer'; if (this.model.totalKreditsEarned <= 5000) return 'Newcomer';
return 'Contributor'; return 'Contributor';
}),
ipfsGatewayUrl: computed(function() {
return config.ipfs.gatewayUrl;
}) })
}); });
-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;
});
}
}
});
+39 -3
View File
@@ -1,6 +1,7 @@
import Helper from '@ember/component/helper'; import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service'; import { inject as service } from '@ember/service';
import { alias } from '@ember/object/computed'; import { alias } from '@ember/object/computed';
import { once } from '@ember/runloop';
export default Helper.extend({ export default Helper.extend({
@@ -8,13 +9,48 @@ export default Helper.extend({
currentBlock: alias('kredits.currentBlock'), currentBlock: alias('kredits.currentBlock'),
compute([contribution]) { compute([contribution]) {
this.setupRecompute(contribution);
let status = [];
if (contribution.vetoed) { if (contribution.vetoed) {
return 'vetoed'; status.push('vetoed');
} else if (contribution.confirmedAt > this.currentBlock) { } else if (contribution.confirmedAt > this.currentBlock) {
return 'unconfirmed'; status.push('unconfirmed');
} else { } else {
return 'confirmed' status.push('confirmed');
} }
if (contribution.hasPendingChanges) {
status.push('pending');
}
return status.join(' ');
},
destroy () {
if (this.teardown) this.teardown();
this._super(...arguments);
},
setupRecompute (contribution) {
if (this.teardown) this.teardown();
contribution.addObserver('vetoed' , this, this.triggerRecompute);
contribution.addObserver('confirmedAt' , this, this.triggerRecompute);
contribution.addObserver('currentBlock' , this, this.triggerRecompute);
contribution.addObserver('hasPendingChanges' , this, this.triggerRecompute);
this.teardown = () => {
contribution.removeObserver('vetoed', this, this.triggerRecompute);
contribution.removeObserver('confirmedAt', this, this.triggerRecompute);
contribution.removeObserver('currentBlock', this, this.triggerRecompute);
contribution.removeObserver('hasPendingChanges', this, this.triggerRecompute);
};
},
triggerRecompute () {
once(this, this.recompute);
} }
}); });
+13 -1
View File
@@ -1,5 +1,7 @@
import EmberObject, { computed } from '@ember/object'; import EmberObject, { computed } from '@ember/object';
import { isEmpty, isPresent } 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({
@@ -22,13 +24,23 @@ export default EmberObject.extend({
time: null, time: null,
ipfsData: '', ipfsData: '',
pendingTx: null,
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();
}),
hasPendingChanges: computed('pendingTx', function() {
return isPresent(this.pendingTx);
}) })
}); });
+1
View File
@@ -19,6 +19,7 @@ export default EmberObject.extend({
github_username: null, github_username: null,
github_uid: null, github_uid: null,
wiki_username: null, wiki_username: null,
zoom_display_name: null,
ipfsData: '' ipfsData: ''
}); });
-32
View File
@@ -1,32 +0,0 @@
import EmberObject from '@ember/object';
import { alias } from '@ember/object/computed';
import bignumber from 'kredits-web/utils/cps/bignumber';
export default EmberObject.extend({
// Contract
id: bignumber('idRaw', 'toString'),
creatorAccount: null,
contributorId: bignumber('contributorIdRaw', 'toString'),
amount: bignumber('amountRaw', 'toNumber'),
votesCount: bignumber('votesCountRaw', 'toNumber'),
votesNeeded: bignumber('votesNeededRaw', 'toNumber'),
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', {});
}
});
-3
View File
@@ -1,3 +0,0 @@
import Resolver from 'ember-resolver';
export default Resolver;
+6 -10
View File
@@ -1,10 +1,10 @@
import EmberRouter from '@ember/routing/router'; import EmberRouter from '@ember/routing/router';
import config from './config/environment'; import config from './config/environment';
const Router = EmberRouter.extend({ export default class Router extends EmberRouter {
location: config.locationType, location = config.locationType;
rootURL: config.rootURL rootURL = config.rootURL;
}); }
Router.map(function() { Router.map(function() {
this.route('dashboard', function() { this.route('dashboard', function() {
@@ -16,11 +16,9 @@ Router.map(function() {
this.route('show', { path: ':id' }); this.route('show', { path: ':id' });
}); });
}); });
this.route('proposals', function() {
this.route('new');
});
this.route('contributions', function() { this.route('contributions', function() {
this.route('new'); this.route('new', { queryParams: ['contributorId', 'kind', 'amount'] });
this.route('resubmit', { path: ':id/resubmit' });
}); });
this.route('contributors', function() { this.route('contributors', function() {
this.route('new'); this.route('new');
@@ -32,5 +30,3 @@ Router.map(function() {
this.route('complete'); this.route('complete');
}); });
}); });
export default Router;
+1 -6
View File
@@ -4,7 +4,7 @@ import Route from '@ember/routing/route';
export default Route.extend({ export default Route.extend({
kredits: service(), kredits: service(),
beforeModel(transition) { beforeModel(/* transition */) {
const kredits = this.kredits; const kredits = this.kredits;
return kredits.setup().then(() => { return kredits.setup().then(() => {
@@ -12,11 +12,6 @@ export default Route.extend({
console.error('Kredits preflight check failed!'); console.error('Kredits preflight check failed!');
console.error(error); 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) => { }).catch((error) => {
console.log('Error initializing Kredits', error); console.log('Error initializing Kredits', error);
}); });
+9
View File
@@ -0,0 +1,9 @@
import Route from '@ember/routing/route';
export default Route.extend({
model (params) {
return { params };
}
});
+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);
}
});
+2 -1
View File
@@ -22,7 +22,8 @@ export default Route.extend({
github_username: model.github_username, github_username: model.github_username,
github_uid: model.github_uid, github_uid: model.github_uid,
gitea_username: model.gitea_username, gitea_username: model.gitea_username,
wiki_username: model.wiki_username wiki_username: model.wiki_username,
zoom_display_name: model.zoom_display_name
}); });
} }
+38 -98
View File
@@ -6,14 +6,13 @@ import Service from '@ember/service';
import EmberObject from '@ember/object'; import EmberObject from '@ember/object';
import { computed } from '@ember/object'; import { computed } from '@ember/object';
import { alias, notEmpty } from '@ember/object/computed'; import { alias, notEmpty } from '@ember/object/computed';
import { isEmpty } from '@ember/utils'; import { isEmpty, isPresent } from '@ember/utils';
import groupBy from 'kredits-web/utils/group-by'; import groupBy from 'kredits-web/utils/group-by';
import formatKredits from 'kredits-web/utils/format-kredits'; import formatKredits from 'kredits-web/utils/format-kredits';
import config from 'kredits-web/config/environment'; import config from 'kredits-web/config/environment';
import Contributor from 'kredits-web/models/contributor' import Contributor from 'kredits-web/models/contributor'
import Proposal from 'kredits-web/models/proposal'
import Contribution from 'kredits-web/models/contribution' import Contribution from 'kredits-web/models/contribution'
export default Service.extend({ export default Service.extend({
@@ -23,17 +22,12 @@ export default Service.extend({
currentUser: null, currentUser: null,
contributors: null, contributors: null,
contributions: null, contributions: null,
proposals: null,
githubAccessToken: null, githubAccessToken: null,
currentUserIsContributor: notEmpty('currentUser'), currentUserIsContributor: notEmpty('currentUser'),
currentUserIsCore: alias('currentUser.isCore'), currentUserIsCore: alias('currentUser.isCore'),
hasAccounts: notEmpty('currentUserAccounts'), hasAccounts: notEmpty('currentUserAccounts'),
accountNeedsUnlock: computed('currentUserAccounts', function() {
return this.currentUserAccounts && isEmpty(this.currentUserAccounts);
}),
contributionsUnconfirmed: computed('contributions.[]', 'currentBlock', function() { contributionsUnconfirmed: computed('contributions.[]', 'currentBlock', function() {
return this.contributions.filter(contribution => { return this.contributions.filter(contribution => {
return contribution.confirmedAt > this.currentBlock; return contribution.confirmedAt > this.currentBlock;
@@ -81,7 +75,6 @@ export default Service.extend({
init () { init () {
this._super(...arguments); this._super(...arguments);
this.set('contributors', []); this.set('contributors', []);
this.set('proposals', []);
this.set('contributions', []); this.set('contributions', []);
}, },
@@ -105,7 +98,14 @@ export default Service.extend({
async function instantiateWithAccount (web3Provider, context) { async function instantiateWithAccount (web3Provider, context) {
console.debug('[kredits] Using user-provided instance, e.g. from Mist browser or Metamask'); console.debug('[kredits] Using user-provided instance, e.g. from Mist browser or Metamask');
ethProvider = new ethers.providers.Web3Provider(web3Provider); ethProvider = new ethers.providers.Web3Provider(web3Provider);
// const network = await ethProvider.getNetwork();
const network = await ethProvider.getNetwork();
if (isPresent(config.web3RequiredNetwork) &&
network.name !== config.web3RequiredNetwork) {
window.alert(`Please switch your Ethereum wallet to the "${config.web3RequiredNetwork}" network before connecting your account.`);
return instantiateWithoutAccount();
}
ethProvider.listAccounts().then(accounts => { ethProvider.listAccounts().then(accounts => {
context.set('currentUserAccounts', accounts); context.set('currentUserAccounts', accounts);
const ethSigner = accounts.length === 0 ? null : ethProvider.getSigner(); const ethSigner = accounts.length === 0 ? null : ethProvider.getSigner();
@@ -117,12 +117,9 @@ export default Service.extend({
} }
if (window.ethereum) { if (window.ethereum) {
try { if (window.ethereum.isConnected()) {
// Request account access if needed
await window.ethereum.enable();
// Acccounts now exposed
instantiateWithAccount(window.ethereum, this); instantiateWithAccount(window.ethereum, this);
} catch (error) { } else {
instantiateWithoutAccount(); instantiateWithoutAccount();
} }
} }
@@ -210,8 +207,8 @@ export default Service.extend({
getContributors () { getContributors () {
return this.kredits.Contributor.all() return this.kredits.Contributor.all()
.then((contributors) => { .then(contributors => {
return contributors.map((contributor) => { return contributors.map(contributor => {
return Contributor.create(contributor); return Contributor.create(contributor);
}); });
}); });
@@ -225,34 +222,13 @@ 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('pendingTx', data);
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);
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 () { getContributions () {
return this.kredits.Contribution.all({page: {size: 200}}) return this.kredits.Contribution.all({page: {size: 200}})
.then(contributions => { .then(contributions => {
@@ -263,32 +239,24 @@ export default Service.extend({
}); });
}, },
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) { veto (contributionId) {
console.debug('[kredits] veto against', contributionId); console.debug('[kredits] veto against', contributionId);
const contribution = this.contributions.findBy('id', contributionId);
return this.kredits.Contribution.functions.veto(contributionId, { gasLimit: 300000 }) return this.kredits.Contribution.functions.veto(contributionId, { gasLimit: 300000 })
.then(data => { .then(data => {
console.debug('[kredits] veto response', data); console.debug('[kredits] veto response', data);
contribution.set('pendingTx', data);
return data; return data;
}); });
}, },
getCurrentUser: computed('kredits.provider', function() { getCurrentUser: computed('kredits.provider', 'currentUserAccounts.[]', function() {
if (isEmpty(this.currentUserAccounts)) { if (isEmpty(this.currentUserAccounts)) {
return RSVP.resolve(); return RSVP.resolve();
} }
return this.kredits.Contributor return this.kredits.Contributor
.functions.getContributorIdByAddress(this.get('currentUserAccounts.firstObject')) .functions.getContributorIdByAddress(this.currentUserAccounts.firstObject)
.then((id) => { .then((id) => {
// check if the user is a contributor or not // check if the user is a contributor or not
if (id === 0) { if (id === 0) {
@@ -299,10 +267,6 @@ export default Service.extend({
}); });
}), }),
findProposalById(proposalId) {
return this.proposals.findBy('id', proposalId.toString());
},
// Contract events // Contract events
addContractEventHandlers () { addContractEventHandlers () {
this.kredits.Contributor this.kredits.Contributor
@@ -311,13 +275,9 @@ 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
.on('ProposalCreated', this.handleProposalCreated.bind(this))
.on('ProposalVoted', this.handleProposalVoted.bind(this))
.on('ProposalExecuted', this.handleProposalExecuted.bind(this));
this.kredits.Token this.kredits.Token
.on('Transfer', this.handleTransfer.bind(this)); .on('Transfer', this.handleTransfer.bind(this));
}, },
@@ -338,6 +298,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);
@@ -345,48 +323,10 @@ export default Service.extend({
if (contribution) { if (contribution) {
contribution.set('vetoed', true); contribution.set('vetoed', true);
contribution.set('pendingTx', null);
} }
}, },
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) { handleTransfer (from, to, value) {
value = value.toNumber(); value = value.toNumber();
+3 -2
View File
@@ -10,6 +10,7 @@ button, input[type=submit], .button {
text-transform: uppercase; text-transform: uppercase;
cursor: pointer; cursor: pointer;
letter-spacing: 0.1em; letter-spacing: 0.1em;
-webkit-appearance: none;
&+button, &+input[type=submit], &+.button { &+button, &+input[type=submit], &+.button {
margin-left: 0.5rem; margin-left: 0.5rem;
@@ -32,7 +33,7 @@ button, input[type=submit], .button {
padding: 0.2rem 0.8rem; padding: 0.2rem 0.8rem;
} }
&.danger { &.danger:not(:disabled) {
color: $red; color: $red;
background-color: rgba(40, 21, 21, 0.6); background-color: rgba(40, 21, 21, 0.6);
border-color: rgba(40, 21, 21, 1); border-color: rgba(40, 21, 21, 1);
@@ -45,7 +46,7 @@ button, input[type=submit], .button {
} }
} }
&.green { &.green:not(:disabled) {
color: $green; color: $green;
background-color: rgba(21, 40, 21, 0.6); background-color: rgba(21, 40, 21, 0.6);
border-color: rgba(21, 40, 21, 1); border-color: rgba(21, 40, 21, 1);
-5
View File
@@ -8,8 +8,3 @@ $red: #fb6868;
$primary-color: $blue; $primary-color: $blue;
$body-text-color: #fff; $body-text-color: #fff;
#topbar {
background-color: rgba(255, 0, 255, .2);
}
-1
View File
@@ -1,6 +1,5 @@
section#add-contributor, section#add-contributor,
section#add-contribution, section#add-contribution,
section#add-proposal,
section#signup { section#signup {
form { form {
+34
View File
@@ -61,6 +61,40 @@ main {
} }
} }
#intro {
padding: 2rem;
background-color: rgba(0,0,0,.2);
font-size: 1.6rem;
@include media-max(small) {
padding: 2rem 1rem;
font-size: 1.4rem;
}
h2 {
font-size: inherit;
margin-bottom: 1em;
}
p {
margin-bottom: 1em;
line-height: 1.5em;
font-size: 1.2rem;
&:last-child {
margin-bottom: 0;
}
}
a {
text-decoration: none;
&:hover, &:active {
text-decoration: underline;
}
}
}
@media (min-width: 550px) { @media (min-width: 550px) {
main { main {
&#dashboard { &#dashboard {
-17
View File
@@ -76,22 +76,6 @@ section {
} }
} }
} }
&#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;
}
}
}
} }
@media (min-width: 550px) { @media (min-width: 550px) {
@@ -111,7 +95,6 @@ section {
@import "components/contributor-profile"; @import "components/contributor-profile";
@import "components/external-account-link"; @import "components/external-account-link";
@import "components/loading-spinner"; @import "components/loading-spinner";
@import "components/proposal-list";
@import "components/topbar"; @import "components/topbar";
@import "components/topbar-account-panel"; @import "components/topbar-account-panel";
@import "components/user-avatar"; @import "components/user-avatar";
@@ -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,47 @@ 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;
}
}
}
}
// On small screens, hide intro text, contributor and contributions list when
// showing details
@include media-max(small) {
#dashboard.with-details {
#contributions, #stats {
display: none;
}
}
#intro.with-details {
display: none;
}
} }
@@ -115,37 +115,3 @@ ul.contribution-list {
} }
} }
@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 {
}
}
}
}
@@ -42,6 +42,10 @@ section#contributor-profile {
} }
} }
} }
.actions {
margin-top: 2rem;
}
} }
.actions { .actions {
-111
View File
@@ -1,111 +0,0 @@
ul.proposal-list {
clear: both;
width: 100%;
list-style: none;
li {
display: grid;
grid-template-columns: auto 5rem;
grid-row-gap: 0.5rem;
padding: 1rem 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);
}
p {
align-self: center;
margin: 0;
line-height: 2rem;
&.kredits-amount, &.voting {
text-align: right;
}
&.description {
grid-column-start: span 2;
}
&.voting {
grid-column-start: span 2;
}
}
span {
}
.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: 1rem;
font-weight: 500;
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 {
}
}
}
}
@@ -1,7 +1,17 @@
header#topbar section#user-account { header#topbar section#user-account {
button { button {
margin-left: 1.2rem; margin-left: 1.5rem;
}
button + button {
margin-left: 0.6rem;
}
@include media-max(small) {
.anonymous {
display: none;
}
} }
} }
+1 -1
View File
@@ -1 +1 @@
{{loading-spinner}} <LoadingSpinner />
+2 -2
View File
@@ -1,6 +1,6 @@
<header id="topbar"> <header id="topbar">
<h1>{{link-to "Kosmos Kredits" "dashboard"}}</h1> <h1><LinkTo @route="dashboard">Kosmos Kredits</LinkTo></h1>
{{topbar-account-panel}} <TopbarAccountPanel />
</header> </header>
{{outlet}} {{outlet}}
View File

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

@@ -1,4 +1,4 @@
<svg id="svg825" class="icon-github" width="260" height="260" enable-background="new 0 0 212.4575 186.23" version="1.1" viewBox="0 0 260 260" xml:space="preserve" 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#"> <svg class="icon-github" width="260" height="260" enable-background="new 0 0 212.4575 186.23" version="1.1" viewBox="0 0 260 260" xml:space="preserve" 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 transform="translate(23.766 36.885)"> <g transform="translate(23.766 36.885)">
<path d="m151.79 86.234c-7.078 0.1229-14.154 0.5605-21.232 0.7069-12.318 0.248-24.64 0.5664-36.961 0.512-11.176-0.0472-22.358-0.9728-33.518-0.7052-7.3164 0.1776-14.373 2.2948-20.131 7.584-9.9472 9.1368-12.522 21-11.314 33.807 1.92 20.357 9.2716 31.449 29.115 37.064 15.793 4.4704 31.963 5.2088 48.199 4.9744 5.254 0 10.51 0.1367 15.758-0.0292 12.723-0.4064 25.264-2.2072 37.358-6.3596 10.846-3.7225 18.799-10.691 22.572-22.166 2.6736-8.1288 3.7148-16.388 2.5544-24.853-1.7772-12.959-13.275-30.86-32.4-30.535zm-81.576 59.996c-8.836 0-16-8.9551-16-20 0-11.045 7.164-20 16-20s16 8.9553 16 20c0 11.045-7.164 20-16 20zm76 0c-8.836 0-16-8.9551-16-20 0-11.045 7.164-20 16-20s16 8.9553 16 20c0 11.045-7.164 20-16 20z" fill="none"/> <path d="m151.79 86.234c-7.078 0.1229-14.154 0.5605-21.232 0.7069-12.318 0.248-24.64 0.5664-36.961 0.512-11.176-0.0472-22.358-0.9728-33.518-0.7052-7.3164 0.1776-14.373 2.2948-20.131 7.584-9.9472 9.1368-12.522 21-11.314 33.807 1.92 20.357 9.2716 31.449 29.115 37.064 15.793 4.4704 31.963 5.2088 48.199 4.9744 5.254 0 10.51 0.1367 15.758-0.0292 12.723-0.4064 25.264-2.2072 37.358-6.3596 10.846-3.7225 18.799-10.691 22.572-22.166 2.6736-8.1288 3.7148-16.388 2.5544-24.853-1.7772-12.959-13.275-30.86-32.4-30.535zm-81.576 59.996c-8.836 0-16-8.9551-16-20 0-11.045 7.164-20 16-20s16 8.9553 16 20c0 11.045-7.164 20-16 20zm76 0c-8.836 0-16-8.9551-16-20 0-11.045 7.164-20 16-20s16 8.9553 16 20c0 11.045-7.164 20-16 20z" fill="none"/>
<path class="fg" d="m200.25 59.188c-2.5076-3.4493-4.3632-6.3888-3.8748-11.44 0.6796-7.0664-0.3536-14.396-1.3204-21.518-1.2188-8.9843-3.5236-17.74-7.1776-26.23-9.0332 1.9356-17.981 3.49-25.963 8.0976-8.4648 4.8908-16.695 10.215-25.08 15.25-0.9532 0.5704-2.3124 0.8848-3.3848 0.7032-17.967-3.1368-35.92-3.0196-53.898-0.086-1.3632 0.2244-3.0724-0.2345-4.2948-0.9608-4.4436-2.6604-8.6564-5.7344-13.123-8.3516-11.656-6.844-23.66-12.822-37.494-14.59-0.3928 0.8597-0.7188 1.4785-0.9612 2.1253-4.164 11.22-6.6424 22.844-7.4276 34.82-0.2872 4.3516-0.6092 8.8048 0 13.072 0.3456 2.4296-4e-3 3.8788-1.3924 5.6132-4.8516 6.0488-8.6368 12.717-11.102 20.219-4.6972 14.295-4.4004 28.861-2.2756 43.475 1.7268 11.974 4.7344 23.537 11.324 33.873 13.186 20.682 32.892 29.774 55.572 31.705 19.308 1.6464 38.8 1.1992 58.213 1.2364 13.855 0.0251 27.57-1.4924 40.715-6.6389 20.375-7.9727 33.859-22.604 40.275-44.166 3.7344-12.545 5.2324-25.396 4.8144-38.498-0.4412-13.81-4.0504-26.566-12.144-37.711zm-18.609 82.435c-3.7736 11.475-11.727 18.444-22.572 22.166-12.094 4.1524-24.635 5.9532-37.358 6.3596-5.248 0.1659-10.504 0.0292-15.758 0.0292-16.236 0.2344-32.406-0.504-48.199-4.9744-19.844-5.6152-27.195-16.707-29.115-37.064-1.2072-12.807 1.3672-24.67 11.314-33.807 5.7576-5.2892 12.814-7.4064 20.131-7.584 11.16-0.2676 22.342 0.658 33.518 0.7052 12.32 0.0544 24.642-0.264 36.961-0.512 7.0784-0.1464 14.154-0.584 21.232-0.7069 19.125-0.3243 30.623 17.576 32.4 30.535 1.1604 8.4647 0.1192 16.724-2.5544 24.853z"/> <path class="fg" d="m200.25 59.188c-2.5076-3.4493-4.3632-6.3888-3.8748-11.44 0.6796-7.0664-0.3536-14.396-1.3204-21.518-1.2188-8.9843-3.5236-17.74-7.1776-26.23-9.0332 1.9356-17.981 3.49-25.963 8.0976-8.4648 4.8908-16.695 10.215-25.08 15.25-0.9532 0.5704-2.3124 0.8848-3.3848 0.7032-17.967-3.1368-35.92-3.0196-53.898-0.086-1.3632 0.2244-3.0724-0.2345-4.2948-0.9608-4.4436-2.6604-8.6564-5.7344-13.123-8.3516-11.656-6.844-23.66-12.822-37.494-14.59-0.3928 0.8597-0.7188 1.4785-0.9612 2.1253-4.164 11.22-6.6424 22.844-7.4276 34.82-0.2872 4.3516-0.6092 8.8048 0 13.072 0.3456 2.4296-4e-3 3.8788-1.3924 5.6132-4.8516 6.0488-8.6368 12.717-11.102 20.219-4.6972 14.295-4.4004 28.861-2.2756 43.475 1.7268 11.974 4.7344 23.537 11.324 33.873 13.186 20.682 32.892 29.774 55.572 31.705 19.308 1.6464 38.8 1.1992 58.213 1.2364 13.855 0.0251 27.57-1.4924 40.715-6.6389 20.375-7.9727 33.859-22.604 40.275-44.166 3.7344-12.545 5.2324-25.396 4.8144-38.498-0.4412-13.81-4.0504-26.566-12.144-37.711zm-18.609 82.435c-3.7736 11.475-11.727 18.444-22.572 22.166-12.094 4.1524-24.635 5.9532-37.358 6.3596-5.248 0.1659-10.504 0.0292-15.758 0.0292-16.236 0.2344-32.406-0.504-48.199-4.9744-19.844-5.6152-27.195-16.707-29.115-37.064-1.2072-12.807 1.3672-24.67 11.314-33.807 5.7576-5.2892 12.814-7.4064 20.131-7.584 11.16-0.2676 22.342 0.658 33.518 0.7052 12.32 0.0544 24.642-0.264 36.961-0.512 7.0784-0.1464 14.154-0.584 21.232-0.7069 19.125-0.3243 30.623 17.576 32.4 30.535 1.1604 8.4647 0.1192 16.724-2.5544 24.853z"/>

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Before

Width:  |  Height:  |  Size: 703 B

After

Width:  |  Height:  |  Size: 703 B

@@ -0,0 +1,8 @@
<svg width="256" height="256" version="1.1" viewBox="0 0 67.733 67.733" 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 transform="translate(0 -229.27)">
<g transform="matrix(.90278 0 0 .90278 6.5684 141.05)" fill-rule="evenodd">
<path class="fg" d="m32.67 117.1c2.2056 0.1405 3.0528 0.27041 4.1992 0.64479 3.9359 1.2854 6.7418 4.6736 7.3059 8.8223 0.06615 0.48578 0.13996 1.0253 0.16431 1.1986 0.29104 2.0743 0.07488 21.552-0.25003 22.55-0.59082 1.814-1.901 2.7993-4.0537 3.0488-1.3671 0.15849-30.564 0.0701-31.846-0.0963-5.2843-0.68659-8.8934-4.001-9.7398-8.9445-0.38418-2.2439-0.62362-20.748-0.29871-23.084 0.34422-2.4746 1.7264-3.797 4.3212-4.1338 0.98769-0.12832 28.191-0.13361 30.197-6e-3"/>
<path class="fg" d="m61.114 118.11c0.56621 0.4072 0.97816 1.0565 1.1885 1.874 0.19553 0.75909 0.24474 28.04 0.05371 29.747-0.37333 3.3361-2.6305 4.0137-5.5264 1.6584-7.9722-6.4841-9.021-7.5734-9.6795-10.052-0.26008-0.97895-0.33152-10.629-0.08811-11.876 0.38021-1.9457 1.2594-3.1946 3.7383-5.3099 7.4491-6.3564 7.5914-6.4569 9.0522-6.4008 0.70723 0.0272 0.8599 0.0709 1.2613 0.3593"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+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

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

+3 -1
View File
@@ -6,7 +6,9 @@
</header> </header>
<div class="content"> <div class="content">
{{add-contribution contributors=sortedContributors save=(action "save")}} <AddContribution @contributors={{this.sortedContributors}}
@attributes={{this.model.params}}
@save={{action "save"}} />
</div> </div>
</section> </section>
+15
View File
@@ -0,0 +1,15 @@
<main class="center-column">
<section id="add-contribution">
<header>
<h2>Re-submit contribution #{{this.model.id}}</h2>
</header>
<div class="content">
<AddContribution @attributes={{this.attributes}}
@contributors={{this.sortedContributors}}
@save={{action "save"}} />
</div>
</section>
</main>
+1 -1
View File
@@ -6,7 +6,7 @@
</header> </header>
<div class="content"> <div class="content">
{{add-contributor attributes=attributes save=(action "save")}} <AddContributor @attributes={{this.attributes}} @save={{action "save"}} />
</div> </div>
</section> </section>
+1 -1
View File
@@ -6,7 +6,7 @@
</header> </header>
<div class="content"> <div class="content">
{{add-contributor save=(action "save")}} <AddContributor @save={{action "save"}} />
</div> </div>
</section> </section>
+55 -27
View File
@@ -1,26 +1,44 @@
<main id="dashboard" class={{if showDetailsPane "with-details"}}> {{#if this.showIntroText}}
<div id="intro" class={{if this.showDetailsPane "with-details"}}>
<h2>
Welcome to the contribution dashboard of the
<a href="https://kosmos.org" target="_blank" rel="noreferrer noopener">Kosmos</a> project!
</h2>
<p>
If you want to learn more about what the numbers mean and how this works,
check out the
<a href="https://wiki.kosmos.org/Kredits" target="_blank" rel="noreferrer noopener">Kredits documentation</a>.
If you want to start earning kredits for your contributions,
<LinkTo @route="signup">create a contributor profile</LinkTo>.
</p>
</div>
{{/if}}
<main id="dashboard" class={{if this.showDetailsPane "with-details"}}>
<div id="stats"> <div id="stats">
<section id="people"> <section id="people">
<header class="with-nav"> <header class="with-nav">
<h2>Contributors</h2> <h2>Contributors</h2>
{{#if kredits.hasAccounts}} {{#if this.kredits.hasAccounts}}
<nav> <nav>
{{link-to "add" "contributors.new" title="Add contributor profile" class="button small green"}} <LinkTo @route="contributors.new" @title="Add contributor profile" class="button small green">add</LinkTo>
</nav> </nav>
{{/if}} {{/if}}
</header> </header>
<div class="content"> <div class="content">
{{contributor-list contributorList=kreditsToplist <ContributorList @contributorList={{this.kreditsToplist}}
showUnconfirmedKredits=showUnconfirmedKredits @showUnconfirmedKredits={{this.showUnconfirmedKredits}}
selectedContributorId=selectedContributorId}} @selectedContributorId={{this.selectedContributorId}} />
<p class="stats"> <p class="stats">
<span class="number">{{await kredits.totalKreditsEarned}}</span> kredits confirmed and issued to <span class="number">{{await this.kredits.totalKreditsEarned}}</span> kredits confirmed and issued to
<span class="number">{{contributorsWithKredits.length}}</span> contributors <span class="number">{{this.contributorsWithKredits.length}}</span> contributors
</p> </p>
<p class="stats"> <p class="stats">
{{input type="checkbox" id="hide-unnconfirmed-kredits" checked=showUnconfirmedKredits}} <Input id="hide-unnconfirmed-kredits"
@type="checkbox"
@checked={{this.showUnconfirmedKredits}} />
<label for="hide-unnconfirmed-kredits">Show unconfirmed kredits in toplist</label> <label for="hide-unnconfirmed-kredits">Show unconfirmed kredits in toplist</label>
</p> </p>
</div> </div>
@@ -31,30 +49,36 @@
<h2>Contributions by type</h2> <h2>Contributions by type</h2>
</header> </header>
<div class="content"> <div class="content">
{{chart-contributions-by-type contributions=contributions}} <ChartContributionsByType @contributions={{this.contributions}} />
</div> </div>
</section> </section>
</div> </div>
<div id="contributions"> <div id="contributions">
{{#if contributionsUnconfirmed}} {{#if this.contributionsUnconfirmed}}
<section id="contributions-unconfirmed"> <section id="contributions-unconfirmed">
<header class="with-nav"> <header class="with-nav">
<h2>Latest Contributions</h2> <h2>Latest Contributions</h2>
{{#if kredits.hasAccounts}} <nav>
<nav> <button type="button"
<button {{action "toggleQuickFilterUnconfirmed"}} class="small {{if showQuickFilterUnconfirmed "active"}}">filter</button> onclick={{action "toggleQuickFilterUnconfirmed"}}
{{link-to "add" "contributions.new" title="Submit a contribution" class="button small green"}} class="small {{if this.showQuickFilterUnconfirmed "active"}}">
</nav> filter
{{/if}} </button>
{{#if this.kredits.hasAccounts}}
<LinkTo @route="contributions.new"
@title="Submit a contribution"
class="button small green">add</LinkTo>
{{/if}}
</nav>
</header> </header>
<div class="content"> <div class="content">
{{!-- TODO: We need a better naming for kredits.hasAccounts --}} {{!-- TODO: We need a better naming for kredits.hasAccounts --}}
{{contribution-list contributions=contributionsUnconfirmedSorted <ContributionList @contributions={{this.contributionsUnconfirmedSorted}}
vetoContribution=(action "vetoContribution") @vetoContribution={{action "vetoContribution"}}
contractInteractionEnabled=kredits.hasAccounts @contractInteractionEnabled={{this.kredits.hasAccounts}}
selectedContributionId=selectedContributionId @selectedContributionId={{this.selectedContributionId}}
showQuickFilter=showQuickFilterUnconfirmed}} @showQuickFilter={{this.showQuickFilterUnconfirmed}} />
</div> </div>
</section> </section>
{{/if}} {{/if}}
@@ -63,14 +87,18 @@
<header class="with-nav"> <header class="with-nav">
<h2>Confirmed Contributions</h2> <h2>Confirmed Contributions</h2>
<nav> <nav>
<button {{action "toggleQuickFilterConfirmed"}} class="small {{if showQuickFilterConfirmed "active"}}">filter</button> <button type="button"
onclick={{action "toggleQuickFilterConfirmed"}}
class="small {{if this.showQuickFilterConfirmed "active"}}">
filter
</button>
</nav> </nav>
</header> </header>
<div class="content"> <div class="content">
{{contribution-list contributions=contributionsConfirmedSorted <ContributionList @contributions={{this.contributionsConfirmedSorted}}
vetoContribution=(action "vetoContribution") @vetoContribution={{action "vetoContribution"}}
selectedContributionId=selectedContributionId @selectedContributionId={{this.selectedContributionId}}
showQuickFilter=showQuickFilterConfirmed}} @showQuickFilter={{this.showQuickFilterConfirmed}} />
</div> </div>
</section> </section>
</div> </div>
+31 -16
View File
@@ -1,8 +1,8 @@
<section id="contribution-details"> <section id="contribution-details" class={{if this.model.vetoed "vetoed"}}>
<header class="with-nav"> <header class="with-nav">
<h2>Contribution #{{model.id}}</h2> <h2>Contribution #{{this.model.id}}</h2>
<nav> <nav>
<span class="amount">{{model.amount}}</span>&nbsp; <span class="amount">{{this.model.amount}}</span>&nbsp;
<span class="symbol">₭S</span> <span class="symbol">₭S</span>
</nav> </nav>
</header> </header>
@@ -10,35 +10,50 @@
<div class="content"> <div class="content">
<p class="who-what-when"> <p class="who-what-when">
<span class="contributor"> <span class="contributor">
{{user-avatar contributor=model.contributor}} <UserAvatar @contributor={{this.model.contributor}} />
{{link-to model.contributor.name "dashboard.contributors.show" model.contributor}} <LinkTo @route="dashboard.contributors.show" @model={{this.model.contributor}}>{{this.model.contributor.name}}</LinkTo>
</span> </span>
contributed contributed
<span class="date" title={{model.iso8601Date}}>{{moment-from model.iso8601Date}}</span>: <span class="date" title={{this.model.iso8601Date}}>{{moment-from this.model.iso8601Date}}</span>:
</p> </p>
<h3>{{model.description}}</h3> <h3>{{this.model.description}}</h3>
<p> <p>
Kind: {{model.kind}} Kind: {{this.model.kind}}
<br>Status: {{contribution-status model}} <br>Status: {{contribution-status this.model}}
</p> </p>
{{#if model.url}} {{#if this.model.url}}
<p> <p>
<a href={{model.url}} <a href={{this.model.url}}
title={{model.description}} title={{this.model.description}}
class="button" class="button"
target="_blank" target="_blank"
rel="noopener"> rel="noopener noreferrer">
Open URL Open URL
</a> </a>
</p> </p>
{{/if}} {{/if}}
{{#if this.model.vetoed}}
<div class="hint vetoed">
<div class="icon">
<IconWarning />
</div>
<p>
This contribution has been vetoed, meaning no
kredits will be issued.
</p>
<p>
<LinkTo @route="contributions.resubmit" @model={{this.model}} class="button small green">Re-submit contribution …</LinkTo>
</p>
</div>
{{/if}}
</div> </div>
<div class="actions"> <div class="actions">
<p> <p>
{{#if model.ipfsHash}} <LinkTo @route="contributions.resubmit" @model={{this.model}} class="button small">Copy & edit as new</LinkTo>
<a href="https://ipfs.io/ipfs/{{model.ipfsHash}}" {{#if this.model.ipfsHash}}
class="button small" target="_blank" rel="noopener"> <a href="{{this.ipfsGatewayUrl}}/{{this.model.ipfsHash}}"
class="button small" target="_blank" rel="noopener noreferrer">
Inspect IPFS data Inspect IPFS data
</a> </a>
{{/if}} {{/if}}
+17 -12
View File
@@ -1,36 +1,41 @@
<section id="contributor-profile"> <section id="contributor-profile">
<header> <header>
{{user-avatar contributor=model size="medium"}} <UserAvatar @contributor={{this.model}} @size="medium" />
</header> </header>
<div class="content"> <div class="content">
<h2>{{model.name}}</h2> <h2>{{this.model.name}}</h2>
<p class="role">{{roleName}}</p> <p class="role">{{this.roleName}}</p>
<ul class="external-accounts"> <ul class="external-accounts">
{{#each model.accounts as |account|}} {{#each this.model.accounts as |account|}}
<li> <li>
{{external-account-link account=account}} <ExternalAccountLink @account={{account}} />
</li> </li>
{{/each}} {{/each}}
{{#if model.url}} {{#if this.model.url}}
<li> <li>
<a href={{model.url}} target="_blank" rel="noopener" title="Website"> <a href={{this.model.url}} target="_blank" rel="noopener noreferrer" title="Website">
<span class="site">Web</span> <span class="site">Web</span>
{{icon-web-globe}} <IconWebGlobe />
</a> </a>
</li> </li>
{{/if}} {{/if}}
</ul> </ul>
<div class="actions">
<p>
<LinkTo @route="contributions.new" @query={{hash contributorId=this.model.id}} class="button green">♥ Give kredits</LinkTo>
</p>
</div>
</div> </div>
<div class="actions"> <div class="actions">
<p> <p>
<a href="https://rinkeby.etherscan.io/address/{{model.account}}" class="button small" target="_blank" rel="noopener">Inspect Ethereum transactions</a> <a href="https://rinkeby.etherscan.io/address/{{this.model.account}}" class="button small" target="_blank" rel="noopener noreferrer">Inspect Ethereum transactions</a>
{{#if model.ipfsHash}} {{#if this.model.ipfsHash}}
<a href="https://ipfs.io/ipfs/{{model.ipfsHash}}" class="button small" target="_blank" rel="noopener">Inspect IPFS profile</a> <a href="{{this.ipfsGatewayUrl}}/{{this.model.ipfsHash}}" class="button small" target="_blank" rel="noopener noreferrer">Inspect IPFS profile</a>
{{/if}} {{/if}}
{{link-to "Edit profile" "contributors.edit" model class="button small"}} <LinkTo @route="contributors.edit" @model={{this.model}} class="button small">Edit profile</LinkTo>
</p> </p>
</div> </div>
</section> </section>
-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 -1
View File
@@ -10,6 +10,6 @@
<a href="https://wiki.kosmos.org/Main_Page#Community_.2F_Getting_in_touch_.2F_Getting_involved">in one of our chat rooms</a>?. <a href="https://wiki.kosmos.org/Main_Page#Community_.2F_Getting_in_touch_.2F_Getting_involved">in one of our chat rooms</a>?.
</p> </p>
<p class="actions"> <p class="actions">
{{#link-to "dashboard" class="button small"}}Return to dashboard{{/link-to}} <LinkTo @route="dashboard" class="button small">Return to dashboard</LinkTo>
</p> </p>
</div> </div>
+5 -6
View File
@@ -6,19 +6,18 @@
Kredits allow you to take part in project governance, and to earn rewards for Kredits allow you to take part in project governance, and to earn rewards for
your contributions. For both, you will need an Ethereum wallet/account. your contributions. For both, you will need an Ethereum wallet/account.
</p> </p>
<form {{action "submit" on="submit"}}> <form>
<p> <p>
<label> <label>
Ethereum account:<br> Ethereum account:<br>
{{input type="text" value=ethAddress <Input @type="text" @value={{this.ethAddress}} placeholder="0xF18E631Ea191aE4ebE70046Fcb01a436554421BA4" class={{if this.isValidEthAccount "valid" ""}} />
placeholder="0xF18E631Ea191aE4ebE70046Fcb01a436554421BA4"
class=(if isValidEthAccount "valid" "")}}
</label> </label>
</p> </p>
</form> </form>
<p class="actions"> <p class="actions">
<button disabled={{signupButtonDisabled}} <button disabled={{this.signupButtonDisabled}}
{{action "completeSignup"}}> onclick={{action "completeSignup"}}
type="button">
Complete my profile Complete my profile
</button> </button>
</p> </p>
+2 -2
View File
@@ -12,8 +12,8 @@
connecting one of the following accounts: connecting one of the following accounts:
</p> </p>
<p class="actions"> <p class="actions">
<button {{action "connectGithub"}} class="icon"> <button onclick={{action "connectGithub"}} class="icon" type="button">
{{icon-account-github-com}} <IconAccountGithubCom />
Connect GitHub Connect GitHub
</button> </button>
</p> </p>
+20
View File
@@ -0,0 +1,20 @@
{
"schemaVersion": "1.0.0",
"packages": [
{
"name": "ember-cli",
"version": "3.18.0",
"blueprints": [
{
"name": "app",
"outputRepo": "https://github.com/ember-cli/ember-new-output",
"codemodsSource": "ember-app-codemods-manifest@1",
"isBaseBlueprint": true,
"options": [
"--no-welcome"
]
}
]
}
]
}
+2 -5
View File
@@ -36,6 +36,7 @@ module.exports = function(environment) {
}, },
web3ProviderUrl: 'https://rinkeby.infura.io/v3/d4f788b7a6584f7db2fc3c268d4d09e9', web3ProviderUrl: 'https://rinkeby.infura.io/v3/d4f788b7a6584f7db2fc3c268d4d09e9',
web3RequiredNetwork: 'rinkeby',
githubConnectUrl: 'https://hal8000.chat.kosmos.org/kredits/signup/connect/github', githubConnectUrl: 'https://hal8000.chat.kosmos.org/kredits/signup/connect/github',
githubSignupUrl: 'https://hal8000.chat.kosmos.org/kredits/signup/github', githubSignupUrl: 'https://hal8000.chat.kosmos.org/kredits/signup/github',
@@ -79,13 +80,9 @@ module.exports = function(environment) {
ENV.APP.autoboot = false; 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) { if (process.env.WEB3_PROVIDER_URL) {
ENV.web3ProviderUrl = process.env.WEB3_PROVIDER_URL; ENV.web3ProviderUrl = process.env.WEB3_PROVIDER_URL;
ENV.web3RequiredNetwork = null;
} }
if (process.env.KREDITS_DAO_ADDRESS) { if (process.env.KREDITS_DAO_ADDRESS) {
ENV.kreditsKernelAddress = process.env.KREDITS_DAO_ADDRESS; ENV.kreditsKernelAddress = process.env.KREDITS_DAO_ADDRESS;
+4 -1
View File
@@ -1,3 +1,6 @@
{ {
"jquery-integration": true "application-template-wrapper": false,
"default-async-observers": true,
"jquery-integration": false,
"template-only-glimmer-components": true
} }
+8928 -2975
View File
File diff suppressed because it is too large Load Diff
+43 -35
View File
@@ -1,6 +1,6 @@
{ {
"name": "kredits-web", "name": "kredits-web",
"version": "1.9.0", "version": "1.16.0",
"private": true, "private": true,
"description": "Contribution dashboard of the Kosmos project", "description": "Contribution dashboard of the Kosmos project",
"repository": "https://github.com/67P/kredits-web", "repository": "https://github.com/67P/kredits-web",
@@ -11,12 +11,14 @@
"test": "tests" "test": "tests"
}, },
"scripts": { "scripts": {
"lint": "npm-run-all --aggregate-output --continue-on-error --parallel lint:*",
"lint:hbs": "ember-template-lint .", "lint:hbs": "ember-template-lint .",
"lint:js": "eslint .", "lint:js": "eslint .",
"test": "ember test", "start": "ember serve",
"start": "KREDITS_APM_DOMAIN=open.aragonpm.eth ember serve", "test": "npm-run-all lint:* test:*",
"start:local": "WEB3_PROVIDER_URL=http://localhost:7545 ember s", "test:ember": "ember test",
"build": "ember build", "start:local": "WEB3_PROVIDER_URL=http://localhost:7545 ember serve",
"build": "ember build --environment=production",
"build-prod": "rm -rf release/* && ember build -prod --output-path release", "build-prod": "rm -rf release/* && ember build -prod --output-path release",
"preversion": "npm test", "preversion": "npm test",
"version": "npm run build-prod && git add release/", "version": "npm run build-prod && git add release/",
@@ -24,53 +26,59 @@
"deploy": "git push 5apps master" "deploy": "git push 5apps master"
}, },
"devDependencies": { "devDependencies": {
"@ember/jquery": "^0.6.0", "@ember/optional-features": "^1.3.0",
"@ember/optional-features": "^0.7.0", "@glimmer/component": "^1.0.0",
"@glimmer/tracking": "^1.0.0",
"babel-eslint": "^10.1.0",
"babel-preset-es2015": "^6.22.0", "babel-preset-es2015": "^6.22.0",
"babelify": "^7.3.0", "babelify": "^7.3.0",
"brfs": "^2.0.2", "brfs": "^2.0.2",
"broccoli-asset-rev": "^3.0.0", "broccoli-asset-rev": "^3.0.0",
"ember-ajax": "^5.0.0", "ember-auto-import": "^1.5.3",
"ember-auto-import": "^1.5.2",
"ember-awesome-macros": "0.41.0", "ember-awesome-macros": "0.41.0",
"ember-cli": "~3.10.1", "ember-cli": "~3.18.0",
"ember-cli-app-version": "^3.2.0", "ember-cli-app-version": "^3.2.0",
"ember-cli-babel": "^7.7.3", "ember-cli-babel": "^7.19.0",
"ember-cli-chart": "^3.4.0", "ember-cli-chart": "^3.6.0",
"ember-cli-dependency-checker": "^3.1.0", "ember-cli-dependency-checker": "^3.2.0",
"ember-cli-eslint": "^5.1.0", "ember-cli-htmlbars": "^4.3.1",
"ember-cli-htmlbars": "^3.0.1", "ember-cli-inject-live-reload": "^2.0.2",
"ember-cli-htmlbars-inline-precompile": "^2.1.0",
"ember-cli-inject-live-reload": "^1.8.2",
"ember-cli-moment-shim": "^3.7.1", "ember-cli-moment-shim": "^3.7.1",
"ember-cli-sass": "^7.2.0", "ember-cli-sass": "^10.0.1",
"ember-cli-sri": "^2.1.1", "ember-cli-sri": "^2.1.1",
"ember-cli-template-lint": "^1.0.0-beta.1", "ember-cli-uglify": "^3.0.0",
"ember-cli-uglify": "^2.1.0", "ember-export-application-global": "^2.0.1",
"ember-export-application-global": "^2.0.0", "ember-fetch": "^8.0.1",
"ember-flatpickr": "^2.14.0", "ember-flatpickr": "^2.16.2",
"ember-load-initializers": "^2.0.0", "ember-load-initializers": "^2.1.1",
"ember-macro-helpers": "0.17.0", "ember-macro-helpers": "0.17.0",
"ember-maybe-import-regenerator": "^0.1.6", "ember-maybe-import-regenerator": "^0.1.6",
"ember-moment": "^7.8.1", "ember-moment": "^7.8.1",
"ember-promise-helpers": "1.0.6", "ember-promise-helpers": "^1.0.9",
"ember-qunit": "^4.4.1", "ember-qunit": "^4.6.0",
"ember-resolver": "^5.0.1", "ember-resolver": "^8.0.0",
"ember-source": "~3.10.0", "ember-source": "~3.18.0",
"ember-template-lint": "^2.6.0",
"ember-truth-helpers": "github:jmurphyau/ember-truth-helpers#31a14373a31f1f82c77537720549b47a95c28e5f", "ember-truth-helpers": "github:jmurphyau/ember-truth-helpers#31a14373a31f1f82c77537720549b47a95c28e5f",
"eslint-plugin-ember": "^6.2.0", "eslint": "^7.0.0",
"eslint-plugin-node": "^9.0.1", "eslint-plugin-ember": "^8.4.0",
"ethers": "^4.0.27", "eslint-plugin-node": "^11.1.0",
"kosmos-schemas": "^2.0.0", "ethers": "^4.0.47",
"kredits-contracts": "^5.4.0", "kosmos-schemas": "^2.1.0",
"kredits-contracts": "^5.5.0",
"loader.js": "^4.7.0", "loader.js": "^4.7.0",
"ndjson": "github:hugomrdias/ndjson#feat/readable-stream3", "ndjson": "github:hugomrdias/ndjson#feat/readable-stream3",
"qunit-dom": "^0.8.4", "npm-run-all": "^4.1.5",
"qunit-dom": "^1.2.0",
"sass": "^1.26.5",
"transform-loader": "^0.2.4", "transform-loader": "^0.2.4",
"tv4": "^1.3.0", "tv4": "^1.3.0",
"web3-utils": "^1.0.0" "web3-utils": "^1.2.7"
}, },
"engines": { "engines": {
"node": "8.* || >= 10.*" "node": "10.* || >= 12"
},
"ember": {
"edition": "octane"
} }
} }
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
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
File diff suppressed because one or more lines are too long
+5 -5
View File
@@ -8,10 +8,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> <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%2C%22_JQUERY_INTEGRATION%22%3Atrue%7D%2C%22APP%22%3A%7B%22name%22%3A%22kredits-web%22%2C%22version%22%3A%221.9.0%2B9bf2ae2d%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%22githubConnectUrl%22%3A%22https%3A%2F%2Fhal8000.chat.kosmos.org%2Fkredits%2Fsignup%2Fconnect%2Fgithub%22%2C%22githubSignupUrl%22%3A%22https%3A%2F%2Fhal8000.chat.kosmos.org%2Fkredits%2Fsignup%2Fgithub%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%2C%22gatewayUrl%22%3A%22https%3A%2F%2Fipfs.kosmos.org%2Fipfs%22%7D%2C%22kreditsApmDomain%22%3A%22open.aragonpm.eth%22%2C%22exportApplicationGlobal%22%3Afalse%7D" /> <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%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_DEFAULT_ASYNC_OBSERVERS%22%3Atrue%2C%22_JQUERY_INTEGRATION%22%3Afalse%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22name%22%3A%22kredits-web%22%2C%22version%22%3A%221.16.0%2B41cc37d3%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%22web3RequiredNetwork%22%3A%22rinkeby%22%2C%22githubConnectUrl%22%3A%22https%3A%2F%2Fhal8000.chat.kosmos.org%2Fkredits%2Fsignup%2Fconnect%2Fgithub%22%2C%22githubSignupUrl%22%3A%22https%3A%2F%2Fhal8000.chat.kosmos.org%2Fkredits%2Fsignup%2Fgithub%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%2C%22gatewayUrl%22%3A%22https%3A%2F%2Fipfs.kosmos.org%2Fipfs%22%7D%2C%22exportApplicationGlobal%22%3Afalse%7D" />
<link integrity="" rel="stylesheet" href="/assets/vendor-179cf27a97ea5bbb0ce72403a401cc8c.css"> <link integrity="" rel="stylesheet" href="/assets/vendor-ca96b2e19fc9f356e3dbad90c9f3f323.css">
<link integrity="" rel="stylesheet" href="/assets/kredits-web-c870e46b48f385300f37386e5ce5b3a6.css"> <link integrity="" rel="stylesheet" href="/assets/kredits-web-8440190dda6de1748075524fe140b4ee.css">
@@ -24,8 +24,8 @@
<body> <body>
<script src="/assets/vendor-765025e7de61c40a38fb3d7f2c93d4aa.js" integrity="sha256-/Qtv1B7vhqswTyQR74IPIUbG3346Xqb94WqJleIR3v4= sha512-T77HNtXJ47uJ90fMPppaFIoPzyymEX1ZWVkVOkuDWCA/miwGZXeJreaMsE++XphOLB8hvHm26eORNOJECPC37g==" ></script> <script src="/assets/vendor-5ebca0a713676bf484d729ec58e9d74b.js" integrity="sha256-K9BPrQzg0Nv83HSPUwk2n1hU8IOaceDf03EaU5LgblQ= sha512-stOJYOdJfiuzleqChwK9pNLCVMQwg9sZXUSboTsvtIixnRoQ285yS080rRX/GfcRd/eI0TEpPI0XKqvN56kzLA==" ></script>
<script src="/assets/kredits-web-788265737118a90913112fa6ebe6b8f5.js" integrity="sha256-ey9RABp1iJ86aXudb96KujZGI4jaUU1Ng3W4Cx1Cqg0= sha512-MCgoD4+VRdwXCLq2rZc4AOhchBv+wZ/RCpfvfUaCtiUk5VCktp3Lrf7vy6dn++LmQUtx3yVHw/oRmRyLH7tW2A==" ></script> <script src="/assets/kredits-web-d376614e43d3edec456b90f7efdfedf4.js" integrity="sha256-ZUj9gy+521ioE0n+gKl53UrRqVALwY7YTOonD2SjZfg= sha512-0G4MUqxkZ+yazboR03+jfA9BRKoyKh2/IgG9iAVttTfVZRyMTHqiFnGlG00KY72H0y2jVamQtgY6UpLgAohGLg==" ></script>
</body> </body>
+3 -1
View File
@@ -1,3 +1,5 @@
'use strict';
module.exports = { module.exports = {
test_page: 'tests/index.html?hidepassed', test_page: 'tests/index.html?hidepassed',
disable_watching: true, disable_watching: true,
@@ -7,13 +9,13 @@ module.exports = {
launch_in_dev: [ launch_in_dev: [
'Chrome' 'Chrome'
], ],
browser_start_timeout: 120,
browser_args: { browser_args: {
Chrome: { Chrome: {
ci: [ ci: [
// --no-sandbox is needed when running Chrome inside a container // --no-sandbox is needed when running Chrome inside a container
process.env.CI ? '--no-sandbox' : null, process.env.CI ? '--no-sandbox' : null,
'--headless', '--headless',
'--disable-gpu',
'--disable-dev-shm-usage', '--disable-dev-shm-usage',
'--disable-software-rasterizer', '--disable-software-rasterizer',
'--mute-audio', '--mute-audio',
@@ -1,18 +0,0 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
module('Integration | Component | add proposal', function(hooks) {
setupRenderingTest(hooks);
test('it renders', async function(assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.on('myAction', function(val) { ... });
await render(hbs`{{add-proposal}}`);
assert.dom('.actions a').hasText('Back');
});
});
@@ -6,7 +6,7 @@ import hbs from 'htmlbars-inline-precompile';
module('Integration | Component | chart-contributions-by-type', function(hooks) { module('Integration | Component | chart-contributions-by-type', function(hooks) {
setupRenderingTest(hooks); setupRenderingTest(hooks);
let proposals = [ let contributions = [
{ kind: 'dev', amount: 500 }, { kind: 'dev', amount: 500 },
{ kind: 'dev', amount: 1500 }, { kind: 'dev', amount: 1500 },
{ kind: 'ops', amount: 1500 }, { kind: 'ops', amount: 1500 },
@@ -20,9 +20,9 @@ module('Integration | Component | chart-contributions-by-type', function(hooks)
]; ];
test('it renders', async function(assert) { test('it renders', async function(assert) {
this.set('proposals', proposals); this.set('contributions', contributions);
await render(hbs`{{chart-contributions-by-type contributions=proposals}}`); await render(hbs`{{chart-contributions-by-type contributions=contributions}}`);
assert.dom(this.element).hasText(''); assert.dom(this.element).hasText('');
}); });
@@ -1,18 +0,0 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
module('Integration | Component | proposal list', function(hooks) {
setupRenderingTest(hooks);
test('it renders', async function(assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.on('myAction', function(val) { ... });
await render(hbs`{{proposal-list}}`);
assert.dom('*').hasText('');
});
});
@@ -29,7 +29,7 @@ module('Integration | Component | topbar-account-panel', function(hooks) {
}); });
await render(hbs`<TopbarAccountPanel />`); await render(hbs`<TopbarAccountPanel />`);
assert.equal(this.element.textContent.trim(), 'Dorian Nakamoto'); assert.dom(this.element).hasText('Dorian Nakamoto');
service.set('currentUser.isCore', true); service.set('currentUser.isCore', true);
await render(hbs`<TopbarAccountPanel />`); await render(hbs`<TopbarAccountPanel />`);
@@ -0,0 +1,41 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import moment from 'moment';
module('Unit | Component | add-contribution', function(hooks) {
setupTest(hooks);
test('it exists', function(assert) {
let component = this.owner.factoryFor('component:add-contribution').create();
assert.ok(component);
});
test('default attributes', function(assert) {
let component = this.owner.factoryFor('component:add-contribution').create();
['contributorId', 'kind', 'amount', 'description', 'url', 'details'].forEach(a => {
assert.equal(component.attributes[a], null, `sets the default ${a} attribute`);
assert.equal(component.get(a), null, `sets the ${a} property`);
});
assert.ok(moment.isDate(component.attributes.date), 'sets the default date attribute');
assert.ok(moment.isDate(component.date), 'sets the default date');
});
test('override default attributes', function(assert) {
let component = this.owner.factoryFor('component:add-contribution').create({
attributes: { contributorId: '1' }
});
assert.equal(component.contributorId, '1', `overrides the default property`);
['kind', 'amount', 'description', 'url', 'details'].forEach(a => {
assert.equal(component.attributes[a], null, `sets the default ${a} attribute`);
assert.equal(component.get(a), null, `sets the ${a} property`);
});
assert.ok(moment.isDate(component.attributes.date), 'sets the default date attribute');
assert.ok(moment.isDate(component.date), 'sets the default date');
});
});
@@ -1,12 +0,0 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Controller | proposals/new', function(hooks) {
setupTest(hooks);
// Replace this with your real tests.
test('it exists', function(assert) {
let controller = this.owner.lookup('controller:proposals/new');
assert.ok(controller);
});
});
@@ -0,0 +1,22 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import Contribution from 'kredits-web/models/contribution';
module('Unit | Helper | contribution-status', function (hooks) {
setupTest(hooks);
test('returns the appropriate status', function (assert) {
const contributionStatus = this.owner.factoryFor('helper:contribution-status').create();
const kredits = this.owner.lookup('service:kredits');
kredits.set('currentBlock', 23000);
const contributionUnconfirmed = Contribution.create({ confirmedAt: 23001, vetoed: false });
const contributionConfirmed = Contribution.create({ confirmedAt: 21000, vetoed: false });
const contributionVetoed = Contribution.create({ confirmedAt: 23001, vetoed: true });
assert.equal(contributionStatus.compute([contributionUnconfirmed]), 'unconfirmed');
assert.equal(contributionStatus.compute([contributionConfirmed]), 'confirmed');
assert.equal(contributionStatus.compute([contributionVetoed]), 'vetoed');
});
});

Some files were not shown because too many files have changed in this diff Show More