From 769317777ceff35371fdf6cb327abe07bf2a3468 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 18 Jun 2020 15:25:03 +0200 Subject: [PATCH 01/57] Refactor routes * Add specific dashboard route * Port application route to Octane * Fetch/sync contributors in application route, but only sync contributions in dashboard route for now --- app/routes/application.js | 40 +++++++++++++---------------- app/routes/dashboard.js | 18 +++++++++++++ tests/unit/routes/dashboard-test.js | 11 ++++++++ 3 files changed, 47 insertions(+), 22 deletions(-) create mode 100644 app/routes/dashboard.js create mode 100644 tests/unit/routes/dashboard-test.js diff --git a/app/routes/application.js b/app/routes/application.js index 92f0e9d..638ddd3 100644 --- a/app/routes/application.js +++ b/app/routes/application.js @@ -1,39 +1,35 @@ -import { inject as service } from '@ember/service'; import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; import { schedule } from '@ember/runloop'; -export default Route.extend({ - kredits: service(), +export default class ApplicationRoute extends Route { + + @service kredits; beforeModel(/* transition */) { const kredits = this.kredits; return kredits.setup().then(() => { - kredits.get('kredits').preflightChecks().catch((error) => { + kredits.kredits.preflightChecks().catch((error) => { console.error('Kredits preflight check failed!'); console.error(error); }); }).catch((error) => { console.log('Error initializing Kredits', error); }); - }, + } + + model() { + return this.kredits.loadInitialData().then(() => { + this.kredits.addContractEventHandlers() + }); + } afterModel() { - return this.kredits.loadInitialData() - .then(() => { - this.kredits.addContractEventHandlers(); - }) - .then(() => { - if (this.kredits.contributorsNeedSync) { - schedule('afterRender', this.kredits.syncContributors, - this.kredits.syncContributors.perform); - } - if (this.kredits.contributionsNeedSync) { - schedule('afterRender', this.kredits.syncContributions, - this.kredits.syncContributions.perform); - } - schedule('afterRender', this.kredits.fetchMissingContributions, - this.kredits.fetchMissingContributions.perform); - }); + if (this.kredits.contributorsNeedSync) { + schedule('afterRender', this.kredits.syncContributors, + this.kredits.syncContributors.perform); + } } -}); + +} diff --git a/app/routes/dashboard.js b/app/routes/dashboard.js new file mode 100644 index 0000000..a6b1d4e --- /dev/null +++ b/app/routes/dashboard.js @@ -0,0 +1,18 @@ +import Route from '@ember/routing/route'; +import { schedule } from '@ember/runloop'; +import { inject as service } from '@ember/service'; + +export default class DashboardRoute extends Route { + + @service kredits; + + afterModel() { + if (this.kredits.contributionsNeedSync) { + schedule('afterRender', this.kredits.syncContributions, + this.kredits.syncContributions.perform); + } + schedule('afterRender', this.kredits.fetchMissingContributions, + this.kredits.fetchMissingContributions.perform); + } + +} diff --git a/tests/unit/routes/dashboard-test.js b/tests/unit/routes/dashboard-test.js new file mode 100644 index 0000000..26accbd --- /dev/null +++ b/tests/unit/routes/dashboard-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | dashboard', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:dashboard'); + assert.ok(route); + }); +}); From 3b127b0e81ba7f9915df5bf83b7eb814480356ed Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Sat, 27 Jun 2020 13:36:28 +0200 Subject: [PATCH 02/57] WIP Budget route and basic layout --- app/router.js | 3 ++ app/routes/budget.js | 4 ++ app/routes/budget/expenses.js | 4 ++ app/templates/budget.hbs | 50 +++++++++++++++++++++++ app/templates/budget/expenses.hbs | 1 + jsconfig.json | 5 +++ tests/unit/routes/budget-test.js | 11 +++++ tests/unit/routes/budget/expenses-test.js | 11 +++++ 8 files changed, 89 insertions(+) create mode 100644 app/routes/budget.js create mode 100644 app/routes/budget/expenses.js create mode 100644 app/templates/budget.hbs create mode 100644 app/templates/budget/expenses.hbs create mode 100644 jsconfig.json create mode 100644 tests/unit/routes/budget-test.js create mode 100644 tests/unit/routes/budget/expenses-test.js diff --git a/app/router.js b/app/router.js index 578bb62..52d8cf8 100644 --- a/app/router.js +++ b/app/router.js @@ -29,4 +29,7 @@ Router.map(function() { this.route('eth-account'); this.route('complete'); }); + this.route('budget', function() { + this.route('expenses'); + }); }); diff --git a/app/routes/budget.js b/app/routes/budget.js new file mode 100644 index 0000000..551250a --- /dev/null +++ b/app/routes/budget.js @@ -0,0 +1,4 @@ +import Route from '@ember/routing/route'; + +export default class BudgetRoute extends Route { +} diff --git a/app/routes/budget/expenses.js b/app/routes/budget/expenses.js new file mode 100644 index 0000000..7eb9882 --- /dev/null +++ b/app/routes/budget/expenses.js @@ -0,0 +1,4 @@ +import Route from '@ember/routing/route'; + +export default class BudgetExpensesRoute extends Route { +} diff --git a/app/templates/budget.hbs b/app/templates/budget.hbs new file mode 100644 index 0000000..eade3ae --- /dev/null +++ b/app/templates/budget.hbs @@ -0,0 +1,50 @@ +
+ + + +
+
+

Community funds

+
+
+ + + + + + + + + + + + + + + + + + + + +
TokenAmountFiat value
WBTC1.1721511031.15 USD
ETH0.5115.60 USD
+
+
+ + {{outlet}} + +
\ No newline at end of file diff --git a/app/templates/budget/expenses.hbs b/app/templates/budget/expenses.hbs new file mode 100644 index 0000000..e2147ca --- /dev/null +++ b/app/templates/budget/expenses.hbs @@ -0,0 +1 @@ +{{outlet}} \ No newline at end of file diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..504cd64 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "experimentalDecorators": true + } +} diff --git a/tests/unit/routes/budget-test.js b/tests/unit/routes/budget-test.js new file mode 100644 index 0000000..122704e --- /dev/null +++ b/tests/unit/routes/budget-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | budget', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:budget'); + assert.ok(route); + }); +}); diff --git a/tests/unit/routes/budget/expenses-test.js b/tests/unit/routes/budget/expenses-test.js new file mode 100644 index 0000000..c79b55e --- /dev/null +++ b/tests/unit/routes/budget/expenses-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | budget/expenses', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:budget/expenses'); + assert.ok(route); + }); +}); From 4a9dd5ff09167e919e9bbb49262dddd52407b54d Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Sat, 27 Jun 2020 14:01:05 +0200 Subject: [PATCH 03/57] Re-organize functions of kredits service --- app/services/kredits.js | 126 +++++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 61 deletions(-) diff --git a/app/services/kredits.js b/app/services/kredits.js index e892f56..eac93a0 100644 --- a/app/services/kredits.js +++ b/app/services/kredits.js @@ -38,50 +38,6 @@ export default Service.extend({ contributorsNeedSync: false, contributionsNeedSync: false, - contributionsUnconfirmed: computed('contributions.[]', 'currentBlock', function() { - return this.contributions.filter(contribution => { - return contribution.confirmedAt > this.currentBlock; - }); - }), - - contributionsConfirmed: computed('contributions.[]', 'currentBlock', function() { - return this.contributions - .filterBy('vetoed', false) - .filter(contribution => { - return contribution.confirmedAt <= this.currentBlock; - }); - }), - - kreditsByContributor: computed('contributionsUnconfirmed.@each.vetoed', 'contributors.[]', function() { - const contributionsUnconfirmed = this.contributionsUnconfirmed.filterBy('vetoed', false); - const contributionsGrouped = groupBy(contributionsUnconfirmed, 'contributorId'); - const contributorsWithUnconfirmed = contributionsGrouped.map(c => c.value.toString()); - const contributorsWithOnlyConfirmed = this.contributors.reject(c => contributorsWithUnconfirmed.includes(c.id)) - - const kreditsByContributor = contributionsGrouped.map(c => { - const amountUnconfirmed = c.items.mapBy('amount').reduce((a, b) => a + b); - const contributor = this.contributors.findBy('id', c.value.toString()); - - return EmberObject.create({ - contributor: contributor, - amountUnconfirmed: amountUnconfirmed, - amountConfirmed: contributor.totalKreditsEarned, - amountTotal: contributor.totalKreditsEarned + amountUnconfirmed - }) - }); - - contributorsWithOnlyConfirmed.forEach(c => { - kreditsByContributor.push(EmberObject.create({ - contributor: c, - amountUnconfirmed: 0, - amountConfirmed: c.totalKreditsEarned, - amountTotal: c.totalKreditsEarned - })); - }) - - return kreditsByContributor; - }), - init () { this._super(...arguments); this.set('contributors', []); @@ -168,6 +124,22 @@ export default Service.extend({ }); }, + getCurrentUser: computed('kredits.provider', 'currentUserAccounts.[]', function() { + if (isEmpty(this.currentUserAccounts)) { + return Promise.resolve(); + } + return this.kredits.Contributor + .functions.getContributorIdByAddress(this.currentUserAccounts.firstObject) + .then((id) => { + // check if the user is a contributor or not + if (id === 0) { + return Promise.resolve(); + } else { + return this.kredits.Contributor.getById(id); + } + }); + }), + totalSupply: computed(function() { return this.kredits.Token.functions.totalSupply().then(total => { return formatKredits(total); @@ -179,6 +151,51 @@ export default Service.extend({ .then(total => total.toNumber()); }), + kreditsByContributor: computed('contributionsUnconfirmed.@each.vetoed', 'contributors.[]', function() { + const contributionsUnconfirmed = this.contributionsUnconfirmed.filterBy('vetoed', false); + const contributionsGrouped = groupBy(contributionsUnconfirmed, 'contributorId'); + const contributorsWithUnconfirmed = contributionsGrouped.map(c => c.value.toString()); + const contributorsWithOnlyConfirmed = this.contributors.reject(c => contributorsWithUnconfirmed.includes(c.id)) + + const kreditsByContributor = contributionsGrouped.map(c => { + const amountUnconfirmed = c.items.mapBy('amount').reduce((a, b) => a + b); + const contributor = this.contributors.findBy('id', c.value.toString()); + + return EmberObject.create({ + contributor: contributor, + amountUnconfirmed: amountUnconfirmed, + amountConfirmed: contributor.totalKreditsEarned, + amountTotal: contributor.totalKreditsEarned + amountUnconfirmed + }) + }); + + contributorsWithOnlyConfirmed.forEach(c => { + kreditsByContributor.push(EmberObject.create({ + contributor: c, + amountUnconfirmed: 0, + amountConfirmed: c.totalKreditsEarned, + amountTotal: c.totalKreditsEarned + })); + }) + + return kreditsByContributor; + }), + + contributionsUnconfirmed: computed('contributions.[]', 'currentBlock', function() { + return this.contributions.filter(contribution => { + return contribution.confirmedAt > this.currentBlock; + }); + }), + + contributionsConfirmed: computed('contributions.[]', 'currentBlock', function() { + return this.contributions + .filterBy('vetoed', false) + .filter(contribution => { + return contribution.confirmedAt <= this.currentBlock; + }); + }), + + async loadInitialData () { const numCachedContributors = await this.browserCache.contributors.length(); if (numCachedContributors > 0) { @@ -336,7 +353,7 @@ export default Service.extend({ }).group('contributionTasks'), fetchNewContributions: task(function * () { - const count = yield this.kredits.Contribution.functions.contributionsCount(); + const count = yield this.kredits.Contribution.count(); const lastKnownContributionId = Math.max.apply(null, this.contributions.mapBy('id')); const toFetch = count - lastKnownContributionId; @@ -406,23 +423,10 @@ export default Service.extend({ }); }, - getCurrentUser: computed('kredits.provider', 'currentUserAccounts.[]', function() { - if (isEmpty(this.currentUserAccounts)) { - return Promise.resolve(); - } - return this.kredits.Contributor - .functions.getContributorIdByAddress(this.currentUserAccounts.firstObject) - .then((id) => { - // check if the user is a contributor or not - if (id === 0) { - return Promise.resolve(); - } else { - return this.kredits.Contributor.getById(id); - } - }); - }), - + // // Contract events + // + addContractEventHandlers () { this.kredits.Contributor .on('ContributorProfileUpdated', this.handleContributorChange.bind(this)) From 95743330e4d09bc63e295cbd706d744f5b87fdbe Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Sat, 27 Jun 2020 16:35:04 +0200 Subject: [PATCH 04/57] WIP Generic data handling and caching Add basic support for reimbursements via new, generic data handling functions. --- app/models/reimbursement.js | 48 + app/routes/budget.js | 15 + app/services/browser-cache.js | 7 +- app/services/kredits.js | 172 ++- app/templates/budget.hbs | 7 +- app/utils/process-reimbursement-data.js | 20 + package-lock.json | 1655 ++++++++++++++++------- package.json | 4 +- 8 files changed, 1409 insertions(+), 519 deletions(-) create mode 100644 app/models/reimbursement.js create mode 100644 app/utils/process-reimbursement-data.js diff --git a/app/models/reimbursement.js b/app/models/reimbursement.js new file mode 100644 index 0000000..f074c30 --- /dev/null +++ b/app/models/reimbursement.js @@ -0,0 +1,48 @@ +import EmberObject, { computed } from '@ember/object'; +import { isEmpty, isPresent } from '@ember/utils'; +import moment from 'moment'; + +export default EmberObject.extend({ + + // Contract + id: null, + contributorId: null, + token: null, + amount: null, + confirmedAt: null, + vetoed: null, + ipfsHash: null, + + // contributor model instance + contributor: null, + + // TODO contributor who submitted the reimbursement + // recordedBy: null, + + // IPFS + expenses: null, // Array of expense objects + + pendingTx: null, + + init () { + this._super(...arguments); + if (isEmpty(this.details)) this.set('details', {}); + }, + + iso8601Date: computed('date', 'time', function() { + return this.time ? `${this.date}T${this.time}` : this.date; + }), + + jsDate: computed('iso8601Date', function() { + return moment(this.iso8601Date).toDate(); + }), + + hasPendingChanges: computed('pendingTx', function() { + return isPresent(this.pendingTx); + }), + + serialize () { + return JSON.stringify(this); + } + +}); diff --git a/app/routes/budget.js b/app/routes/budget.js index 551250a..0f32c30 100644 --- a/app/routes/budget.js +++ b/app/routes/budget.js @@ -1,4 +1,19 @@ import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; export default class BudgetRoute extends Route { + + @service browserCache; + @service kredits; + + async model () { + const numCachedReimbursements = await this.browserCache.reimbursements.length(); + if (numCachedReimbursements > 0) { + await this.kredits.loadObjectsFromCache('Reimbursement'); + this.kredits.set('reimbursementsNeedSync', true); + } else { + await this.kredits.fetchObjects('Reimbursement', { page: { size: 10 } }); + } + } + } diff --git a/app/services/browser-cache.js b/app/services/browser-cache.js index 29232dd..f6dc63a 100644 --- a/app/services/browser-cache.js +++ b/app/services/browser-cache.js @@ -13,7 +13,8 @@ export default class BrowserCacheService extends Service { super(...arguments); this.stores = { contributors: createStore('contributors'), - contributions: createStore('contributions') + contributions: createStore('contributions'), + reimbursements: createStore('reimbursements') } } @@ -24,4 +25,8 @@ export default class BrowserCacheService extends Service { get contributions() { return this.stores.contributions; } + + get reimbursements() { + return this.stores.reimbursements; + } } diff --git a/app/services/kredits.js b/app/services/kredits.js index eac93a0..bcc32f4 100644 --- a/app/services/kredits.js +++ b/app/services/kredits.js @@ -13,11 +13,15 @@ import { task, taskGroup } from 'ember-concurrency'; import groupBy from 'kredits-web/utils/group-by'; import processContributorData from 'kredits-web/utils/process-contributor-data'; import processContributionData from 'kredits-web/utils/process-contribution-data'; +import processReimbursementData from 'kredits-web/utils/process-reimbursement-data'; import formatKredits from 'kredits-web/utils/format-kredits'; import config from 'kredits-web/config/environment'; -import Contributor from 'kredits-web/models/contributor' -import Contribution from 'kredits-web/models/contribution' +import Contributor from 'kredits-web/models/contributor'; +import Contribution from 'kredits-web/models/contribution'; +import Reimbursement from 'kredits-web/models/reimbursement'; +// Lets us access the model classes dynamically +const models = { Contributor, Contribution, Reimbursement } export default Service.extend({ @@ -28,6 +32,7 @@ export default Service.extend({ currentUser: null, contributors: null, contributions: null, + reimbursements: null, githubAccessToken: null, currentUserIsContributor: notEmpty('currentUser'), @@ -37,11 +42,13 @@ export default Service.extend({ // When data was loaded from cache, we need to fetch updates from the network contributorsNeedSync: false, contributionsNeedSync: false, + reimbursementsNeedSync: false, init () { this._super(...arguments); this.set('contributors', []); this.set('contributions', []); + this.set('reimbursements', []); }, // This is called in the application route's beforeModel(). So it is @@ -182,24 +189,31 @@ export default Service.extend({ }), contributionsUnconfirmed: computed('contributions.[]', 'currentBlock', function() { - return this.contributions.filter(contribution => { - return contribution.confirmedAt > this.currentBlock; - }); + return this.contributions + .filter(c => c.confirmedAt > this.currentBlock); }), contributionsConfirmed: computed('contributions.[]', 'currentBlock', function() { return this.contributions .filterBy('vetoed', false) - .filter(contribution => { - return contribution.confirmedAt <= this.currentBlock; - }); + .filter(c => c.confirmedAt <= this.currentBlock); }), + reimbursementsUnconfirmed: computed('reimbursements.[]', 'currentBlock', function() { + return this.reimbursements + .filter(r => r.confirmedAt > this.currentBlock); + }), + + reimbursementsConfirmed: computed('reimbursements.[]', 'currentBlock', function() { + return this.reimbursements + .filterBy('vetoed', false) + .filter(r => r.confirmedAt <= this.currentBlock); + }), async loadInitialData () { const numCachedContributors = await this.browserCache.contributors.length(); if (numCachedContributors > 0) { - await this.loadContributorsFromCache(); + await this.loadObjectsFromCache('Contributor'); this.set('contributorsNeedSync', true); } else { await this.fetchContributors(); @@ -207,7 +221,7 @@ export default Service.extend({ const numCachedContributions = await this.browserCache.contributions.length(); if (numCachedContributions > 0) { - await this.loadContributionsFromCache(); + await this.loadObjectsFromCache('Contribution'); this.set('contributionsNeedSync', true); } else { await this.fetchContributions({ page: { size: 30 } }); @@ -353,7 +367,7 @@ export default Service.extend({ }).group('contributionTasks'), fetchNewContributions: task(function * () { - const count = yield this.kredits.Contribution.count(); + const count = yield this.kredits.Contribution.functions.contributionsCount(); const lastKnownContributionId = Math.max.apply(null, this.contributions.mapBy('id')); const toFetch = count - lastKnownContributionId; @@ -423,6 +437,142 @@ export default Service.extend({ }); }, + // + // Generic data handling (for objects that can be vetoed) + // + + fetchObjects(objectClass, options = { page: { size: 200 } }) { + const objectClassLowerCase = objectClass.toLowerCase(); + console.debug(`[kredits] Fetching ${objectClassLowerCase}s from the network`); + return this.kredits[objectClass].all(options) + .then(objects => { + return objects.map(data => { + const classInstance = this[`load${objectClass}FromData`](data); + return classInstance; + }); + }) + .then(objects => { + const cacheWrites = objects.map(o => { + return this.browserCache[objectClassLowerCase+'s'] + .setItem(o.id.toString(), o.serialize()); + }); + return Promise.all(cacheWrites).then(() => { + console.debug(`[kredits] Cached ${objects.length} ${objectClassLowerCase+'s'} in browser storage`); + }); + }); + }, + + removeObjectFromCollectionIfLoaded (collection, objectId) { + const loadedObj = this[collection].findBy('id', objectId); + if (loadedObj) { this[collection].removeObject(loadedObj); } + }, + + async cacheLoadedObjects (collection) { + for (const o of this[collection]) { + await this.browserCache[collection].setItem(o.id, o.serialize()); + } + console.debug(`[kredits] Cached ${this[collection].length} ${collection} in browser storage`); + return Promise.resolve(); + }, + + async loadObjectsFromCache (objectClass) { + const collection = objectClass.toLowerCase()+'s'; + return this.browserCache[collection].iterate((value/*, key , iterationNumber */) => { + const obj = models[objectClass].create(JSON.parse(value)); + this[collection].pushObject(obj); + }).then((/* result */) => { + console.debug(`[kredits] Loaded ${this[collection].length} ${collection} from cache`); + }); + }, + + fetchNewObjects: task(function * (objectClass) { + const collection = objectClass.toLowerCase()+'s'; + const count = yield this.kredits[objectClass].functions[`${collection}Count`](); + const lastKnownObjectId = Math.max.apply(null, this[collection].mapBy('id')); + const toFetch = count - lastKnownObjectId; + + if (toFetch > 0) { + console.debug(`[kredits] Fetching ${toFetch} new ${collection}`); + for (let id = lastKnownObjectId; id <= count; id++) { + const data = yield this.kredits[objectClass].getById(id); + const o = this[`load${objectClass}FromData`](data); + yield this.browserCache[collection].setItem(o.id.toString(), o.serialize()); + } + } else { + console.debug(`[kredits] No new ${collection} to fetch`); + } + }), + + fetchMissingObjects: task(function * (objectClass) { + const collection = objectClass.toLowerCase()+'s'; + const count = yield this.kredits[objectClass].count(); + const allIds = [...Array(count+1).keys()]; + allIds.shift(); // remove first item, which is 0 + const loadedObjects = new Set(this[collection].mapBy('id')); + const toFetch = allIds.filter(id => !loadedObjects.has(id)); + if (toFetch.length === 0) { + console.debug(`[kredits] No ${collection} left to fetch`); + return; + } + console.debug(`[kredits] Fetching ${toFetch.length} past ${collection}`); + let countFetched = 0; + + for (let id = count; id > 0; id--) { + if (loadedObjects.has(id)) { + continue; + } else { + const data = yield this.kredits[objectClass].getById(id); + const o = this[`load${objectClass}fromData`](data); + yield this.browserCache[collection].setItem(o.id.toString(), o.serialize()); + countFetched++; + if (countFetched % 20 === 0) { + console.debug(`[kredits] Fetched ${countFetched} more ${collection}`); + } + } + } + console.debug(`[kredits] Cached ${countFetched} past ${collection}`); + }).group('syncTaskGroup'), + + syncUnconfirmedObjects: task(function * (objectClass) { + const collection = objectClass.toLowerCase()+'s'; + if (this`${collection}Unconfirmed`.length > 0) { + console.debug(`[kredits] Syncing unconfirmed ${collection}`); + for (const o of this[`${collection}Unconfirmed`]) { + const data = yield this.kredits[objectClass].getById(o.id); + const object = this[`load${objectClass}FromData`](data); + yield this.browserCache[collection] + .setItem(o.id.toString(), object.serialize()); + } + } else { + console.debug(`[kredits] No unconfirmed ${collection} to sync`); + } + }), + + vetoAgainstObject (objectClass, objectId) { + console.debug(`[kredits] veto against ${objectClass.toLowerCase()}`, objectId); + const collection = objectClass.toLowerCase()+'s'; + const object = this[collection].findBy('id', objectId); + + return this.kredits[objectClass].functions.veto(objectId, { gasLimit: 300000 }) + .then(data => { + console.debug('[kredits] veto response', data); + object.set('pendingTx', data); + return data; + }); + }, + + // + // Reimbursements + // + + loadReimbursementFromData(data) { + const obj = Reimbursement.create(processReimbursementData(data)); + obj.set('contributor', this.contributors.findBy('id', data.contributorId.toString())); + this.removeObjectFromCollectionIfLoaded('reimbursements', obj.id); + this.reimbursements.pushObject(obj); + return obj; + }, + // // Contract events // diff --git a/app/templates/budget.hbs b/app/templates/budget.hbs index eade3ae..7f31770 100644 --- a/app/templates/budget.hbs +++ b/app/templates/budget.hbs @@ -45,6 +45,11 @@ - {{outlet}} + {{!-- TODO #if sub-route (i.e. filtered list) --}} + {{!-- {{outlet}} --}} + {{!-- {{else}} --}} + +
+
\ No newline at end of file diff --git a/app/utils/process-reimbursement-data.js b/app/utils/process-reimbursement-data.js new file mode 100644 index 0000000..a0b9399 --- /dev/null +++ b/app/utils/process-reimbursement-data.js @@ -0,0 +1,20 @@ +export default function processReimbursementData(data) { + const processed = {} + + if (data.confirmedAtBlock && (typeof data.confirmedAtBlock.toNumber === 'function')) { + processed.confirmedAt = data.confirmedAtBlock.toNumber(); + } else if (data.confirmedAt !== 'undefined') { + processed.confirmedAt = data.confirmedAt; + } + + const otherProperties = [ + 'id', 'contributorId', 'token', 'amount', 'vetoed', 'ipfsHash', + 'expenses', 'pendingTx' + ]; + + otherProperties.forEach(prop => { + processed[prop] = data[prop]; + }); + + return processed; +} diff --git a/package-lock.json b/package-lock.json index 2477289..39f3526 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2938,9 +2938,8 @@ "dev": true }, "@kosmos/schemas": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@kosmos/schemas/-/schemas-2.2.1.tgz", - "integrity": "sha512-zYUctQ91sYhzoJ0ujO73odBSsnwvdLlS6ENA/U/4/IzRKVZBj9cS4RpgFh1xOQXNN+HB4pUu8u7Su/Xtked+vg==", + "version": "github:67P/kosmos-schemas#67cc3d9d746c93907a68a7b6283bb914c283a612", + "from": "github:67P/kosmos-schemas#feature/browser-compat", "dev": true, "requires": { "brfs-babel": "^1.0.0" @@ -3340,6 +3339,15 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "requires": { + "event-target-shim": "^5.0.0" + } + }, "abortcontroller-polyfill": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.4.0.tgz", @@ -3738,6 +3746,16 @@ "dev": true, "optional": true }, + "async-iterator-to-pull-stream": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/async-iterator-to-pull-stream/-/async-iterator-to-pull-stream-1.3.0.tgz", + "integrity": "sha512-NjyhAEz/sx32olqgKIk/2xbWEM6o8qef1yetIgb0U/R3oBgndP1kE/0CslowH3jvnA94BO4I6OXpOkTKH7Z1AA==", + "dev": true, + "requires": { + "get-iterator": "^1.0.2", + "pull-stream-to-async-iterator": "^1.0.1" + } + }, "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", @@ -4367,9 +4385,9 @@ } }, "babel-plugin-static-fs": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-static-fs/-/babel-plugin-static-fs-1.2.0.tgz", - "integrity": "sha512-7zsDPvDzCBwfbU53WKym5LxTe1PxQHE/dGo+EfIELlBcn08TpU7SlPJILcc6YVAyTrpVUNioQfWiUyMWk1DJVg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/babel-plugin-static-fs/-/babel-plugin-static-fs-1.2.1.tgz", + "integrity": "sha512-dZasA7svnKAsMEB7/6fKhJO+nIZsC2fvJyj3fbuk/xUOwslZOdl+9umXQsB+oqHwOEubZ5WHJ/Zy9dvnVnRvFg==", "dev": true, "requires": { "babel-template": "^6.3.13", @@ -4925,9 +4943,9 @@ } }, "base-x": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.7.tgz", - "integrity": "sha512-zAKJGuQPihXW22fkrfOclUUZXM2g92z5GzlSMHxhO6r6Qj+Nm0ccaGNBzDZojzwOMkpjAv4J0fOv1U4go+a4iw==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", + "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", "dev": true, "requires": { "safe-buffer": "^5.0.1" @@ -4985,9 +5003,9 @@ "dev": true }, "bignumber.js": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-8.1.1.tgz", - "integrity": "sha512-QD46ppGintwPGuL1KqmwhR0O+N2cZUg8JG/VzwI2e28sM9TqHjQB10lI4QAaMHVbLzwVLLAwEglpKPViWX+5NQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", "dev": true }, "binary-extensions": { @@ -5022,18 +5040,36 @@ } }, "bl": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-3.0.0.tgz", - "integrity": "sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz", + "integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==", "dev": true, "requires": { - "readable-stream": "^3.0.1" + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" }, "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -5042,9 +5078,9 @@ } }, "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, "string_decoder": { @@ -5164,23 +5200,55 @@ } }, "borc": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/borc/-/borc-2.1.1.tgz", - "integrity": "sha512-vPLLC2/gS0QN4O3cnPh+8jLshkMMD4qIfs+B1TPGPh30WrtcfItaO6j4k9alsqu/hIgKi8dVdmMvTcbq4tIF7A==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/borc/-/borc-2.1.2.tgz", + "integrity": "sha512-Sy9eoUi4OiKzq7VovMn246iTo17kzuyHJKomCfpWMlI6RpfN1gk95w7d7gH264nApVLg0HZfcpz62/g4VH1Y4w==", "dev": true, "requires": { "bignumber.js": "^9.0.0", + "buffer": "^5.5.0", "commander": "^2.15.0", - "ieee754": "^1.1.8", - "iso-url": "~0.4.4", - "json-text-sequence": "~0.1.0" + "ieee754": "^1.1.13", + "iso-url": "~0.4.7", + "json-text-sequence": "~0.1.0", + "readable-stream": "^3.6.0" }, "dependencies": { - "bignumber.js": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", - "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } } } }, @@ -6466,6 +6534,12 @@ "json-stable-stringify": "^1.0.1" } }, + "callbackify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/callbackify/-/callbackify-1.1.0.tgz", + "integrity": "sha1-0qNphtKKppcUUmwREgm+65l50x4=", + "dev": true + }, "callsite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", @@ -6773,15 +6847,28 @@ "dev": true }, "cids": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/cids/-/cids-0.5.8.tgz", - "integrity": "sha512-Ye8TZP3YQfy0j+i5k+LPHdTY3JOvTwN1pxds44p6BRUv8PTMOAF/Vt4Bc+oiIQ0Sktn0iftkUHgqKNHIMwhshA==", + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.5.tgz", + "integrity": "sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA==", "dev": true, "requires": { + "buffer": "^5.5.0", "class-is": "^1.1.0", "multibase": "~0.6.0", - "multicodec": "~0.5.0", - "multihashes": "~0.4.14" + "multicodec": "^1.0.0", + "multihashes": "~0.4.15" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + } } }, "cipher-base": { @@ -7788,12 +7875,6 @@ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true }, - "detect-node": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", - "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", - "dev": true - }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -14597,9 +14678,9 @@ "dev": true }, "err-code": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", - "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", "dev": true }, "errno": { @@ -15252,6 +15333,12 @@ "es5-ext": "~0.10.14" } }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true + }, "eventemitter3": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.4.tgz", @@ -15367,6 +15454,12 @@ "homedir-polyfill": "^1.0.1" } }, + "explain-error": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/explain-error/-/explain-error-1.0.4.tgz", + "integrity": "sha1-p5PTrAytTGq1cemWj7urbLJTKSk=", + "dev": true + }, "express": { "version": "4.17.1", "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", @@ -15539,6 +15632,12 @@ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", "dev": true }, + "fast-fifo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.0.0.tgz", + "integrity": "sha512-4VEXmjxLj7sbs8J//cn2qhRap50dGzF5n8fjay8mau+Jn4hxSeR3xPFwxMaQq/pDaq7+KQk0PAbC2+nWDkJrmQ==", + "dev": true + }, "fast-glob": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.2.tgz", @@ -16171,12 +16270,6 @@ "write": "1.0.3" } }, - "flatmap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/flatmap/-/flatmap-0.0.3.tgz", - "integrity": "sha1-Hxik2TgVLUlZZfnJWNkjqy3WabQ=", - "dev": true - }, "flatpickr": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.3.tgz", @@ -16279,12 +16372,6 @@ "readable-stream": "^2.0.0" } }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, "fs-extra": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", @@ -16485,6 +16572,12 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "get-iterator": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-iterator/-/get-iterator-1.0.2.tgz", + "integrity": "sha512-v+dm9bNVfOYsY1OrhaCrmyOcYoSeVvbt+hHZ0Au+T+p1y+0Uyj9aMaGIeUTT6xdpRbWzDeYKvfOslPhggQMcsg==", + "dev": true + }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", @@ -17317,9 +17410,9 @@ "dev": true }, "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-4.1.0.tgz", + "integrity": "sha512-pKnZpbgCTfH/1NLIlOduP/V+WRXzC2MOz3Qo8xmxk8C5GudJLgK5QyLVXOSWy3ParAH7Eemurl3xjv/WXYFvMA==", "dev": true }, "ipaddr.js": { @@ -17336,89 +17429,68 @@ "requires": { "cids": "~0.7.0", "class-is": "^1.1.0" - }, - "dependencies": { - "cids": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.1.tgz", - "integrity": "sha512-qEM4j2GKE/BiT6WdUi6cfW8dairhSLTUE8tIdxJG6SvY33Mp/UPjw+xcO0n1zsllgo72BupzKF/44v+Bg8YPPg==", - "dev": true, - "requires": { - "class-is": "^1.1.0", - "multibase": "~0.6.0", - "multicodec": "~0.5.1", - "multihashes": "~0.4.14" - } - } } }, "ipfs-http-client": { - "version": "30.1.4", - "resolved": "https://registry.npmjs.org/ipfs-http-client/-/ipfs-http-client-30.1.4.tgz", - "integrity": "sha512-ordvoPT3lAFL5qsvdYBeDGRP03gtbL6Jl+qJ9dztyhE7NJf2yhtnU3ZNqN1JMCcUK0qpGsDzX89t8dKQvI80Pw==", + "version": "41.0.1", + "resolved": "https://registry.npmjs.org/ipfs-http-client/-/ipfs-http-client-41.0.1.tgz", + "integrity": "sha512-oyH0hXoB+jfz4NqM+SZSpk6c9wR+9uvUO+/0eQFT6B9Ludz4zR8T5MHo7bnQoVerj9Qlv0x0wO1ckSoekaSPpw==", "dev": true, "requires": { - "async": "^2.6.1", - "bignumber.js": "^8.0.2", - "bl": "^3.0.0", + "abort-controller": "^3.0.0", + "async-iterator-to-pull-stream": "^1.3.0", + "bignumber.js": "^9.0.0", + "bl": "^4.0.0", "bs58": "^4.0.1", - "buffer": "^5.2.1", - "cids": "~0.5.5", - "concat-stream": "github:hugomrdias/concat-stream#feat/smaller", + "buffer": "^5.4.2", + "callbackify": "^1.1.0", + "cids": "~0.7.1", "debug": "^4.1.0", - "detect-node": "^2.0.4", - "end-of-stream": "^1.4.1", - "err-code": "^1.1.2", - "flatmap": "0.0.3", - "glob": "^7.1.3", - "ipfs-block": "~0.8.0", - "ipld-dag-cbor": "~0.13.1", - "ipld-dag-pb": "~0.15.3", - "is-ipfs": "~0.6.0", - "is-pull-stream": "0.0.0", - "is-stream": "^1.1.0", - "iso-stream-http": "~0.1.2", - "iso-url": "~0.4.6", - "just-kebab-case": "^1.1.0", - "just-map-keys": "^1.1.0", - "lru-cache": "^5.1.1", + "err-code": "^2.0.0", + "explain-error": "^1.0.4", + "form-data": "^3.0.0", + "ipfs-block": "~0.8.1", + "ipfs-utils": "^0.4.2", + "ipld-dag-cbor": "~0.15.0", + "ipld-dag-pb": "^0.18.1", + "ipld-raw": "^4.0.0", + "is-ipfs": "~0.6.1", + "it-all": "^1.0.1", + "it-glob": "0.0.7", + "it-tar": "^1.1.1", + "it-to-stream": "^0.1.1", + "iterable-ndjson": "^1.1.0", + "ky": "^0.15.0", + "ky-universal": "^0.3.0", + "merge-options": "^2.0.0", "multiaddr": "^6.0.6", + "multiaddr-to-uri": "^5.0.0", "multibase": "~0.6.0", - "multicodec": "~0.5.0", + "multicodec": "^1.0.0", "multihashes": "~0.4.14", - "ndjson": "github:hugomrdias/ndjson#feat/readable-stream3", - "once": "^1.4.0", - "peer-id": "~0.12.2", + "parse-duration": "^0.1.1", + "peer-id": "~0.12.3", "peer-info": "~0.15.1", - "promisify-es6": "^1.0.3", - "pull-defer": "~0.2.3", - "pull-stream": "^3.6.9", - "pull-to-stream": "~0.1.1", - "pump": "^3.0.0", - "qs": "^6.5.2", - "readable-stream": "^3.1.1", - "stream-to-pull-stream": "^1.7.2", - "tar-stream": "^2.0.1", - "through2": "^3.0.1" + "promise-nodeify": "^3.0.1" }, "dependencies": { "buffer": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.4.3.tgz", - "integrity": "sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", "dev": true, "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4" } }, - "concat-stream": { - "version": "github:hugomrdias/concat-stream#057bc7b5d6d8df26c8cf00a3f151b6721a0a8034", - "from": "github:hugomrdias/concat-stream#feat/smaller", + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "requires": { - "inherits": "^2.0.3", - "readable-stream": "^3.0.2" + "delayed-stream": "~1.0.0" } }, "debug": { @@ -17430,42 +17502,87 @@ "ms": "^2.1.1" } }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "form-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", + "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", "dev": true, "requires": { - "yallist": "^3.0.2" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" } }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true - }, - "ndjson": { - "version": "github:hugomrdias/ndjson#4db16da6b42e5b39bf300c3a7cde62abb3fa3a11", - "from": "github:hugomrdias/ndjson#feat/readable-stream3", + } + } + }, + "ipfs-utils": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/ipfs-utils/-/ipfs-utils-0.4.2.tgz", + "integrity": "sha512-k/uNOniniqg7uCnHvmujis8ASNefn0url8GS7HaNLAhL3RV3dHBiibtQFp8JZ/zfN+80FrYJt7cPEzRbGbmJUA==", + "dev": true, + "requires": { + "buffer": "^5.2.1", + "err-code": "^2.0.0", + "fs-extra": "^8.1.0", + "is-buffer": "^2.0.3", + "is-electron": "^2.2.0", + "is-pull-stream": "0.0.0", + "is-stream": "^2.0.0", + "it-glob": "0.0.7", + "kind-of": "^6.0.2", + "pull-stream-to-async-iterator": "^1.0.2", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", "dev": true, "requires": { - "json-stringify-safe": "^5.0.1", - "minimist": "^1.2.0", - "split2": "^3.1.0", - "through2": "^3.0.0" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" } }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -17474,9 +17591,9 @@ } }, "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, "string_decoder": { @@ -17487,49 +17604,139 @@ "requires": { "safe-buffer": "~5.2.0" } - }, - "through2": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", - "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", - "dev": true, - "requires": { - "readable-stream": "2 || 3" - } } } }, "ipld-dag-cbor": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/ipld-dag-cbor/-/ipld-dag-cbor-0.13.1.tgz", - "integrity": "sha512-96KKh5XUq9LrWE/TQ/BOJ5FcQx7UZ892N76ufDdovq+fIwZ4/YpPRTAVssLUuN3crATHoGu80TVZMgevsuTCdQ==", + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/ipld-dag-cbor/-/ipld-dag-cbor-0.15.3.tgz", + "integrity": "sha512-m23nG7ZyoVFnkK55/bLAErc7EfiMgaEQlqHWDTGzPI+O5r6bPfp+qbL5zTVSIT8tpbHmu174dwerVtLoVgeVyA==", "dev": true, "requires": { - "borc": "^2.1.0", - "bs58": "^4.0.1", - "cids": "~0.5.5", + "borc": "^2.1.2", + "buffer": "^5.5.0", + "cids": "~0.8.0", "is-circular": "^1.0.2", - "multihashes": "~0.4.14", - "multihashing-async": "~0.5.1", - "traverse": "~0.6.6" + "multicodec": "^1.0.0", + "multihashing-async": "~0.8.0" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "cids": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.8.3.tgz", + "integrity": "sha512-yoXTbV3llpm+EBGWKeL9xKtksPE/s6DPoDSY4fn8I8TEW1zehWXPSB0pwAXVDlLaOlrw+sNynj995uD9abmPhA==", + "dev": true, + "requires": { + "buffer": "^5.6.0", + "class-is": "^1.1.0", + "multibase": "^1.0.0", + "multicodec": "^1.0.1", + "multihashes": "^1.0.1" + } + }, + "multibase": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-1.0.1.tgz", + "integrity": "sha512-KcCxpBVY8fdVKu4dJMAahq4F/2Z/9xqEjIiR7PiMe7LRGeorFn2NLmicN6nLBCqQvft6MG2Lc9X5P0IdyvnxEw==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "multihashes": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-1.0.1.tgz", + "integrity": "sha512-S27Tepg4i8atNiFaU5ZOm3+gl3KQlUanLs/jWcBxQHFttgq+5x1OgbQmf2d8axJ/48zYGBd/wT9d723USMFduw==", + "dev": true, + "requires": { + "buffer": "^5.6.0", + "multibase": "^1.0.1", + "varint": "^5.0.0" + } + } } }, "ipld-dag-pb": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/ipld-dag-pb/-/ipld-dag-pb-0.15.3.tgz", - "integrity": "sha512-J1RJzSVCaOpxPmSzXbwVNsAZPHctjY4OjqG1dMIG86Z37CKvuy1QwCFkDhNccUTcQpF3sXfj5e0ZUyMM035vzg==", + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/ipld-dag-pb/-/ipld-dag-pb-0.18.5.tgz", + "integrity": "sha512-8IAPZrkRjgTpkxV9JOwXSBe0GXNxd4B2lubPgbifTGL92rZOEKWutpijsWsWvjXOltDFHKMQIIIhkgLC5RPqbA==", "dev": true, "requires": { - "async": "^2.6.1", - "bs58": "^4.0.1", - "cids": "~0.5.4", + "buffer": "^5.6.0", + "cids": "~0.8.0", "class-is": "^1.1.0", - "is-ipfs": "~0.6.0", - "multihashing-async": "~0.5.1", - "protons": "^1.0.1", - "pull-stream": "^3.6.9", - "pull-traverse": "^1.0.3", - "stable": "~0.1.8" + "multicodec": "^1.0.1", + "multihashing-async": "~0.8.1", + "protons": "^1.0.2", + "stable": "^0.1.8" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "cids": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.8.3.tgz", + "integrity": "sha512-yoXTbV3llpm+EBGWKeL9xKtksPE/s6DPoDSY4fn8I8TEW1zehWXPSB0pwAXVDlLaOlrw+sNynj995uD9abmPhA==", + "dev": true, + "requires": { + "buffer": "^5.6.0", + "class-is": "^1.1.0", + "multibase": "^1.0.0", + "multicodec": "^1.0.1", + "multihashes": "^1.0.1" + } + }, + "multibase": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-1.0.1.tgz", + "integrity": "sha512-KcCxpBVY8fdVKu4dJMAahq4F/2Z/9xqEjIiR7PiMe7LRGeorFn2NLmicN6nLBCqQvft6MG2Lc9X5P0IdyvnxEw==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "multihashes": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-1.0.1.tgz", + "integrity": "sha512-S27Tepg4i8atNiFaU5ZOm3+gl3KQlUanLs/jWcBxQHFttgq+5x1OgbQmf2d8axJ/48zYGBd/wT9d723USMFduw==", + "dev": true, + "requires": { + "buffer": "^5.6.0", + "multibase": "^1.0.1", + "varint": "^5.0.0" + } + } + } + }, + "ipld-raw": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/ipld-raw/-/ipld-raw-4.0.1.tgz", + "integrity": "sha512-WjIdtZ06jJEar8zh+BHB84tE6ZdbS/XNa7+XCArOYfmeJ/c01T9VQpeMwdJQYn5c3s5UvvCu7y4VIi3vk2g1bA==", + "dev": true, + "requires": { + "cids": "~0.7.0", + "multicodec": "^1.0.0", + "multihashing-async": "~0.8.0" } }, "is-accessor-descriptor": { @@ -17625,6 +17832,12 @@ } } }, + "is-electron": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-electron/-/is-electron-2.2.0.tgz", + "integrity": "sha512-SpMppC2XR3YdxSzczXReBjqs2zGscWQpBIKqwXYBFic0ERaxNVgwLCHwOLZeESfdJQjX0RDvrJ1lBXX2ij+G1Q==", + "dev": true + }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", @@ -17687,38 +17900,110 @@ "dev": true }, "is-ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-2.0.0.tgz", - "integrity": "sha1-aO6gfooKCpTC0IDdZ0xzGrKkYas=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-3.1.0.tgz", + "integrity": "sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==", "dev": true, "requires": { - "ip-regex": "^2.0.0" + "ip-regex": "^4.0.0" } }, "is-ipfs": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/is-ipfs/-/is-ipfs-0.6.1.tgz", - "integrity": "sha512-WhqQylam6pODS2RyqT/u0PR5KWtBZNCgPjgargFOVQjzw/3+6d0midXenzU65klM4LH13IUiCC6ObhDUdXZ7Nw==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/is-ipfs/-/is-ipfs-0.6.3.tgz", + "integrity": "sha512-HyRot1dvLcxImtDqPxAaY1miO6WsiP/z7Yxpg2qpaLWv5UdhAPtLvHJ4kMLM0w8GSl8AFsVF23PHe1LzuWrUlQ==", "dev": true, "requires": { "bs58": "^4.0.1", "cids": "~0.7.0", - "mafmt": "^6.0.7", - "multiaddr": "^6.0.4", + "mafmt": "^7.0.0", + "multiaddr": "^7.2.1", "multibase": "~0.6.0", "multihashes": "~0.4.13" }, "dependencies": { - "cids": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/cids/-/cids-0.7.1.tgz", - "integrity": "sha512-qEM4j2GKE/BiT6WdUi6cfW8dairhSLTUE8tIdxJG6SvY33Mp/UPjw+xcO0n1zsllgo72BupzKF/44v+Bg8YPPg==", + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", "dev": true, "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "multiaddr": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/multiaddr/-/multiaddr-7.5.0.tgz", + "integrity": "sha512-GvhHsIGDULh06jyb6ev+VfREH9evJCFIRnh3jUt9iEZ6XDbyoisZRFEI9bMvK/AiR6y66y6P+eoBw9mBYMhMvw==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "cids": "~0.8.0", "class-is": "^1.1.0", - "multibase": "~0.6.0", - "multicodec": "~0.5.1", - "multihashes": "~0.4.14" + "is-ip": "^3.1.0", + "multibase": "^0.7.0", + "varint": "^5.0.0" + }, + "dependencies": { + "cids": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.8.3.tgz", + "integrity": "sha512-yoXTbV3llpm+EBGWKeL9xKtksPE/s6DPoDSY4fn8I8TEW1zehWXPSB0pwAXVDlLaOlrw+sNynj995uD9abmPhA==", + "dev": true, + "requires": { + "buffer": "^5.6.0", + "class-is": "^1.1.0", + "multibase": "^1.0.0", + "multicodec": "^1.0.1", + "multihashes": "^1.0.1" + }, + "dependencies": { + "multibase": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-1.0.1.tgz", + "integrity": "sha512-KcCxpBVY8fdVKu4dJMAahq4F/2Z/9xqEjIiR7PiMe7LRGeorFn2NLmicN6nLBCqQvft6MG2Lc9X5P0IdyvnxEw==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + } + } + }, + "multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "multihashes": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-1.0.1.tgz", + "integrity": "sha512-S27Tepg4i8atNiFaU5ZOm3+gl3KQlUanLs/jWcBxQHFttgq+5x1OgbQmf2d8axJ/48zYGBd/wT9d723USMFduw==", + "dev": true, + "requires": { + "buffer": "^5.6.0", + "multibase": "^1.0.1", + "varint": "^5.0.0" + }, + "dependencies": { + "multibase": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-1.0.1.tgz", + "integrity": "sha512-KcCxpBVY8fdVKu4dJMAahq4F/2Z/9xqEjIiR7PiMe7LRGeorFn2NLmicN6nLBCqQvft6MG2Lc9X5P0IdyvnxEw==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + } + } + } } } } @@ -17770,6 +18055,12 @@ "isobject": "^3.0.1" } }, + "is-promise": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz", + "integrity": "sha1-MVc3YcBX4zwukaq56W2gjO++duU=", + "dev": true + }, "is-pull-stream": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/is-pull-stream/-/is-pull-stream-0.0.0.tgz", @@ -17865,27 +18156,36 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "iso-random-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/iso-random-stream/-/iso-random-stream-1.1.0.tgz", - "integrity": "sha512-ywSWt0KrWcsaK0jVoVJIR30rLyjg9Rw3k2Sm/qp+3tdtSV0SNH7L7KilKnENcENOSoJxDFvpt2idvuMMQohdCQ==", + "iso-constants": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/iso-constants/-/iso-constants-0.1.2.tgz", + "integrity": "sha512-OTCM5ZCQsHBCI4Wdu4tSxvDIkmDHd5EwJDps5mKqnQnWJSKlnwMs3EDZ4n3Fh1tmkWkDlyd2vCDbEYuPbyrUNQ==", "dev": true }, - "iso-stream-http": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/iso-stream-http/-/iso-stream-http-0.1.2.tgz", - "integrity": "sha512-oHEDNOysIMTNypbg2f1SlydqRBvjl4ZbSE9+0awVxnkx3K2stGTFwB/kpVqnB6UEfF8QD36kAjDwZvqyXBLMnQ==", + "iso-random-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/iso-random-stream/-/iso-random-stream-1.1.1.tgz", + "integrity": "sha512-YEt/7xOwTdu4KXIgtdgGFkiLUsBaddbnkmHyaFdjJYIcD7V4gpQHPvYC5tyh3kA0PQ01y9lWm1ruVdf8Mqzovg==", "dev": true, "requires": { - "builtin-status-codes": "^3.0.0", - "inherits": "^2.0.1", - "readable-stream": "^3.1.1" + "buffer": "^5.4.3", + "readable-stream": "^3.4.0" }, "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { "inherits": "^2.0.3", @@ -17894,9 +18194,9 @@ } }, "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, "string_decoder": { @@ -17911,9 +18211,9 @@ } }, "iso-url": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/iso-url/-/iso-url-0.4.6.tgz", - "integrity": "sha512-YQO7+aIe6l1aSJUKOx+Vrv08DlhZeLFIVfehG2L29KLSEb9RszqPXilxJRVpp57px36BddKR5ZsebacO5qG0tg==", + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/iso-url/-/iso-url-0.4.7.tgz", + "integrity": "sha512-27fFRDnPAMnHGLq36bWTpKET+eiXct3ENlCcdcMdk+mjXrb2kw3mhBUg1B7ewAC0kVzlOPhADzQgz1SE6Tglog==", "dev": true }, "isobject": { @@ -17949,6 +18249,163 @@ "is-object": "^1.0.1" } }, + "it-all": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/it-all/-/it-all-1.0.2.tgz", + "integrity": "sha512-3hrCLLcuHS1/VUn1qETPuh9rFTw31SBCUUijjs41VJ+oQGx3H+3Lpxo1bFD3q3570w3o99a+sfRGic5PBBt3Vg==", + "dev": true + }, + "it-concat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/it-concat/-/it-concat-1.0.0.tgz", + "integrity": "sha512-mLhiCB3tW4NTYTg7bMlyYX2c782KsAacthHMR3y5kjJn9JhNFb02NcH70KZuNrSXFSTq8k6m8MiYaQWRjrDxAA==", + "dev": true, + "requires": { + "bl": "^4.0.0" + } + }, + "it-glob": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/it-glob/-/it-glob-0.0.7.tgz", + "integrity": "sha512-XfbziJs4fi0MfdEGTLkZXeqo2EorF2baFXxFn1E2dGbgYMhFTZlZ2Yn/mx5CkpuLWVJvO1DwtTOVW2mzRyVK8w==", + "dev": true, + "requires": { + "fs-extra": "^8.1.0", + "minimatch": "^3.0.4" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + } + } + }, + "it-reader": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/it-reader/-/it-reader-2.1.0.tgz", + "integrity": "sha512-hSysqWTO9Tlwc5EGjVf8JYZzw0D2FsxD/g+eNNWrez9zODxWt6QlN6JAMmycK72Mv4jHEKEXoyzUN4FYGmJaZw==", + "dev": true, + "requires": { + "bl": "^4.0.0" + } + }, + "it-tar": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/it-tar/-/it-tar-1.2.2.tgz", + "integrity": "sha512-M8V4a9I+x/vwXTjqvixcEZbQZHjwDIb8iUQ+D4M2QbhAdNs3WKVSl+45u5/F2XFx6jYMFOGzMVlKNK/uONgNIA==", + "dev": true, + "requires": { + "bl": "^4.0.0", + "buffer": "^5.4.3", + "iso-constants": "^0.1.2", + "it-concat": "^1.0.0", + "it-reader": "^2.0.0", + "p-defer": "^3.0.0" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + } + } + }, + "it-to-stream": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/it-to-stream/-/it-to-stream-0.1.1.tgz", + "integrity": "sha512-QQx/58JBvT189imr6fD234F8aVf8EdyQHJR0MxXAOShEWK1NWyahPYIQt/tQG7PId0ZG/6/3tUiVCfw2cq+e1w==", + "dev": true, + "requires": { + "buffer": "^5.2.1", + "fast-fifo": "^1.0.0", + "get-iterator": "^1.0.2", + "p-defer": "^3.0.0", + "p-fifo": "^1.0.0", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + } + } + }, + "iterable-ndjson": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/iterable-ndjson/-/iterable-ndjson-1.1.0.tgz", + "integrity": "sha512-OOp1Lb0o3k5MkXHx1YaIY5Z0ELosZfTnBaas9f8opJVcZGBIONA2zY/6CYE+LKkqrSDooIneZbrBGgOZnHPkrg==", + "dev": true, + "requires": { + "string_decoder": "^1.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + } + } + }, "jquery": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz", @@ -18127,18 +18584,6 @@ "verror": "1.10.0" } }, - "just-kebab-case": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/just-kebab-case/-/just-kebab-case-1.1.0.tgz", - "integrity": "sha512-QkuwuBMQ9BQHMUEkAtIA4INLrkmnnveqlFB1oFi09gbU0wBdZo6tTnyxNWMR84zHxBuwK7GLAwqN8nrvVxOLTA==", - "dev": true - }, - "just-map-keys": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/just-map-keys/-/just-map-keys-1.1.0.tgz", - "integrity": "sha512-oNKi+4y7fr8lXnhKYpBbCkiwHRVkAnx0VDkCeTDtKKMzGr1Lz1Yym+RSieKUTKim68emC5Yxrb4YmiF9STDO+g==", - "dev": true - }, "keypair": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/keypair/-/keypair-1.0.1.tgz", @@ -18161,79 +18606,31 @@ "dev": true }, "kredits-contracts": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/kredits-contracts/-/kredits-contracts-5.5.0.tgz", - "integrity": "sha512-kiiKySe7plOeywiJv+0E2MfUxQ56yTUamrQzVqLjyTssHWtjv7Nv+/EoYnVXgWHBcGouh02QzmxrYJYpAAS6Ig==", + "version": "github:67P/kredits-contracts#17cc44cb981074b32b7732744ce5699949fc1f2f", + "from": "github:67P/kredits-contracts#feature/expenses", "dev": true, "requires": { - "ethers": "^4.0.29", - "ipfs-http-client": "^30.1.3", - "kosmos-schemas": "^2.1.0", + "@kosmos/schemas": "github:67P/kosmos-schemas#feature/browser-compat", + "ethers": "^4.0.47", + "ipfs-http-client": "^41.0.1", "node-fetch": "^2.6.0", "tv4": "^1.3.0" - }, - "dependencies": { - "@types/node": { - "version": "10.14.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.18.tgz", - "integrity": "sha512-ryO3Q3++yZC/+b8j8BdKd/dn9JlzlHBPdm80656xwYUdmPkpTGTjkAdt6BByiNupGPE8w0FhBgvYy/fX9hRNGQ==", - "dev": true - }, - "elliptic": { - "version": "6.3.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.3.3.tgz", - "integrity": "sha1-VILZZG1UvLif19mU/J4ulWiHbj8=", - "dev": true, - "requires": { - "bn.js": "^4.4.0", - "brorand": "^1.0.1", - "hash.js": "^1.0.0", - "inherits": "^2.0.1" - } - }, - "ethers": { - "version": "4.0.37", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-4.0.37.tgz", - "integrity": "sha512-B7bDdyQ45A5lPr6k2HOkEKMtYOuqlfy+nNf8glnRvWidkDQnToKw1bv7UyrwlbsIgY2mE03UxTVtouXcT6Vvcw==", - "dev": true, - "requires": { - "@types/node": "^10.3.2", - "aes-js": "3.0.0", - "bn.js": "^4.4.0", - "elliptic": "6.3.3", - "hash.js": "1.1.3", - "js-sha3": "0.5.7", - "scrypt-js": "2.0.4", - "setimmediate": "1.0.4", - "uuid": "2.0.1", - "xmlhttprequest": "1.8.0" - } - }, - "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.0" - } - }, - "kosmos-schemas": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/kosmos-schemas/-/kosmos-schemas-2.1.0.tgz", - "integrity": "sha512-RT90o0ujAKoCUpcYHi5ijDxg9F9enY5aOIZXujidjkCQ/hgjJ2tyNi+x8rszutsAP/mx64yj307oWJWhNZTyTg==", - "dev": true, - "requires": { - "brfs-babel": "^1.0.0" - } - }, - "uuid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.1.tgz", - "integrity": "sha1-wqMN7bPlNdcsz4LjQ5QaULqFM6w=", - "dev": true - } + } + }, + "ky": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/ky/-/ky-0.15.0.tgz", + "integrity": "sha512-6IlJRPFHq4ZKRRa9lyh6YqHqlmddAkfyXI9CYvZpLQtg7fQvwncPHyHrmtXAHKCqHOilINPMT88eW6FTA3HwkA==", + "dev": true + }, + "ky-universal": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/ky-universal/-/ky-universal-0.3.0.tgz", + "integrity": "sha512-CM4Bgb2zZZpsprcjI6DNYTaH3oGHXL2u7BU4DK+lfCuC4snkt9/WRpMYeKbBbXscvKkeqBwzzjFX2WwmKY5K/A==", + "dev": true, + "requires": { + "abort-controller": "^3.0.0", + "node-fetch": "^2.6.0" } }, "leek": { @@ -18273,9 +18670,9 @@ } }, "libp2p-crypto": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/libp2p-crypto/-/libp2p-crypto-0.16.1.tgz", - "integrity": "sha512-+fxqy+cDjwOKK4KTj44WQmjPE5ep2eR5uAIQWHl/+RKvRSor3+RAY53VWkAecgAEvjX2AswxBsoCIJK1Qk5aIQ==", + "version": "0.16.3", + "resolved": "https://registry.npmjs.org/libp2p-crypto/-/libp2p-crypto-0.16.3.tgz", + "integrity": "sha512-ro7/5Tu+f8p2+qDS1JrROnO++nNaAaBFs+VVXVHLuTMnbnMASu1eUtSlWPk1uOwikAlBFTvfqe5J1bK6Bpq6Pg==", "dev": true, "requires": { "asmcrypto.js": "^2.3.2", @@ -18288,29 +18685,49 @@ "keypair": "^1.0.1", "libp2p-crypto-secp256k1": "~0.3.0", "multihashing-async": "~0.5.1", - "node-forge": "~0.7.6", + "node-forge": "~0.9.1", "pem-jwk": "^2.0.0", "protons": "^1.0.1", "rsa-pem-to-jwk": "^1.1.3", "tweetnacl": "^1.0.0", - "ursa-optional": "~0.9.10" + "ursa-optional": "~0.10.0" }, "dependencies": { "asn1.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.2.0.tgz", - "integrity": "sha512-Q7hnYGGNYbcmGrCPulXfkEw7oW7qjWeM4ZTALmgpuIcZLxyqqKYWxCZg2UBm8bklrnB4m2mGyJPWfoktdORD8A==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", "dev": true, "requires": { "bn.js": "^4.0.0", "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "dev": true + }, + "multihashing-async": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/multihashing-async/-/multihashing-async-0.5.2.tgz", + "integrity": "sha512-mmyG6M/FKxrpBh9xQDUvuJ7BbqT93ZeEeH5X6LeMYKoYshYLr9BDdCsvDtZvn+Egf+/Xi+aOznrWL4vp3s+p0Q==", + "dev": true, + "requires": { + "blakejs": "^1.1.0", + "js-sha3": "~0.8.0", + "multihashes": "~0.4.13", + "murmurhash3js": "^3.0.1", + "nodeify": "^1.0.1" } }, "tweetnacl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.1.tgz", - "integrity": "sha512-kcoMoKTPYnoeS50tzoqjPY3Uv9axeuuFAZY9M/9zFnhoVvRfxz9K29IMPD7jGmt2c8SW7i3gT9WqDl2+nV7p4A==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", "dev": true } } @@ -18991,12 +19408,6 @@ } } }, - "looper": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/looper/-/looper-3.0.0.tgz", - "integrity": "sha1-LvpUw7HLq6m5Su4uWRSwvlf7t0k=", - "dev": true - }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -19039,12 +19450,96 @@ } }, "mafmt": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/mafmt/-/mafmt-6.0.10.tgz", - "integrity": "sha512-FjHDnew6dW9lUu3eYwP0FvvJl9uvNbqfoJM+c1WJcSyutNEIlyu6v3f/rlPnD1cnmue38IjuHlhBdIh3btAiyw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/mafmt/-/mafmt-7.1.0.tgz", + "integrity": "sha512-vpeo9S+hepT3k2h5iFxzEHvvR0GPBx9uKaErmnRzYNcaKb03DgOArjEMlgG4a9LcuZZ89a3I8xbeto487n26eA==", "dev": true, "requires": { - "multiaddr": "^6.1.0" + "multiaddr": "^7.3.0" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "cids": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.8.3.tgz", + "integrity": "sha512-yoXTbV3llpm+EBGWKeL9xKtksPE/s6DPoDSY4fn8I8TEW1zehWXPSB0pwAXVDlLaOlrw+sNynj995uD9abmPhA==", + "dev": true, + "requires": { + "buffer": "^5.6.0", + "class-is": "^1.1.0", + "multibase": "^1.0.0", + "multicodec": "^1.0.1", + "multihashes": "^1.0.1" + }, + "dependencies": { + "multibase": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-1.0.1.tgz", + "integrity": "sha512-KcCxpBVY8fdVKu4dJMAahq4F/2Z/9xqEjIiR7PiMe7LRGeorFn2NLmicN6nLBCqQvft6MG2Lc9X5P0IdyvnxEw==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + } + } + }, + "multiaddr": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/multiaddr/-/multiaddr-7.5.0.tgz", + "integrity": "sha512-GvhHsIGDULh06jyb6ev+VfREH9evJCFIRnh3jUt9iEZ6XDbyoisZRFEI9bMvK/AiR6y66y6P+eoBw9mBYMhMvw==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "cids": "~0.8.0", + "class-is": "^1.1.0", + "is-ip": "^3.1.0", + "multibase": "^0.7.0", + "varint": "^5.0.0" + } + }, + "multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "multihashes": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-1.0.1.tgz", + "integrity": "sha512-S27Tepg4i8atNiFaU5ZOm3+gl3KQlUanLs/jWcBxQHFttgq+5x1OgbQmf2d8axJ/48zYGBd/wT9d723USMFduw==", + "dev": true, + "requires": { + "buffer": "^5.6.0", + "multibase": "^1.0.1", + "varint": "^5.0.0" + }, + "dependencies": { + "multibase": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-1.0.1.tgz", + "integrity": "sha512-KcCxpBVY8fdVKu4dJMAahq4F/2Z/9xqEjIiR7PiMe7LRGeorFn2NLmicN6nLBCqQvft6MG2Lc9X5P0IdyvnxEw==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + } + } + } } }, "magic-string": { @@ -19238,6 +19733,23 @@ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", "dev": true }, + "merge-options": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-2.0.0.tgz", + "integrity": "sha512-S7xYIeWHl2ZUKF7SDeBhGg6rfv5bKxVBdk95s/I7wVF8d+hjLSztJ/B271cnUiF6CAFduEQ5Zn3HYwAjT16DlQ==", + "dev": true, + "requires": { + "is-plain-obj": "^2.0.0" + }, + "dependencies": { + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + } + } + }, "merge-source-map": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.0.4.tgz", @@ -19525,65 +20037,245 @@ "ip": "^1.1.5", "is-ip": "^2.0.0", "varint": "^5.0.0" + }, + "dependencies": { + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "is-ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ip/-/is-ip-2.0.0.tgz", + "integrity": "sha1-aO6gfooKCpTC0IDdZ0xzGrKkYas=", + "dev": true, + "requires": { + "ip-regex": "^2.0.0" + } + } + } + }, + "multiaddr-to-uri": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/multiaddr-to-uri/-/multiaddr-to-uri-5.1.0.tgz", + "integrity": "sha512-rIlMLkw3yk3RJmf2hxYYzeqPXz4Vx7C4M/hg7BVWhmksDW0rDVNMEyoVb0H1A+sh3deHOh5EAFK87XcW+mFimA==", + "dev": true, + "requires": { + "multiaddr": "^7.2.1" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "cids": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/cids/-/cids-0.8.3.tgz", + "integrity": "sha512-yoXTbV3llpm+EBGWKeL9xKtksPE/s6DPoDSY4fn8I8TEW1zehWXPSB0pwAXVDlLaOlrw+sNynj995uD9abmPhA==", + "dev": true, + "requires": { + "buffer": "^5.6.0", + "class-is": "^1.1.0", + "multibase": "^1.0.0", + "multicodec": "^1.0.1", + "multihashes": "^1.0.1" + }, + "dependencies": { + "multibase": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-1.0.1.tgz", + "integrity": "sha512-KcCxpBVY8fdVKu4dJMAahq4F/2Z/9xqEjIiR7PiMe7LRGeorFn2NLmicN6nLBCqQvft6MG2Lc9X5P0IdyvnxEw==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + } + } + }, + "multiaddr": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/multiaddr/-/multiaddr-7.5.0.tgz", + "integrity": "sha512-GvhHsIGDULh06jyb6ev+VfREH9evJCFIRnh3jUt9iEZ6XDbyoisZRFEI9bMvK/AiR6y66y6P+eoBw9mBYMhMvw==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "cids": "~0.8.0", + "class-is": "^1.1.0", + "is-ip": "^3.1.0", + "multibase": "^0.7.0", + "varint": "^5.0.0" + } + }, + "multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "multihashes": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-1.0.1.tgz", + "integrity": "sha512-S27Tepg4i8atNiFaU5ZOm3+gl3KQlUanLs/jWcBxQHFttgq+5x1OgbQmf2d8axJ/48zYGBd/wT9d723USMFduw==", + "dev": true, + "requires": { + "buffer": "^5.6.0", + "multibase": "^1.0.1", + "varint": "^5.0.0" + }, + "dependencies": { + "multibase": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-1.0.1.tgz", + "integrity": "sha512-KcCxpBVY8fdVKu4dJMAahq4F/2Z/9xqEjIiR7PiMe7LRGeorFn2NLmicN6nLBCqQvft6MG2Lc9X5P0IdyvnxEw==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + } + } + } } }, "multibase": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.0.tgz", - "integrity": "sha512-R9bNLQhbD7MsitPm1NeY7w9sDgu6d7cuj25snAWH7k5PSNPSwIQQBpcpj8jx1W96dLbdigZqmUWOdQRMnAmgjA==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.6.1.tgz", + "integrity": "sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw==", "dev": true, "requires": { - "base-x": "3.0.4" + "base-x": "^3.0.8", + "buffer": "^5.5.0" }, "dependencies": { - "base-x": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.4.tgz", - "integrity": "sha512-UYOadoSIkEI/VrRGSG6qp93rp2WdokiAiNYDfGW5qURAY8GiAQkvMbwNNSDYiVJopqv4gCna7xqf4rrNGp+5AA==", + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", "dev": true, "requires": { - "safe-buffer": "^5.0.1" + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" } } } }, "multicodec": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-0.5.5.tgz", - "integrity": "sha512-1kOifvwAqp9IdiiTKmpK2tS+LY6GHZdKpk3S2EvW4T32vlwDyA3hJoZtGauzqdedUPVNGChnTksEotVOCVlC+Q==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/multicodec/-/multicodec-1.0.3.tgz", + "integrity": "sha512-8G4JKbHWSe/39Xx2uiI+/b/S6mGgimzwEN4TOCokFUIfofg1T8eHny88ht9eWImD2dng+EEQRsApXxA5ubhU4g==", "dev": true, "requires": { + "buffer": "^5.6.0", "varint": "^5.0.0" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + } } }, "multihashes": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.15.tgz", - "integrity": "sha512-G/Smj1GWqw1RQP3dRuRRPe3oyLqvPqUaEDIaoi7JF7Loxl4WAWvhJNk84oyDEodSucv0MmSW/ZT0RKUrsIFD3g==", + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-0.4.21.tgz", + "integrity": "sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw==", "dev": true, "requires": { - "bs58": "^4.0.1", + "buffer": "^5.5.0", + "multibase": "^0.7.0", "varint": "^5.0.0" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "multibase": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-0.7.0.tgz", + "integrity": "sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + } } }, "multihashing-async": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/multihashing-async/-/multihashing-async-0.5.2.tgz", - "integrity": "sha512-mmyG6M/FKxrpBh9xQDUvuJ7BbqT93ZeEeH5X6LeMYKoYshYLr9BDdCsvDtZvn+Egf+/Xi+aOznrWL4vp3s+p0Q==", + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/multihashing-async/-/multihashing-async-0.8.2.tgz", + "integrity": "sha512-2lKa1autuCy8x7KIEj9aVNbAb3aIMRFYIwN7mq/zD4pxgNIVgGlm+f6GKY4880EOF2Y3GktHYssRy7TAJQ2DyQ==", "dev": true, "requires": { "blakejs": "^1.1.0", - "js-sha3": "~0.8.0", - "multihashes": "~0.4.13", - "murmurhash3js": "^3.0.1", - "nodeify": "^1.0.1" + "buffer": "^5.4.3", + "err-code": "^2.0.0", + "js-sha3": "^0.8.0", + "multihashes": "^1.0.1", + "murmurhash3js-revisited": "^3.0.0" }, "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, "js-sha3": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", "dev": true + }, + "multibase": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multibase/-/multibase-1.0.1.tgz", + "integrity": "sha512-KcCxpBVY8fdVKu4dJMAahq4F/2Z/9xqEjIiR7PiMe7LRGeorFn2NLmicN6nLBCqQvft6MG2Lc9X5P0IdyvnxEw==", + "dev": true, + "requires": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "multihashes": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/multihashes/-/multihashes-1.0.1.tgz", + "integrity": "sha512-S27Tepg4i8atNiFaU5ZOm3+gl3KQlUanLs/jWcBxQHFttgq+5x1OgbQmf2d8axJ/48zYGBd/wT9d723USMFduw==", + "dev": true, + "requires": { + "buffer": "^5.6.0", + "multibase": "^1.0.1", + "varint": "^5.0.0" + } } } }, @@ -19593,6 +20285,12 @@ "integrity": "sha1-Ppg+W0fCoG9DpxMXTn5DXKBEuZg=", "dev": true }, + "murmurhash3js-revisited": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/murmurhash3js-revisited/-/murmurhash3js-revisited-3.0.0.tgz", + "integrity": "sha512-/sF3ee6zvScXMb1XFJ8gDsSnY+X8PbOyjIuBhtgis10W2Jx4ZjIhikUCIF9c4gpJxVnQIsPAFrSwTCuAjicP6g==", + "dev": true + }, "mustache": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/mustache/-/mustache-3.2.1.tgz", @@ -19609,7 +20307,8 @@ "version": "2.13.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==", - "dev": true + "dev": true, + "optional": true }, "nanomatch": { "version": "1.2.13", @@ -19707,9 +20406,9 @@ "dev": true }, "node-forge": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.6.tgz", - "integrity": "sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.1.tgz", + "integrity": "sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ==", "dev": true }, "node-int64": { @@ -19825,14 +20524,6 @@ "requires": { "is-promise": "~1.0.0", "promise": "~1.3.0" - }, - "dependencies": { - "is-promise": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz", - "integrity": "sha1-MVc3YcBX4zwukaq56W2gjO++duU=", - "dev": true - } } }, "nopt": { @@ -20244,6 +20935,15 @@ "mimic-fn": "^2.1.0" } }, + "optimist": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=", + "dev": true, + "requires": { + "wordwrap": "~0.0.2" + } + }, "optionator": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", @@ -20400,6 +21100,16 @@ "integrity": "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==", "dev": true }, + "p-fifo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-fifo/-/p-fifo-1.0.0.tgz", + "integrity": "sha512-IjoCxXW48tqdtDFz6fqo5q1UfFVjjVZe8TC1QRflvNUJtNfCUhxOUw6MOVZhDPjqhSzc26xKdugsO17gmzd5+A==", + "dev": true, + "requires": { + "fast-fifo": "^1.0.0", + "p-defer": "^3.0.0" + } + }, "p-finally": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz", @@ -20493,6 +21203,12 @@ "safe-buffer": "^5.1.1" } }, + "parse-duration": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/parse-duration/-/parse-duration-0.1.3.tgz", + "integrity": "sha512-hMOZHfUmjxO5hMKn7Eft+ckP2M4nV4yzauLXiw3PndpkASnx5r8pDAMcOAiqxoemqWjMWmz4fOHQM6n6WwETXw==", + "dev": true + }, "parse-headers": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.3.tgz", @@ -20641,9 +21357,9 @@ } }, "peer-id": { - "version": "0.12.4", - "resolved": "https://registry.npmjs.org/peer-id/-/peer-id-0.12.4.tgz", - "integrity": "sha512-AIAwL/6CmVc/VKbUhpA1rY3A/VJ3Z9ELvtvDQfl5cIi0A74L7lvsJ6LxQn5JSJVHM5Us2Ng9zMO523dO3FFnnw==", + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/peer-id/-/peer-id-0.12.5.tgz", + "integrity": "sha512-3xVWrtIvNm9/OPzaQBgXDrfWNx63AftgFQkvqO6YSZy7sP3Fuadwwbn54F/VO9AnpyW/26i0WRQz9FScivXrmw==", "dev": true, "requires": { "async": "^2.6.3", @@ -20673,6 +21389,17 @@ "multiaddr": "^6.0.3", "peer-id": "~0.12.2", "unique-by": "^1.0.0" + }, + "dependencies": { + "mafmt": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/mafmt/-/mafmt-6.0.10.tgz", + "integrity": "sha512-FjHDnew6dW9lUu3eYwP0FvvJl9uvNbqfoJM+c1WJcSyutNEIlyu6v3f/rlPnD1cnmue38IjuHlhBdIh3btAiyw==", + "dev": true, + "requires": { + "multiaddr": "^6.1.0" + } + } } }, "pem-jwk": { @@ -20685,14 +21412,15 @@ }, "dependencies": { "asn1.js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.2.0.tgz", - "integrity": "sha512-Q7hnYGGNYbcmGrCPulXfkEw7oW7qjWeM4ZTALmgpuIcZLxyqqKYWxCZg2UBm8bklrnB4m2mGyJPWfoktdORD8A==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", "dev": true, "requires": { "bn.js": "^4.0.0", "inherits": "^2.0.1", - "minimalistic-assert": "^1.0.0" + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" } } } @@ -20923,14 +21651,6 @@ "dev": true, "requires": { "is-promise": "~1" - }, - "dependencies": { - "is-promise": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-1.0.1.tgz", - "integrity": "sha1-MVc3YcBX4zwukaq56W2gjO++duU=", - "dev": true - } } }, "promise-inflight": { @@ -20948,34 +21668,46 @@ "rsvp": "^3.0.14" } }, + "promise-nodeify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/promise-nodeify/-/promise-nodeify-3.0.1.tgz", + "integrity": "sha512-ghsSuzZXJX8iO7WVec2z7GI+Xk/EyiD+JZK7AZKhUqYfpLa/Zs4ylUD+CwwnKlG6G3HnkUPMAi6PO7zeqGKssg==", + "dev": true + }, "promise.hash.helper": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/promise.hash.helper/-/promise.hash.helper-1.0.7.tgz", "integrity": "sha512-0qhWYyCV9TYDMSooYw1fShIb7R6hsWYja7JLqbeb1MvHqDTvP/uy/R1RsyVqDi6GCiHOI4G5p2Hpr3IA+/l/+Q==", "dev": true }, - "promisify-es6": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/promisify-es6/-/promisify-es6-1.0.3.tgz", - "integrity": "sha512-N9iVG+CGJsI4b4ZGazjwLnxErD2d9Pe4DPvvXSxYA9tFNu8ymXME4Qs5HIQ0LMJpNM7zj+m0NlNnNeqFpKzqnA==", - "dev": true - }, "protocol-buffers-schema": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.3.2.tgz", - "integrity": "sha512-Xdayp8sB/mU+sUV4G7ws8xtYMGdQnxbeIfLjyO9TZZRJdztBGhlmbI5x1qcY4TG5hBkIKGnc28i7nXxaugu88w==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.4.0.tgz", + "integrity": "sha512-G/2kcamPF2S49W5yaMGdIpkG6+5wZF0fzBteLKgEHjbNzqjZQ85aAs1iJGto31EJaSTkNvHs5IXuHSaTLWBAiA==", "dev": true }, "protons": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/protons/-/protons-1.0.1.tgz", - "integrity": "sha512-+0ZKnfVs+4c43tbAQ5j0Mck8wPcLnlxUYzKQoB4iDW4ocdXGnN4P+0dDbgX1FTpoY9+7P2Tn2scJyHHqj+S/lQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/protons/-/protons-1.2.1.tgz", + "integrity": "sha512-2oqDyc/SN+tNcJf8XxrXhYL7sQn2/OMl8mSdD7NVGsWjMEmAbks4eDVnCyf0vAoRbBWyWTEXWk4D8XfuKVl3zg==", "dev": true, "requires": { + "buffer": "^5.5.0", "protocol-buffers-schema": "^3.3.1", - "safe-buffer": "^5.1.1", "signed-varint": "^2.0.1", "varint": "^5.0.0" + }, + "dependencies": { + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + } } }, "proxy-addr": { @@ -21014,61 +21746,21 @@ "safe-buffer": "^5.1.2" } }, - "pull-defer": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/pull-defer/-/pull-defer-0.2.3.tgz", - "integrity": "sha512-/An3KE7mVjZCqNhZsr22k1Tx8MACnUnHZZNPSJ0S62td8JtYr/AiRG42Vz7Syu31SoTLUzVIe61jtT/pNdjVYA==", - "dev": true - }, "pull-stream": { "version": "3.6.14", "resolved": "https://registry.npmjs.org/pull-stream/-/pull-stream-3.6.14.tgz", "integrity": "sha512-KIqdvpqHHaTUA2mCYcLG1ibEbu/LCKoJZsBWyv9lSYtPkJPBq8m3Hxa103xHi6D2thj5YXa0TqK3L3GUkwgnew==", "dev": true }, - "pull-to-stream": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pull-to-stream/-/pull-to-stream-0.1.1.tgz", - "integrity": "sha512-thZkMv6F9PILt9zdvpI2gxs19mkDrlixYKX6cOBxAW16i1NZH+yLAmF4r8QfJ69zuQh27e01JZP9y27tsH021w==", + "pull-stream-to-async-iterator": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pull-stream-to-async-iterator/-/pull-stream-to-async-iterator-1.0.2.tgz", + "integrity": "sha512-c3KRs2EneuxP7b6pG9fvQTIjatf33RbIErhbQ75s5r2MI6E8R74NZC1nJgXc8kcmqiQxmr+TWY+WwK2mWaUnlA==", "dev": true, "requires": { - "readable-stream": "^3.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", - "dev": true - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - } - } + "pull-stream": "^3.6.9" } }, - "pull-traverse": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pull-traverse/-/pull-traverse-1.0.3.tgz", - "integrity": "sha1-dPtde+f6a9enjpeTPhmbeUWGaTg=", - "dev": true - }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -21885,17 +22577,6 @@ "dev": true, "requires": { "optimist": "~0.3.5" - }, - "dependencies": { - "optimist": { - "version": "0.3.7", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", - "integrity": "sha1-yQlBrVnkJzMokjB00s8ufLxuwNk=", - "dev": true, - "requires": { - "wordwrap": "~0.0.2" - } - } } }, "rsvp": { @@ -22111,9 +22792,9 @@ "dev": true }, "secp256k1": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.7.1.tgz", - "integrity": "sha512-1cf8sbnRreXrQFdH6qsg2H71Xw91fCCS9Yp021GnUNJzWJS/py96fS4lHbnTnouLp08Xj6jBoBB6V78Tdbdu5g==", + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.8.0.tgz", + "integrity": "sha512-k5ke5avRZbtl9Tqx/SA7CbY3NF6Ro+Sj9cZxezFzuBlLDmyqPiL8hJJ+EmzD8Ig4LUDByHJ3/iPOVoRixs/hmw==", "dev": true, "requires": { "bindings": "^1.5.0", @@ -22121,15 +22802,30 @@ "bn.js": "^4.11.8", "create-hash": "^1.2.0", "drbg.js": "^1.0.1", - "elliptic": "^6.4.1", + "elliptic": "^6.5.2", "nan": "^2.14.0", "safe-buffer": "^5.1.2" }, "dependencies": { + "elliptic": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", + "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", "dev": true } } @@ -23098,16 +23794,6 @@ "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", "dev": true }, - "stream-to-pull-stream": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/stream-to-pull-stream/-/stream-to-pull-stream-1.7.3.tgz", - "integrity": "sha512-6sNyqJpr5dIOQdgNy/xcDWwDuzAsAwVzhzrWlAPAQ7Lkjx/rv0wgvxEyKwTq6FmNd5rjTrELt/CLmaSw7crMGg==", - "dev": true, - "requires": { - "looper": "^3.0.0", - "pull-stream": "^3.2.3" - } - }, "strict-uri-encode": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", @@ -23658,47 +24344,6 @@ "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", "dev": true }, - "tar-stream": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.0.tgz", - "integrity": "sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==", - "dev": true, - "requires": { - "bl": "^3.0.0", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", - "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", - "dev": true - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - } - } - } - }, "temp": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.1.tgz", @@ -24121,12 +24766,6 @@ "loader-utils": "^1.0.2" } }, - "traverse": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", - "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=", - "dev": true - }, "tree-sync": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/tree-sync/-/tree-sync-1.4.0.tgz", @@ -24505,13 +25144,21 @@ "dev": true }, "ursa-optional": { - "version": "0.9.10", - "resolved": "https://registry.npmjs.org/ursa-optional/-/ursa-optional-0.9.10.tgz", - "integrity": "sha512-RvEbhnxlggX4MXon7KQulTFiJQtLJZpSb9ZSa7ZTkOW0AzqiVTaLjI4vxaSzJBDH9dwZ3ltZadFiBaZslp6haA==", + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/ursa-optional/-/ursa-optional-0.10.1.tgz", + "integrity": "sha512-/pgpBXVJut57dHNrdGF+1/qXi+5B7JrlmZDWPSyoivEcbwFWRZJBJGkWb6ivknMBA3bnFA7lqsb6iHiFfp79QQ==", "dev": true, "requires": { - "bindings": "^1.3.0", - "nan": "^2.11.1" + "bindings": "^1.5.0", + "nan": "^2.14.0" + }, + "dependencies": { + "nan": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", + "dev": true + } } }, "use": { diff --git a/package.json b/package.json index 8f62fc8..6d8313d 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@ember/optional-features": "^1.3.0", "@glimmer/component": "^1.0.0", "@glimmer/tracking": "^1.0.0", - "@kosmos/schemas": "^2.2.1", + "@kosmos/schemas": "github:67P/kosmos-schemas#feature/browser-compat", "babel-eslint": "^10.1.0", "babel-preset-es2015": "^6.22.0", "babelify": "^7.3.0", @@ -66,7 +66,7 @@ "eslint-plugin-ember": "^8.5.2", "eslint-plugin-node": "^11.1.0", "ethers": "^4.0.47", - "kredits-contracts": "^5.5.0", + "kredits-contracts": "github:67P/kredits-contracts#feature/expenses", "loader.js": "^4.7.0", "localforage": "^1.7.3", "ndjson": "github:hugomrdias/ndjson#feat/readable-stream3", From eaac245f4e6c3718362041c8e24e340ec4a0988f Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 9 Jul 2020 15:14:09 +0200 Subject: [PATCH 05/57] WIP Basic reimbursement lists --- .../reimbursement-list/component.js | 7 ++ .../reimbursement-list/template.hbs | 14 +++ app/controllers/budget.js | 10 ++ app/styles/_layout.scss | 16 +++ app/templates/budget.hbs | 114 ++++++++++-------- app/utils/process-reimbursement-data.js | 6 +- config/environment.js | 4 + package-lock.json | 111 ++++++++--------- package.json | 2 +- .../reimbursement-list/component-test.js | 26 ++++ tests/unit/controllers/budget-test.js | 12 ++ 11 files changed, 212 insertions(+), 110 deletions(-) create mode 100644 app/components/reimbursement-list/component.js create mode 100644 app/components/reimbursement-list/template.hbs create mode 100644 app/controllers/budget.js create mode 100644 tests/integration/components/reimbursement-list/component-test.js create mode 100644 tests/unit/controllers/budget-test.js diff --git a/app/components/reimbursement-list/component.js b/app/components/reimbursement-list/component.js new file mode 100644 index 0000000..6f2b5cb --- /dev/null +++ b/app/components/reimbursement-list/component.js @@ -0,0 +1,7 @@ +import Component from '@glimmer/component'; +import { sort } from '@ember/object/computed'; + +export default class ReimbursementListComponent extends Component { + itemSorting = Object.freeze(['id:desc']); + @sort('args.items', 'itemSorting') itemsSorted; +} diff --git a/app/components/reimbursement-list/template.hbs b/app/components/reimbursement-list/template.hbs new file mode 100644 index 0000000..0ef5075 --- /dev/null +++ b/app/components/reimbursement-list/template.hbs @@ -0,0 +1,14 @@ +
    + {{#each this.itemsSorted as |reimbursement|}} +
  • + {{reimbursement.id}}
    + {{reimbursement.amount}} WBTC
    + vetoed: {{reimbursement.vetoed}}
    + pay out to: {{reimbursement.contributor.name}}
    + + {{#each reimbursement.expenses as |expense|}} + {{expense.date}}: {{expense.title}} + {{/each}} +
  • + {{/each}} +
\ No newline at end of file diff --git a/app/controllers/budget.js b/app/controllers/budget.js new file mode 100644 index 0000000..f932b83 --- /dev/null +++ b/app/controllers/budget.js @@ -0,0 +1,10 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; +import { alias } from '@ember/object/computed'; + +export default class BudgetController extends Controller { + @service kredits; + + @alias('kredits.reimbursementsUnconfirmed') reimbursementsUnconfirmed; + @alias('kredits.reimbursementsConfirmed') reimbursementsConfirmed; +} diff --git a/app/styles/_layout.scss b/app/styles/_layout.scss index 23be5fa..ce31120 100644 --- a/app/styles/_layout.scss +++ b/app/styles/_layout.scss @@ -14,6 +14,15 @@ main { "contributions"; } + &#budget { + width: 100%; + display: grid; + grid-row-gap: 2rem; + grid-template-areas: + "aside" + "content"; + } + &.center-column { display: flex; flex-direction: column; @@ -111,6 +120,13 @@ main { "stats contributions details"; } } + + &#budget { + grid-column-gap: 3rem; + grid-template-columns: 2fr 4fr 2fr; + grid-template-areas: + "aside content empty"; + } } } diff --git a/app/templates/budget.hbs b/app/templates/budget.hbs index 7f31770..80dd73d 100644 --- a/app/templates/budget.hbs +++ b/app/templates/budget.hbs @@ -1,55 +1,73 @@
- +
+ -
-
-

Community funds

-
-
- - - - - - - - - - - - - - - - - - - - -
TokenAmountFiat value
WBTC1.1721511031.15 USD
ETH0.5115.60 USD
-
-
+
+
+

Community funds

+
+
+ + + + + + + + + + + + + + + + + + + + +
TokenAmountFiat value
WBTC1.1721511031.15 USD
ETH0.5115.60 USD
+
+
+
- {{!-- TODO #if sub-route (i.e. filtered list) --}} - {{!-- {{outlet}} --}} - {{!-- {{else}} --}} +
+
+
+

Proposed Reimbursements

+
+
+ +
+
-
-
+
+
+

Confirmed Expenses

+
+
+ +
+
+
+ +
+
\ No newline at end of file diff --git a/app/utils/process-reimbursement-data.js b/app/utils/process-reimbursement-data.js index a0b9399..a66287c 100644 --- a/app/utils/process-reimbursement-data.js +++ b/app/utils/process-reimbursement-data.js @@ -1,5 +1,7 @@ export default function processReimbursementData(data) { - const processed = {} + const processed = { + amount: data.amount.toNumber() + } if (data.confirmedAtBlock && (typeof data.confirmedAtBlock.toNumber === 'function')) { processed.confirmedAt = data.confirmedAtBlock.toNumber(); @@ -8,7 +10,7 @@ export default function processReimbursementData(data) { } const otherProperties = [ - 'id', 'contributorId', 'token', 'amount', 'vetoed', 'ipfsHash', + 'id', 'contributorId', 'token', 'vetoed', 'ipfsHash', 'expenses', 'pendingTx' ]; diff --git a/config/environment.js b/config/environment.js index 3554ed2..e2c59ea 100644 --- a/config/environment.js +++ b/config/environment.js @@ -46,6 +46,10 @@ module.exports = function(environment) { port: '5444', protocol: 'https', gatewayUrl: 'https://ipfs.kosmos.org/ipfs' + }, + + tokens: { + 'WBTC': '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599' } }; diff --git a/package-lock.json b/package-lock.json index 39f3526..4669c89 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2938,8 +2938,9 @@ "dev": true }, "@kosmos/schemas": { - "version": "github:67P/kosmos-schemas#67cc3d9d746c93907a68a7b6283bb914c283a612", - "from": "github:67P/kosmos-schemas#feature/browser-compat", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@kosmos/schemas/-/schemas-3.0.0.tgz", + "integrity": "sha512-7hnirq0ShsDjENBPjNnu6izwzVjkDzEZ4SKvPzQJJfkeJ/NRVHKvfdn9rkE7CRXTi2hMzsZVFOnlF6D/eYXTCA==", "dev": true, "requires": { "brfs-babel": "^1.0.0" @@ -6759,13 +6760,6 @@ "to-regex-range": "^5.0.1" } }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "dev": true, - "optional": true - }, "glob-parent": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", @@ -10890,6 +10884,39 @@ "ms": "^2.1.1" } }, + "ember-get-config": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/ember-get-config/-/ember-get-config-0.2.4.tgz", + "integrity": "sha1-EYSSoqA9c+RgBO13eSiUICH+Hs0=", + "dev": true, + "requires": { + "broccoli-file-creator": "^1.1.1", + "ember-cli-babel": "^6.3.0" + }, + "dependencies": { + "ember-cli-babel": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.18.0.tgz", + "integrity": "sha512-7ceC8joNYxY2wES16iIBlbPSxwKDBhYwC8drU3ZEvuPDMwVv1KzxCNu1fvxyFEBWhwaRNTUxSCsEVoTd9nosGA==", + "dev": true, + "requires": { + "amd-name-resolver": "1.2.0", + "babel-plugin-debug-macros": "^0.2.0-beta.6", + "babel-plugin-ember-modules-api-polyfill": "^2.6.0", + "babel-plugin-transform-es2015-modules-amd": "^6.24.0", + "babel-polyfill": "^6.26.0", + "babel-preset-env": "^1.7.0", + "broccoli-babel-transpiler": "^6.5.0", + "broccoli-debug": "^0.6.4", + "broccoli-funnel": "^2.0.0", + "broccoli-source": "^1.1.0", + "clone": "^2.0.0", + "ember-cli-version-checker": "^2.1.2", + "semver": "^5.5.0" + } + } + } + }, "fs-extra": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz", @@ -11830,39 +11857,6 @@ } } }, - "ember-get-config": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/ember-get-config/-/ember-get-config-0.2.4.tgz", - "integrity": "sha1-EYSSoqA9c+RgBO13eSiUICH+Hs0=", - "dev": true, - "requires": { - "broccoli-file-creator": "^1.1.1", - "ember-cli-babel": "^6.3.0" - }, - "dependencies": { - "ember-cli-babel": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/ember-cli-babel/-/ember-cli-babel-6.18.0.tgz", - "integrity": "sha512-7ceC8joNYxY2wES16iIBlbPSxwKDBhYwC8drU3ZEvuPDMwVv1KzxCNu1fvxyFEBWhwaRNTUxSCsEVoTd9nosGA==", - "dev": true, - "requires": { - "amd-name-resolver": "1.2.0", - "babel-plugin-debug-macros": "^0.2.0-beta.6", - "babel-plugin-ember-modules-api-polyfill": "^2.6.0", - "babel-plugin-transform-es2015-modules-amd": "^6.24.0", - "babel-polyfill": "^6.26.0", - "babel-preset-env": "^1.7.0", - "broccoli-babel-transpiler": "^6.5.0", - "broccoli-debug": "^0.6.4", - "broccoli-funnel": "^2.0.0", - "broccoli-source": "^1.1.0", - "clone": "^2.0.0", - "ember-cli-version-checker": "^2.1.2", - "semver": "^5.5.0" - } - } - } - }, "ember-getowner-polyfill": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ember-getowner-polyfill/-/ember-getowner-polyfill-2.2.0.tgz", @@ -16494,15 +16488,11 @@ "dev": true }, "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } + "optional": true }, "function-bind": { "version": "1.1.1", @@ -18606,11 +18596,11 @@ "dev": true }, "kredits-contracts": { - "version": "github:67P/kredits-contracts#17cc44cb981074b32b7732744ce5699949fc1f2f", + "version": "github:67P/kredits-contracts#c63fcc002b05c5907d3f1ebd9487ee074e80d6e9", "from": "github:67P/kredits-contracts#feature/expenses", "dev": true, "requires": { - "@kosmos/schemas": "github:67P/kosmos-schemas#feature/browser-compat", + "@kosmos/schemas": "^3.0.0", "ethers": "^4.0.47", "ipfs-http-client": "^41.0.1", "node-fetch": "^2.6.0", @@ -20303,13 +20293,6 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "nan": { - "version": "2.13.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz", - "integrity": "sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==", - "dev": true, - "optional": true - }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -25437,6 +25420,16 @@ "upath": "^1.1.1" } }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0" + } + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", diff --git a/package.json b/package.json index 6d8313d..dc7b99c 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@ember/optional-features": "^1.3.0", "@glimmer/component": "^1.0.0", "@glimmer/tracking": "^1.0.0", - "@kosmos/schemas": "github:67P/kosmos-schemas#feature/browser-compat", + "@kosmos/schemas": "^3.0.0", "babel-eslint": "^10.1.0", "babel-preset-es2015": "^6.22.0", "babelify": "^7.3.0", diff --git a/tests/integration/components/reimbursement-list/component-test.js b/tests/integration/components/reimbursement-list/component-test.js new file mode 100644 index 0000000..0e8114a --- /dev/null +++ b/tests/integration/components/reimbursement-list/component-test.js @@ -0,0 +1,26 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | reimbursement-list', function(hooks) { + setupRenderingTest(hooks); + + test('it renders', async function(assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.set('myAction', function(val) { ... }); + + await render(hbs``); + + assert.equal(this.element.textContent.trim(), ''); + + // Template block usage: + await render(hbs` + + template block text + + `); + + assert.equal(this.element.textContent.trim(), 'template block text'); + }); +}); diff --git a/tests/unit/controllers/budget-test.js b/tests/unit/controllers/budget-test.js new file mode 100644 index 0000000..ec61054 --- /dev/null +++ b/tests/unit/controllers/budget-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Controller | budget', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let controller = this.owner.lookup('controller:budget'); + assert.ok(controller); + }); +}); From 4849a755dc20e7668d6d366cc87fe1d16374a6b0 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 9 Jul 2020 17:07:05 +0200 Subject: [PATCH 06/57] Render currencies etc. --- app/components/reimbursement-list/template.hbs | 4 ++-- app/helpers/fmt-fiat-currency.js | 10 ++++++++++ app/helpers/sats-to-btc.js | 5 +++++ .../reimbursement-list/component-test.js | 9 --------- .../helpers/fmt-fiat-currency-test.js | 18 ++++++++++++++++++ tests/integration/helpers/sats-to-btc-test.js | 16 ++++++++++++++++ 6 files changed, 51 insertions(+), 11 deletions(-) create mode 100644 app/helpers/fmt-fiat-currency.js create mode 100644 app/helpers/sats-to-btc.js create mode 100644 tests/integration/helpers/fmt-fiat-currency-test.js create mode 100644 tests/integration/helpers/sats-to-btc-test.js diff --git a/app/components/reimbursement-list/template.hbs b/app/components/reimbursement-list/template.hbs index 0ef5075..4c3fe9e 100644 --- a/app/components/reimbursement-list/template.hbs +++ b/app/components/reimbursement-list/template.hbs @@ -2,12 +2,12 @@ {{#each this.itemsSorted as |reimbursement|}}
  • {{reimbursement.id}}
    - {{reimbursement.amount}} WBTC
    + {{sats-to-btc reimbursement.amount}} WBTC
    vetoed: {{reimbursement.vetoed}}
    pay out to: {{reimbursement.contributor.name}}
    {{#each reimbursement.expenses as |expense|}} - {{expense.date}}: {{expense.title}} + {{expense.date}}: {{expense.title}} - {{fmt-fiat-currency expense.amount expense.currency}}
    {{/each}}
  • {{/each}} diff --git a/app/helpers/fmt-fiat-currency.js b/app/helpers/fmt-fiat-currency.js new file mode 100644 index 0000000..712987a --- /dev/null +++ b/app/helpers/fmt-fiat-currency.js @@ -0,0 +1,10 @@ +import { helper } from '@ember/component/helper'; + +export default helper(function fmtFiatCurrency(params) { + const formatter = new Intl.NumberFormat('en-US', { + style: 'currency', + currency: params[1] || 'EUR', + minimumFractionDigits: 2 + }) + return formatter.format(params[0]); +}); diff --git a/app/helpers/sats-to-btc.js b/app/helpers/sats-to-btc.js new file mode 100644 index 0000000..319004e --- /dev/null +++ b/app/helpers/sats-to-btc.js @@ -0,0 +1,5 @@ +import { helper } from '@ember/component/helper'; + +export default helper(function satsToBtc(amount/*, hash*/) { + return amount / 100000000; +}); diff --git a/tests/integration/components/reimbursement-list/component-test.js b/tests/integration/components/reimbursement-list/component-test.js index 0e8114a..7c0c2aa 100644 --- a/tests/integration/components/reimbursement-list/component-test.js +++ b/tests/integration/components/reimbursement-list/component-test.js @@ -13,14 +13,5 @@ module('Integration | Component | reimbursement-list', function(hooks) { await render(hbs``); assert.equal(this.element.textContent.trim(), ''); - - // Template block usage: - await render(hbs` - - template block text - - `); - - assert.equal(this.element.textContent.trim(), 'template block text'); }); }); diff --git a/tests/integration/helpers/fmt-fiat-currency-test.js b/tests/integration/helpers/fmt-fiat-currency-test.js new file mode 100644 index 0000000..26dceb5 --- /dev/null +++ b/tests/integration/helpers/fmt-fiat-currency-test.js @@ -0,0 +1,18 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Helper | fmt-fiat-currency', function(hooks) { + setupRenderingTest(hooks); + + test('it returns the number formatted as currency', async function(assert) { + this.set('amount', 13.9); + + await render(hbs`{{fmt-fiat-currency this.amount}}`); + assert.equal(this.element.textContent.trim(), '€13.90', 'using EUR amount by default'); + + await render(hbs`{{fmt-fiat-currency this.amount 'USD'}}`); + assert.equal(this.element.textContent.trim(), '$13.90', 'using the defined currency'); + }); +}); diff --git a/tests/integration/helpers/sats-to-btc-test.js b/tests/integration/helpers/sats-to-btc-test.js new file mode 100644 index 0000000..1773874 --- /dev/null +++ b/tests/integration/helpers/sats-to-btc-test.js @@ -0,0 +1,16 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Helper | sats-to-btc', function(hooks) { + setupRenderingTest(hooks); + + test('it converts satoshis to full BTC amounts', async function(assert) { + this.set('amount', '166800'); + + await render(hbs`{{sats-to-btc this.amount}}`); + + assert.equal(this.element.textContent.trim(), '0.001668'); + }); +}); From a96cca879d018b8a4dae2f1082eede2197fcdf0c Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 9 Jul 2020 22:15:25 +0200 Subject: [PATCH 07/57] Use browser's locale for currency format --- app/helpers/fmt-fiat-currency.js | 5 +++-- tests/integration/helpers/fmt-fiat-currency-test.js | 8 ++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/helpers/fmt-fiat-currency.js b/app/helpers/fmt-fiat-currency.js index 712987a..61f75dd 100644 --- a/app/helpers/fmt-fiat-currency.js +++ b/app/helpers/fmt-fiat-currency.js @@ -1,10 +1,11 @@ import { helper } from '@ember/component/helper'; export default helper(function fmtFiatCurrency(params) { - const formatter = new Intl.NumberFormat('en-US', { + const lang = navigator.language || navigator.userLanguage; + const formatter = new Intl.NumberFormat(lang, { style: 'currency', currency: params[1] || 'EUR', - minimumFractionDigits: 2 + currencyDisplay: 'code' }) return formatter.format(params[0]); }); diff --git a/tests/integration/helpers/fmt-fiat-currency-test.js b/tests/integration/helpers/fmt-fiat-currency-test.js index 26dceb5..122760a 100644 --- a/tests/integration/helpers/fmt-fiat-currency-test.js +++ b/tests/integration/helpers/fmt-fiat-currency-test.js @@ -10,9 +10,13 @@ module('Integration | Helper | fmt-fiat-currency', function(hooks) { this.set('amount', 13.9); await render(hbs`{{fmt-fiat-currency this.amount}}`); - assert.equal(this.element.textContent.trim(), '€13.90', 'using EUR amount by default'); + assert.ok(this.element.textContent.trim().match(/13.90/), + 'formats the number with two decimals'); + assert.ok(this.element.textContent.trim().match(/EUR/), + 'using EUR by default'); await render(hbs`{{fmt-fiat-currency this.amount 'USD'}}`); - assert.equal(this.element.textContent.trim(), '$13.90', 'using the defined currency'); + assert.ok(this.element.textContent.trim().match(/USD/), + 'using defined currency when given'); }); }); From fb267813fb8805e151940db609eae6c9c7895ea8 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 9 Jul 2020 22:41:11 +0200 Subject: [PATCH 08/57] Introduce item-list CSS, move item colors to variables --- app/components/contribution-list/template.hbs | 2 +- app/helpers/sats-to-btc.js | 4 +-- app/styles/_colors.scss | 4 +++ app/styles/_item-list.scss | 27 +++++++++++++++++++ app/styles/app.scss | 1 + .../components/_contribution-details.scss | 8 +++--- app/styles/components/_contribution-list.scss | 21 --------------- app/styles/components/_contributor-list.scss | 8 +++--- .../components/_contributor-profile.scss | 8 +++--- 9 files changed, 47 insertions(+), 36 deletions(-) create mode 100644 app/styles/_item-list.scss diff --git a/app/components/contribution-list/template.hbs b/app/components/contribution-list/template.hbs index 42280a2..aecc670 100644 --- a/app/components/contribution-list/template.hbs +++ b/app/components/contribution-list/template.hbs @@ -29,7 +29,7 @@ {{/if}} -
      +
        {{#each this.contributionsFiltered as |contribution|}}
      • Date: Thu, 9 Jul 2020 23:52:39 +0200 Subject: [PATCH 09/57] Style reimbursement list items --- app/components/contribution-list/template.hbs | 2 +- .../reimbursement-list/template.hbs | 30 ++++++---- app/helpers/contribution-status.js | 56 ------------------- app/helpers/item-status.js | 56 +++++++++++++++++++ app/helpers/sats-to-btc.js | 4 +- app/styles/_item-list.scss | 3 +- app/styles/app.scss | 3 +- app/styles/components/_contribution-list.scss | 2 - .../components/_reimbursement-list.scss | 52 +++++++++++++++++ .../dashboard/contributions/show.hbs | 2 +- public/img/bitcoin.svg | 7 +++ ...ion-status-test.js => item-status-test.js} | 4 +- 12 files changed, 145 insertions(+), 76 deletions(-) delete mode 100644 app/helpers/contribution-status.js create mode 100644 app/helpers/item-status.js create mode 100644 app/styles/components/_reimbursement-list.scss create mode 100644 public/img/bitcoin.svg rename tests/unit/helpers/{contribution-status-test.js => item-status-test.js} (84%) diff --git a/app/components/contribution-list/template.hbs b/app/components/contribution-list/template.hbs index aecc670..be603d0 100644 --- a/app/components/contribution-list/template.hbs +++ b/app/components/contribution-list/template.hbs @@ -33,7 +33,7 @@ {{#each this.contributionsFiltered as |contribution|}}
      • + class="{{item-status contribution}}{{if (eq contribution.id @selectedContributionId) " selected"}}">

        ({{contribution.kind}}) diff --git a/app/components/reimbursement-list/template.hbs b/app/components/reimbursement-list/template.hbs index 4c3fe9e..76ecb03 100644 --- a/app/components/reimbursement-list/template.hbs +++ b/app/components/reimbursement-list/template.hbs @@ -1,14 +1,24 @@ -

          +
            {{#each this.itemsSorted as |reimbursement|}} -
          • - {{reimbursement.id}}
            - {{sats-to-btc reimbursement.amount}} WBTC
            - vetoed: {{reimbursement.vetoed}}
            - pay out to: {{reimbursement.contributor.name}}
            - - {{#each reimbursement.expenses as |expense|}} - {{expense.date}}: {{expense.title}} - {{fmt-fiat-currency expense.amount expense.currency}}
            - {{/each}} +
          • +

            + + Expenses covered by {{reimbursement.contributor.name}} +

            +

            + + + {{sats-to-btc reimbursement.amount}}WBTC +

            + + {{#each reimbursement.expenses as |expense|}} + + + + + {{/each}} +
            {{expense.title}} – {{expense.description}}{{fmt-fiat-currency expense.amount expense.currency}}
          • {{/each}}
          \ No newline at end of file diff --git a/app/helpers/contribution-status.js b/app/helpers/contribution-status.js deleted file mode 100644 index 959aa72..0000000 --- a/app/helpers/contribution-status.js +++ /dev/null @@ -1,56 +0,0 @@ -import Helper from '@ember/component/helper'; -import { inject as service } from '@ember/service'; -import { alias } from '@ember/object/computed'; -import { once } from '@ember/runloop'; - -export default Helper.extend({ - - kredits: service(), - currentBlock: alias('kredits.currentBlock'), - - compute([contribution]) { - this.setupRecompute(contribution); - - let status = []; - - if (contribution.vetoed) { - status.push('vetoed'); - } else if (contribution.confirmedAt > this.currentBlock) { - status.push('unconfirmed'); - } else { - 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); - } - -}); diff --git a/app/helpers/item-status.js b/app/helpers/item-status.js new file mode 100644 index 0000000..e86ee3f --- /dev/null +++ b/app/helpers/item-status.js @@ -0,0 +1,56 @@ +import Helper from '@ember/component/helper'; +import { inject as service } from '@ember/service'; +import { alias } from '@ember/object/computed'; +import { once } from '@ember/runloop'; + +export default Helper.extend({ + + kredits: service(), + currentBlock: alias('kredits.currentBlock'), + + compute([item]) { + this.setupRecompute(item); + + let status = []; + + if (item.vetoed) { + status.push('vetoed'); + } else if (item.confirmedAt > this.currentBlock) { + status.push('unconfirmed'); + } else { + status.push('confirmed'); + } + + if (item.hasPendingChanges) { + status.push('pending'); + } + + return status.join(' '); + }, + + destroy () { + if (this.teardown) this.teardown(); + this._super(...arguments); + }, + + setupRecompute (item) { + if (this.teardown) this.teardown(); + + item.addObserver('vetoed' , this, this.triggerRecompute); + item.addObserver('confirmedAt' , this, this.triggerRecompute); + item.addObserver('currentBlock' , this, this.triggerRecompute); + item.addObserver('hasPendingChanges' , this, this.triggerRecompute); + + this.teardown = () => { + item.removeObserver('vetoed', this, this.triggerRecompute); + item.removeObserver('confirmedAt', this, this.triggerRecompute); + item.removeObserver('currentBlock', this, this.triggerRecompute); + item.removeObserver('hasPendingChanges', this, this.triggerRecompute); + }; + }, + + triggerRecompute () { + once(this, this.recompute); + } + +}); diff --git a/app/helpers/sats-to-btc.js b/app/helpers/sats-to-btc.js index eccfed7..319004e 100644 --- a/app/helpers/sats-to-btc.js +++ b/app/helpers/sats-to-btc.js @@ -1,5 +1,5 @@ import { helper } from '@ember/component/helper'; -export default helper(function satsToBtc(params/*, hash*/) { - return params; +export default helper(function satsToBtc(amount/*, hash*/) { + return amount / 100000000; }); diff --git a/app/styles/_item-list.scss b/app/styles/_item-list.scss index a3877f2..1bfcf0b 100644 --- a/app/styles/_item-list.scss +++ b/app/styles/_item-list.scss @@ -2,9 +2,10 @@ ul.item-list { list-style: none; li { + padding: 0.8rem 1.2rem; + font-size: 1.2rem; background-color: $item-background-color; border-bottom: 1px solid $item-border-color; - font-size: 1.2rem; &:first-of-type { border-top: 1px solid $item-border-color; diff --git a/app/styles/app.scss b/app/styles/app.scss index 5af3d7a..858471c 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -91,12 +91,13 @@ section { @import "sugar"; @import "item-list"; -@import "components/contribution-list"; @import "components/contribution-details"; +@import "components/contribution-list"; @import "components/contributor-list"; @import "components/contributor-profile"; @import "components/external-account-link"; @import "components/loading-spinner"; +@import "components/reimbursement-list"; @import "components/topbar"; @import "components/topbar-account-panel"; @import "components/user-avatar"; diff --git a/app/styles/components/_contribution-list.scss b/app/styles/components/_contribution-list.scss index ab51c4d..2c6034d 100644 --- a/app/styles/components/_contribution-list.scss +++ b/app/styles/components/_contribution-list.scss @@ -24,13 +24,11 @@ main section { ul.contribution-list { clear: both; width: 100%; - list-style: none; li { display: grid; grid-template-columns: auto 5rem 5rem; grid-row-gap: 0.5rem; - padding: 0.8rem 1.2rem; cursor: pointer; &.confirmed { diff --git a/app/styles/components/_reimbursement-list.scss b/app/styles/components/_reimbursement-list.scss new file mode 100644 index 0000000..e7b0167 --- /dev/null +++ b/app/styles/components/_reimbursement-list.scss @@ -0,0 +1,52 @@ +ul.reimbursement-list { + width: 100%; + + li { + display: grid; + grid-template-columns: auto auto; + grid-row-gap: 0.5rem; + padding-top: 1.6rem; + + .token-amount { + text-align: right; + + img { + height: 1em; + vertical-align: middle; + margin-top: -2px; + } + + .amount { + font-weight: 500; + } + + .symbol { + font-size: 0.8rem; + padding-left: 0.2rem; + } + } + + table { + grid-column-start: span 2; + width: 100%; + margin-top: 0.8rem; + border-collapse: collapse; + + tr { + border-top: 1px solid $item-border-color; + } + + td { + padding: 0.8rem 0; + + &.amount { + text-align: right; + } + } + + @include media-max(small) { + td.date { display: none; } + } + } + } +} diff --git a/app/templates/dashboard/contributions/show.hbs b/app/templates/dashboard/contributions/show.hbs index a447c1e..52d6b3d 100644 --- a/app/templates/dashboard/contributions/show.hbs +++ b/app/templates/dashboard/contributions/show.hbs @@ -19,7 +19,7 @@

          {{this.model.description}}

          Kind: {{this.model.kind}} -
          Status: {{contribution-status this.model}} +
          Status: {{item-status this.model}}

          {{#if this.model.url}}

          diff --git a/public/img/bitcoin.svg b/public/img/bitcoin.svg new file mode 100644 index 0000000..b3fd9e3 --- /dev/null +++ b/public/img/bitcoin.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/unit/helpers/contribution-status-test.js b/tests/unit/helpers/item-status-test.js similarity index 84% rename from tests/unit/helpers/contribution-status-test.js rename to tests/unit/helpers/item-status-test.js index f0b9f91..0496f27 100644 --- a/tests/unit/helpers/contribution-status-test.js +++ b/tests/unit/helpers/item-status-test.js @@ -2,11 +2,11 @@ import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; import Contribution from 'kredits-web/models/contribution'; -module('Unit | Helper | contribution-status', function (hooks) { +module('Unit | Helper | item-status', function (hooks) { setupTest(hooks); test('returns the appropriate status', function (assert) { - const contributionStatus = this.owner.factoryFor('helper:contribution-status').create(); + const contributionStatus = this.owner.factoryFor('helper:item-status').create(); const kredits = this.owner.lookup('service:kredits'); kredits.set('currentBlock', 23000); From 8074d2d0e3ea0706c4f5b6c2e337e0cecc611f79 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Fri, 10 Jul 2020 13:01:06 +0200 Subject: [PATCH 10/57] Hide empty sections in budget --- app/templates/budget.hbs | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/app/templates/budget.hbs b/app/templates/budget.hbs index 80dd73d..20d4546 100644 --- a/app/templates/budget.hbs +++ b/app/templates/budget.hbs @@ -48,23 +48,27 @@

          -
          -
          -

          Proposed Reimbursements

          -
          -
          - -
          -
          + {{#if this.reimbursementsUnconfirmed}} +
          +
          +

          Proposed Reimbursements

          +
          +
          + +
          +
          + {{/if}} -
          -
          -

          Confirmed Expenses

          -
          -
          - -
          -
          + {{#if this.reimbursementsConfirmed}} +
          +
          +

          Confirmed Expenses

          +
          +
          + +
          +
          + {{/if}}
          From 69a6c850bf4eec70be0cd5f1210a35fafd24c904 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Sat, 25 Jul 2020 18:22:02 +0200 Subject: [PATCH 11/57] Convert route to class --- app/routes/contributions/new.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/routes/contributions/new.js b/app/routes/contributions/new.js index 7d760ab..a3eb6a3 100644 --- a/app/routes/contributions/new.js +++ b/app/routes/contributions/new.js @@ -1,9 +1,9 @@ import Route from '@ember/routing/route'; -export default Route.extend({ +export default class ContributionsNewRoute extends Route { model (params) { return { params }; } -}); +} From 083334ed18bd5af7ff71a49d9f6b68aa950f6699 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Sat, 25 Jul 2020 18:23:55 +0200 Subject: [PATCH 12/57] Don't redirect to dashboard after connecting web3 account --- app/components/topbar-account-panel/component.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/topbar-account-panel/component.js b/app/components/topbar-account-panel/component.js index d7ae8a4..b4ad5dd 100644 --- a/app/components/topbar-account-panel/component.js +++ b/app/components/topbar-account-panel/component.js @@ -34,7 +34,7 @@ export default Component.extend({ this.set('setupInProgress', true); await this.kredits.setup(); this.set('setupInProgress', false); - this.router.transitionTo('dashboard'); + // this.router.transitionTo('dashboard'); } catch (error) { this.set('setupInProgress', false); console.log('Opening Ethereum wallet failed:', error); From ef0fc11edfeba4ee9aa8701dc72cde5172b700a6 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Sat, 25 Jul 2020 18:24:16 +0200 Subject: [PATCH 13/57] Add reimbursement form route and component --- app/components/add-reimbursement/template.hbs | 1 + app/router.js | 6 +++++ app/routes/reimbursements/new.js | 9 +++++++ .../components/_reimbursement-list.scss | 2 +- app/templates/budget.hbs | 10 +++++-- app/templates/reimbursements/new.hbs | 13 ++++++++++ .../add-reimbursement/component-test.js | 26 +++++++++++++++++++ tests/unit/routes/reimbursements/new-test.js | 11 ++++++++ 8 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 app/components/add-reimbursement/template.hbs create mode 100644 app/routes/reimbursements/new.js create mode 100644 app/templates/reimbursements/new.hbs create mode 100644 tests/integration/components/add-reimbursement/component-test.js create mode 100644 tests/unit/routes/reimbursements/new-test.js diff --git a/app/components/add-reimbursement/template.hbs b/app/components/add-reimbursement/template.hbs new file mode 100644 index 0000000..fb5c4b1 --- /dev/null +++ b/app/components/add-reimbursement/template.hbs @@ -0,0 +1 @@ +{{yield}} \ No newline at end of file diff --git a/app/router.js b/app/router.js index 52d8cf8..b0941de 100644 --- a/app/router.js +++ b/app/router.js @@ -31,5 +31,11 @@ Router.map(function() { }); this.route('budget', function() { this.route('expenses'); + + this.route('reimbursements', function() {}); + }); + + this.route('reimbursements', function() { + this.route('new'); }); }); diff --git a/app/routes/reimbursements/new.js b/app/routes/reimbursements/new.js new file mode 100644 index 0000000..0e3509d --- /dev/null +++ b/app/routes/reimbursements/new.js @@ -0,0 +1,9 @@ +import Route from '@ember/routing/route'; + +export default class ReimbursementsNewRoute extends Route { + + model (params) { + return { params }; + } + +} diff --git a/app/styles/components/_reimbursement-list.scss b/app/styles/components/_reimbursement-list.scss index e7b0167..c5f6458 100644 --- a/app/styles/components/_reimbursement-list.scss +++ b/app/styles/components/_reimbursement-list.scss @@ -3,7 +3,7 @@ ul.reimbursement-list { li { display: grid; - grid-template-columns: auto auto; + grid-template-columns: auto 10rem; grid-row-gap: 0.5rem; padding-top: 1.6rem; diff --git a/app/templates/budget.hbs b/app/templates/budget.hbs index 20d4546..066cd82 100644 --- a/app/templates/budget.hbs +++ b/app/templates/budget.hbs @@ -50,8 +50,11 @@
          {{#if this.reimbursementsUnconfirmed}}
          -
          +

          Proposed Reimbursements

          +
          @@ -61,8 +64,11 @@ {{#if this.reimbursementsConfirmed}}
          -
          +

          Confirmed Expenses

          +
          diff --git a/app/templates/reimbursements/new.hbs b/app/templates/reimbursements/new.hbs new file mode 100644 index 0000000..1596085 --- /dev/null +++ b/app/templates/reimbursements/new.hbs @@ -0,0 +1,13 @@ +
          + +
          +
          +

          Submit a reimbursement

          +
          + +
          + +
          +
          + +
          \ No newline at end of file diff --git a/tests/integration/components/add-reimbursement/component-test.js b/tests/integration/components/add-reimbursement/component-test.js new file mode 100644 index 0000000..da9bed2 --- /dev/null +++ b/tests/integration/components/add-reimbursement/component-test.js @@ -0,0 +1,26 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | add-reimbursement', function(hooks) { + setupRenderingTest(hooks); + + test('it renders', async function(assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.set('myAction', function(val) { ... }); + + await render(hbs``); + + assert.equal(this.element.textContent.trim(), ''); + + // Template block usage: + await render(hbs` + + template block text + + `); + + assert.equal(this.element.textContent.trim(), 'template block text'); + }); +}); diff --git a/tests/unit/routes/reimbursements/new-test.js b/tests/unit/routes/reimbursements/new-test.js new file mode 100644 index 0000000..e98d799 --- /dev/null +++ b/tests/unit/routes/reimbursements/new-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Route | reimbursements/new', function(hooks) { + setupTest(hooks); + + test('it exists', function(assert) { + let route = this.owner.lookup('route:reimbursements/new'); + assert.ok(route); + }); +}); From f63d14d7b41a3f32ef988bf0b4587c691932aea7 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Wed, 12 Aug 2020 22:51:52 +0200 Subject: [PATCH 14/57] Move sorted contributors to kredits service --- app/components/add-contribution/component.js | 8 ++++---- app/services/kredits.js | 6 +++++- app/templates/contributions/new.hbs | 3 +-- tests/unit/services/kredits-test.js | 8 ++++++++ 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/components/add-contribution/component.js b/app/components/add-contribution/component.js index 56de353..96c4f48 100644 --- a/app/components/add-contribution/component.js +++ b/app/components/add-contribution/component.js @@ -1,13 +1,15 @@ import Component from '@ember/component'; import { computed } from '@ember/object'; -import { and, notEmpty } from '@ember/object/computed'; +import { alias, and, notEmpty } from '@ember/object/computed'; import { assign } from '@ember/polyfills'; import moment from 'moment'; +import { inject as service } from '@ember/service'; export default Component.extend({ + kredits: service(), attributes: null, - contributors: Object.freeze([]), + contributors: alias('kredits.contributorsSorted'), isValidContributor: notEmpty('contributorId'), isValidKind: notEmpty('kind'), @@ -72,7 +74,5 @@ export default Component.extend({ }) .finally(() => this.set('inProgress', false)); } - } - }); diff --git a/app/services/kredits.js b/app/services/kredits.js index bcc32f4..0e1bcff 100644 --- a/app/services/kredits.js +++ b/app/services/kredits.js @@ -4,7 +4,7 @@ import Kredits from 'kredits-contracts'; import Service from '@ember/service'; import EmberObject from '@ember/object'; import { computed } from '@ember/object'; -import { alias, notEmpty } from '@ember/object/computed'; +import { alias, filterBy, notEmpty, sort } from '@ember/object/computed'; import { isEmpty, isPresent } from '@ember/utils'; import { inject as service } from '@ember/service'; @@ -39,6 +39,10 @@ export default Service.extend({ currentUserIsCore: alias('currentUser.isCore'), hasAccounts: notEmpty('currentUserAccounts'), + contributorsMined: filterBy('contributors', 'id'), + contributorsSorting: Object.freeze(['name:asc']), + contributorsSorted: sort('contributorsMined', 'contributorsSorting'), + // When data was loaded from cache, we need to fetch updates from the network contributorsNeedSync: false, contributionsNeedSync: false, diff --git a/app/templates/contributions/new.hbs b/app/templates/contributions/new.hbs index e0ecce3..984343f 100644 --- a/app/templates/contributions/new.hbs +++ b/app/templates/contributions/new.hbs @@ -6,8 +6,7 @@
          -
          diff --git a/tests/unit/services/kredits-test.js b/tests/unit/services/kredits-test.js index f18e067..526a5a4 100644 --- a/tests/unit/services/kredits-test.js +++ b/tests/unit/services/kredits-test.js @@ -49,4 +49,12 @@ module('Unit | Service | kredits', function(hooks) { assert.equal(c3.amountUnconfirmed, 5000, 'correct amount unconfirmed'); assert.equal(c3.amountTotal, 5000, 'correct amount total'); }); + + test('#contributorsSorted', function(assert) { + let service = this.owner.lookup('service:kredits'); + service.set('contributors', contributors); + + assert.ok(service.contributorsSorted instanceof Array, 'is an array'); + assert.equal(service.contributorsSorted[1].name, 'Manuel', 'sorts by name'); + }); }); From 52172ea065fbb986ad6630083f1a0339f9d71b4e Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Wed, 12 Aug 2020 22:53:08 +0200 Subject: [PATCH 15/57] add-reimbursement component --- app/components/add-reimbursement/component.js | 8 ++++++++ app/components/add-reimbursement/template.hbs | 1 - app/templates/reimbursements/new.hbs | 2 +- .../components/add-reimbursement/component-test.js | 11 ----------- 4 files changed, 9 insertions(+), 13 deletions(-) create mode 100644 app/components/add-reimbursement/component.js diff --git a/app/components/add-reimbursement/component.js b/app/components/add-reimbursement/component.js new file mode 100644 index 0000000..79805cf --- /dev/null +++ b/app/components/add-reimbursement/component.js @@ -0,0 +1,8 @@ + +import Component from '@glimmer/component'; +import { inject as service } from '@ember/service'; + +export default class AddReimbursementComponent extends Component { + @service kredits; + +} diff --git a/app/components/add-reimbursement/template.hbs b/app/components/add-reimbursement/template.hbs index fb5c4b1..e69de29 100644 --- a/app/components/add-reimbursement/template.hbs +++ b/app/components/add-reimbursement/template.hbs @@ -1 +0,0 @@ -{{yield}} \ No newline at end of file diff --git a/app/templates/reimbursements/new.hbs b/app/templates/reimbursements/new.hbs index 1596085..154c3d7 100644 --- a/app/templates/reimbursements/new.hbs +++ b/app/templates/reimbursements/new.hbs @@ -2,7 +2,7 @@
          -

          Submit a reimbursement

          +

          Submit a Reimbursement

          diff --git a/tests/integration/components/add-reimbursement/component-test.js b/tests/integration/components/add-reimbursement/component-test.js index da9bed2..a6b5dc7 100644 --- a/tests/integration/components/add-reimbursement/component-test.js +++ b/tests/integration/components/add-reimbursement/component-test.js @@ -9,18 +9,7 @@ module('Integration | Component | add-reimbursement', function(hooks) { test('it renders', async function(assert) { // Set any properties with this.set('myProperty', 'value'); // Handle any actions with this.set('myAction', function(val) { ... }); - await render(hbs``); - assert.equal(this.element.textContent.trim(), ''); - - // Template block usage: - await render(hbs` - - template block text - - `); - - assert.equal(this.element.textContent.trim(), 'template block text'); }); }); From dec71c6f4f1722be613fe1a3e1bfbd3dda567819 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 13 Aug 2020 00:27:40 +0200 Subject: [PATCH 16/57] Load community funds balances from mainnet Gnosis Safe --- app/components/budget-balances/component.js | 6 + app/components/budget-balances/template.hbs | 21 ++ app/routes/application.js | 6 +- app/services/community-funds.js | 32 +++ app/services/kredits.js | 2 +- app/templates/budget.hbs | 22 +- config/environment.js | 5 + package-lock.json | 266 ++++++++++++++++++ package.json | 1 + .../budget-balances/component-test.js | 26 ++ tests/unit/services/community-funds-test.js | 12 + 11 files changed, 375 insertions(+), 24 deletions(-) create mode 100644 app/components/budget-balances/component.js create mode 100644 app/components/budget-balances/template.hbs create mode 100644 app/services/community-funds.js create mode 100644 tests/integration/components/budget-balances/component-test.js create mode 100644 tests/unit/services/community-funds-test.js diff --git a/app/components/budget-balances/component.js b/app/components/budget-balances/component.js new file mode 100644 index 0000000..4c903e1 --- /dev/null +++ b/app/components/budget-balances/component.js @@ -0,0 +1,6 @@ +import Component from '@glimmer/component'; +import { inject as service } from '@ember/service'; + +export default class BudgetBalancesComponent extends Component { + @service communityFunds +} diff --git a/app/components/budget-balances/template.hbs b/app/components/budget-balances/template.hbs new file mode 100644 index 0000000..617db91 --- /dev/null +++ b/app/components/budget-balances/template.hbs @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + +
          TokenAmountFiat value
          WBTC{{this.communityFunds.balanceWBTC.balance}}{{this.communityFunds.balanceWBTC.balanceUsd}} USD
          ETH{{this.communityFunds.balanceETH.balance}}{{this.communityFunds.balanceETH.balanceUsd}} USD
          \ No newline at end of file diff --git a/app/routes/application.js b/app/routes/application.js index 638ddd3..a7470a0 100644 --- a/app/routes/application.js +++ b/app/routes/application.js @@ -3,8 +3,8 @@ import { inject as service } from '@ember/service'; import { schedule } from '@ember/runloop'; export default class ApplicationRoute extends Route { - @service kredits; + @service communityFunds; beforeModel(/* transition */) { const kredits = this.kredits; @@ -30,6 +30,8 @@ export default class ApplicationRoute extends Route { schedule('afterRender', this.kredits.syncContributors, this.kredits.syncContributors.perform); } - } + schedule('afterRender', this.communityFunds.fetchBalances, + this.communityFunds.fetchBalances.perform); + } } diff --git a/app/services/community-funds.js b/app/services/community-funds.js new file mode 100644 index 0000000..8c6eabd --- /dev/null +++ b/app/services/community-funds.js @@ -0,0 +1,32 @@ +import Service from '@ember/service'; +import { tracked } from '@glimmer/tracking'; +import { task } from 'ember-concurrency-decorators'; +import config from 'kredits-web/config/environment'; + +const txServiceBaseUrl = `${config.gnosisSafe.txServiceHost}/api/v1/safes/${config.gnosisSafe.address}`; + +export default class CommunityFundsService extends Service { + @tracked balanceETH = { balance: 0, balanceUsd: 0, usdConversion: 0 }; + @tracked balanceWBTC = { balance: 0, balanceUsd: 0, usdConversion: 0 }; + + @task + *fetchBalances () { + const uri = `${txServiceBaseUrl}/balances/usd/`; + + yield fetch(uri).then(res => res.json()) + .then(res => { + this.processBalances(res); + }) + .catch(err => { + console.log(`[community-funds] Fetching balances failed:`); + console.error(err); + }); + } + + processBalances (res) { + // TODO proper selection/find + const { balance, balanceUsd, usdConversion } = res[0]; + this.balanceETH = { balance, balanceUsd, usdConversion }; + this.balanceWBTC = res[1]; + } +} diff --git a/app/services/kredits.js b/app/services/kredits.js index 0e1bcff..391b8d3 100644 --- a/app/services/kredits.js +++ b/app/services/kredits.js @@ -21,7 +21,7 @@ import Contributor from 'kredits-web/models/contributor'; import Contribution from 'kredits-web/models/contribution'; import Reimbursement from 'kredits-web/models/reimbursement'; // Lets us access the model classes dynamically -const models = { Contributor, Contribution, Reimbursement } +const models = { Contributor, Contribution, Reimbursement }; export default Service.extend({ diff --git a/app/templates/budget.hbs b/app/templates/budget.hbs index 066cd82..fcac21c 100644 --- a/app/templates/budget.hbs +++ b/app/templates/budget.hbs @@ -22,27 +22,7 @@

          Community funds

          - - - - - - - - - - - - - - - - - - - - -
          TokenAmountFiat value
          WBTC1.1721511031.15 USD
          ETH0.5115.60 USD
          +
          diff --git a/config/environment.js b/config/environment.js index e2c59ea..9d18af7 100644 --- a/config/environment.js +++ b/config/environment.js @@ -50,6 +50,11 @@ module.exports = function(environment) { tokens: { 'WBTC': '0x2260fac5e5542a773aa44fbcfedf7c193bc2c599' + }, + + gnosisSafe: { + txServiceHost: 'https://safe-transaction.mainnet.gnosis.io', + address: '0x9CC29b8373FF92B01C1f09F31B5DD862350c167E' } }; diff --git a/package-lock.json b/package-lock.json index 4669c89..fdfe8d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2582,6 +2582,15 @@ "integrity": "sha512-tGRdvgC9/QMQSuSuJV45xoyhI0Pzjm7A9o/MVVA3HakXIImJbbzx/k/6dO9CUEQXIyS2y0fW6C1XaYOG7rY0FQ==", "dev": true }, + "@ember-decorators/utils": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@ember-decorators/utils/-/utils-6.1.1.tgz", + "integrity": "sha512-0KqnoeoLKb6AyoSU65TRF5T85wmS4uDn06oARddwNPxxf/lt5jQlh41uX3W7V/fWL9tPu8x1L1Vvpc80MN1+YA==", + "dev": true, + "requires": { + "ember-cli-babel": "^7.1.3" + } + }, "@ember/edition-utils": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ember/edition-utils/-/edition-utils-1.2.0.tgz", @@ -11284,6 +11293,263 @@ "ember-maybe-import-regenerator": "^0.1.6" } }, + "ember-concurrency-decorators": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ember-concurrency-decorators/-/ember-concurrency-decorators-2.0.1.tgz", + "integrity": "sha512-KJ8mCZxmvgalawh/zytURsc5ParNr9avPeCDR/mE7VQxWvITHtyAuYS2s1PPFQAQggTXTZYcGnfgzjn/cDHNMQ==", + "dev": true, + "requires": { + "@ember-decorators/utils": "^6.1.0", + "ember-cli-babel": "^7.19.0", + "ember-cli-htmlbars": "^4.3.1", + "ember-cli-typescript": "^3.1.4" + }, + "dependencies": { + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "@babel/plugin-transform-typescript": { + "version": "7.8.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.8.7.tgz", + "integrity": "sha512-7O0UsPQVNKqpHeHLpfvOG4uXmlw+MOxYvUv6Otc9uH5SYMIxvF6eBdjkWvC3f9G+VXe0RsNExyAQBeTRug/wqQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.8.3", + "@babel/helper-plugin-utils": "^7.8.3", + "@babel/plugin-syntax-typescript": "^7.8.3" + } + }, + "babel-plugin-htmlbars-inline-precompile": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-htmlbars-inline-precompile/-/babel-plugin-htmlbars-inline-precompile-3.2.0.tgz", + "integrity": "sha512-IUeZmgs9tMUGXYu1vfke5I18yYJFldFGdNFQOWslXTnDWXzpwPih7QFduUqvT+awDpDuNtXpdt5JAf43Q1Hhzg==", + "dev": true + }, + "broccoli-persistent-filter": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/broccoli-persistent-filter/-/broccoli-persistent-filter-2.3.1.tgz", + "integrity": "sha512-hVsmIgCDrl2NFM+3Gs4Cr2TA6UPaIZip99hN8mtkaUPgM8UeVnCbxelCvBjUBHo0oaaqP5jzqqnRVvb568Yu5g==", + "dev": true, + "requires": { + "async-disk-cache": "^1.2.1", + "async-promise-queue": "^1.0.3", + "broccoli-plugin": "^1.0.0", + "fs-tree-diff": "^2.0.0", + "hash-for-dep": "^1.5.0", + "heimdalljs": "^0.2.1", + "heimdalljs-logger": "^0.1.7", + "mkdirp": "^0.5.1", + "promise-map-series": "^0.2.1", + "rimraf": "^2.6.1", + "rsvp": "^4.7.0", + "symlink-or-copy": "^1.0.1", + "sync-disk-cache": "^1.3.3", + "walk-sync": "^1.0.0" + }, + "dependencies": { + "broccoli-plugin": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-1.3.1.tgz", + "integrity": "sha512-DW8XASZkmorp+q7J4EeDEZz+LoyKLAd2XZULXyD9l4m9/hAKV3vjHmB1kiUshcWAYMgTP1m2i4NnqCE/23h6AQ==", + "dev": true, + "requires": { + "promise-map-series": "^0.2.1", + "quick-temp": "^0.1.3", + "rimraf": "^2.3.4", + "symlink-or-copy": "^1.1.8" + } + }, + "walk-sync": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-1.1.4.tgz", + "integrity": "sha512-nowc9thB/Jg0KW4TgxoRjLLYRPvl3DB/98S89r4ZcJqq2B0alNcKDh6pzLkBSkPMzRSMsJghJHQi79qw0YWEkA==", + "dev": true, + "requires": { + "@types/minimatch": "^3.0.3", + "ensure-posix-path": "^1.1.0", + "matcher-collection": "^1.1.1" + } + } + } + }, + "broccoli-plugin": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/broccoli-plugin/-/broccoli-plugin-3.1.0.tgz", + "integrity": "sha512-7w7FP8WJYjLvb0eaw27LO678TGGaom++49O1VYIuzjhXjK5kn2+AMlDm7CaUFw4F7CLGoVQeZ84d8gICMJa4lA==", + "dev": true, + "requires": { + "broccoli-node-api": "^1.6.0", + "broccoli-output-wrapper": "^2.0.0", + "fs-merger": "^3.0.1", + "promise-map-series": "^0.2.1", + "quick-temp": "^0.1.3", + "rimraf": "^2.3.4", + "symlink-or-copy": "^1.1.8" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ember-cli-htmlbars": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ember-cli-htmlbars/-/ember-cli-htmlbars-4.4.0.tgz", + "integrity": "sha512-ohgctqk7dXIZR4TgN0xRoUYltWhghFJgqmtuswQTpZ7p74RxI9PKx+E8WV/95mGcPzraesvMNBg5utQNvcqgNg==", + "dev": true, + "requires": { + "@ember/edition-utils": "^1.2.0", + "babel-plugin-htmlbars-inline-precompile": "^3.2.0", + "broccoli-debug": "^0.6.5", + "broccoli-persistent-filter": "^2.3.1", + "broccoli-plugin": "^3.1.0", + "common-tags": "^1.8.0", + "ember-cli-babel-plugin-helpers": "^1.1.0", + "fs-tree-diff": "^2.0.1", + "hash-for-dep": "^1.5.1", + "heimdalljs-logger": "^0.1.10", + "json-stable-stringify": "^1.0.1", + "semver": "^6.3.0", + "strip-bom": "^4.0.0", + "walk-sync": "^2.0.2" + } + }, + "ember-cli-typescript": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/ember-cli-typescript/-/ember-cli-typescript-3.1.4.tgz", + "integrity": "sha512-HJ73kL45OGRmIkPhBNFt31I1SGUvdZND+LCH21+qpq3pPlFpJG8GORyXpP+2ze8PbnITNLzwe5AwUrpyuRswdQ==", + "dev": true, + "requires": { + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.4.4", + "@babel/plugin-proposal-optional-chaining": "^7.6.0", + "@babel/plugin-transform-typescript": "~7.8.0", + "ansi-to-html": "^0.6.6", + "broccoli-stew": "^3.0.0", + "debug": "^4.0.0", + "ember-cli-babel-plugin-helpers": "^1.0.0", + "execa": "^3.0.0", + "fs-extra": "^8.0.0", + "resolve": "^1.5.0", + "rsvp": "^4.8.1", + "semver": "^6.3.0", + "stagehand": "^1.0.0", + "walk-sync": "^2.0.0" + } + }, + "execa": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz", + "integrity": "sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "p-finally": "^2.0.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-tree-diff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fs-tree-diff/-/fs-tree-diff-2.0.1.tgz", + "integrity": "sha512-x+CfAZ/lJHQqwlD64pYM5QxWjzWhSjroaVsr8PW831zOApL55qPibed0c+xebaLWVr2BnHFoHdrwOv8pzt8R5A==", + "dev": true, + "requires": { + "@types/symlink-or-copy": "^1.2.0", + "heimdalljs-logger": "^0.1.7", + "object-assign": "^4.1.0", + "path-posix": "^1.0.0", + "symlink-or-copy": "^1.1.8" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "walk-sync": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-2.2.0.tgz", + "integrity": "sha512-IC8sL7aB4/ZgFcGI2T1LczZeFWZ06b3zoHH7jBPyHxOtIIz1jppWHjjEXkOFvFojBVAK9pV7g47xOZ4LW3QLfg==", + "dev": true, + "requires": { + "@types/minimatch": "^3.0.3", + "ensure-posix-path": "^1.1.0", + "matcher-collection": "^2.0.0", + "minimatch": "^3.0.4" + }, + "dependencies": { + "matcher-collection": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-2.0.1.tgz", + "integrity": "sha512-daE62nS2ZQsDg9raM0IlZzLmI2u+7ZapXBwdoeBUKAYERPDDIc0qNqA8E0Rp2D+gspKR7BgIFP52GeujaGXWeQ==", + "dev": true, + "requires": { + "@types/minimatch": "^3.0.3", + "minimatch": "^3.0.2" + } + } + } + } + } + }, "ember-diff-attrs": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/ember-diff-attrs/-/ember-diff-attrs-0.2.2.tgz", diff --git a/package.json b/package.json index dc7b99c..387ebff 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "ember-cli-sri": "^2.1.1", "ember-cli-uglify": "^3.0.0", "ember-concurrency": "^1.1.7", + "ember-concurrency-decorators": "^2.0.1", "ember-export-application-global": "^2.0.1", "ember-fetch": "^8.0.1", "ember-flatpickr": "^2.16.2", diff --git a/tests/integration/components/budget-balances/component-test.js b/tests/integration/components/budget-balances/component-test.js new file mode 100644 index 0000000..cdf9bdd --- /dev/null +++ b/tests/integration/components/budget-balances/component-test.js @@ -0,0 +1,26 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | budget-balances', function(hooks) { + setupRenderingTest(hooks); + + test('it renders', async function(assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.set('myAction', function(val) { ... }); + + await render(hbs``); + + assert.equal(this.element.textContent.trim(), ''); + + // Template block usage: + await render(hbs` + + template block text + + `); + + assert.equal(this.element.textContent.trim(), 'template block text'); + }); +}); diff --git a/tests/unit/services/community-funds-test.js b/tests/unit/services/community-funds-test.js new file mode 100644 index 0000000..8c6fad6 --- /dev/null +++ b/tests/unit/services/community-funds-test.js @@ -0,0 +1,12 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Service | community-funds', function(hooks) { + setupTest(hooks); + + // Replace this with your real tests. + test('it exists', function(assert) { + let service = this.owner.lookup('service:community-funds'); + assert.ok(service); + }); +}); From ec6b72008d0e991c6dd027de938be107cbb95e16 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 13 Aug 2020 14:58:49 +0200 Subject: [PATCH 17/57] Add whitespace between reimbursement items in list They're a bit difficult to scan otherwise. --- app/components/reimbursement-list/template.hbs | 2 +- app/styles/_item-list.scss | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/components/reimbursement-list/template.hbs b/app/components/reimbursement-list/template.hbs index 76ecb03..0bdd008 100644 --- a/app/components/reimbursement-list/template.hbs +++ b/app/components/reimbursement-list/template.hbs @@ -1,4 +1,4 @@ -
            +
              {{#each this.itemsSorted as |reimbursement|}}
            • diff --git a/app/styles/_item-list.scss b/app/styles/_item-list.scss index 1bfcf0b..bdef14c 100644 --- a/app/styles/_item-list.scss +++ b/app/styles/_item-list.scss @@ -25,4 +25,11 @@ ul.item-list { } } } + + &.spaced { + li { + border-top: 1px solid $item-border-color; + margin-bottom: 2rem; + } + } } From f1bd20a6f409a4c6036423c912098e68b8aa9521 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 13 Aug 2020 15:19:17 +0200 Subject: [PATCH 18/57] Add helper for formatting cryptocurrencies --- app/helpers/fmt-crypto-currency.js | 18 ++++++++++++++++ .../budget-balances/component-test.js | 21 ++++--------------- .../helpers/fmt-crypto-currency-test.js | 20 ++++++++++++++++++ 3 files changed, 42 insertions(+), 17 deletions(-) create mode 100644 app/helpers/fmt-crypto-currency.js create mode 100644 tests/integration/helpers/fmt-crypto-currency-test.js diff --git a/app/helpers/fmt-crypto-currency.js b/app/helpers/fmt-crypto-currency.js new file mode 100644 index 0000000..76e47c4 --- /dev/null +++ b/app/helpers/fmt-crypto-currency.js @@ -0,0 +1,18 @@ +import { helper } from '@ember/component/helper'; + +export default helper(function fmtCryptoCurrency(params/*, hash*/) { + let fmtAmount; + const amount = params[0]; + const code = params[1]; + + switch(code) { + case 'ETH': + fmtAmount = amount / 1000000000000000000; + break; + case 'WBTC': + fmtAmount = amount / 100000000; + break; + } + + return fmtAmount; +}); diff --git a/tests/integration/components/budget-balances/component-test.js b/tests/integration/components/budget-balances/component-test.js index cdf9bdd..c786b6e 100644 --- a/tests/integration/components/budget-balances/component-test.js +++ b/tests/integration/components/budget-balances/component-test.js @@ -6,21 +6,8 @@ import { hbs } from 'ember-cli-htmlbars'; module('Integration | Component | budget-balances', function(hooks) { setupRenderingTest(hooks); - test('it renders', async function(assert) { - // Set any properties with this.set('myProperty', 'value'); - // Handle any actions with this.set('myAction', function(val) { ... }); - - await render(hbs``); - - assert.equal(this.element.textContent.trim(), ''); - - // Template block usage: - await render(hbs` - - template block text - - `); - - assert.equal(this.element.textContent.trim(), 'template block text'); - }); + // test('it renders', async function(assert) { + // await render(hbs``); + // assert.equal(this.element.textContent.trim(), ''); + // }); }); diff --git a/tests/integration/helpers/fmt-crypto-currency-test.js b/tests/integration/helpers/fmt-crypto-currency-test.js new file mode 100644 index 0000000..a27bcb9 --- /dev/null +++ b/tests/integration/helpers/fmt-crypto-currency-test.js @@ -0,0 +1,20 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Helper | fmt-crypto-currency', function(hooks) { + setupRenderingTest(hooks); + + test('it converts Wei to ETH', async function(assert) { + this.set('balanceETH', '500000000000000000'); + await render(hbs`{{fmt-crypto-currency balanceETH "ETH"}}`); + assert.equal(this.element.textContent.trim(), '0.5'); + }); + + test('it converts Satoshis to (W)BTC', async function(assert) { + this.set('balanceWBTC', '117214976'); + await render(hbs`{{fmt-crypto-currency balanceWBTC "WBTC"}}`); + assert.equal(this.element.textContent.trim(), '1.17214976'); + }); +}); From 1dd63b2c7a3b0e89cca780c743b139246cade92a Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 13 Aug 2020 15:43:51 +0200 Subject: [PATCH 19/57] Basic styles for budget balances --- app/components/budget-balances/template.hbs | 20 +++++++------- app/styles/app.scss | 1 + app/styles/components/_budget-balances.scss | 30 +++++++++++++++++++++ 3 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 app/styles/components/_budget-balances.scss diff --git a/app/components/budget-balances/template.hbs b/app/components/budget-balances/template.hbs index 617db91..42ffd3a 100644 --- a/app/components/budget-balances/template.hbs +++ b/app/components/budget-balances/template.hbs @@ -1,21 +1,21 @@ - +
              - - - + + + - - - + + + - - - + + +
              TokenAmountFiat valueTokenAmountFiat value
              WBTC{{this.communityFunds.balanceWBTC.balance}}{{this.communityFunds.balanceWBTC.balanceUsd}} USDETH{{fmt-crypto-currency this.communityFunds.balanceETH.balance 'ETH'}}{{this.communityFunds.balanceETH.balanceUsd}} USD
              ETH{{this.communityFunds.balanceETH.balance}}{{this.communityFunds.balanceETH.balanceUsd}} USDWBTC{{fmt-crypto-currency this.communityFunds.balanceWBTC.balance 'WBTC'}}{{this.communityFunds.balanceWBTC.balanceUsd}} USD
              \ No newline at end of file diff --git a/app/styles/app.scss b/app/styles/app.scss index 858471c..14dba8f 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -91,6 +91,7 @@ section { @import "sugar"; @import "item-list"; +@import "components/budget-balances"; @import "components/contribution-details"; @import "components/contribution-list"; @import "components/contributor-list"; diff --git a/app/styles/components/_budget-balances.scss b/app/styles/components/_budget-balances.scss new file mode 100644 index 0000000..7173b02 --- /dev/null +++ b/app/styles/components/_budget-balances.scss @@ -0,0 +1,30 @@ +section#funds { + table.token-balances { + thead { + display: none; + } + + th, td { + font-size: 1.2rem; + vertical-align: text-bottom; + } + + th { + text-align: left; + padding-right: 1.2rem; + } + + td { + text-align: right; + + &.amount { + font-size: 1.6rem; + padding-right: 1.2rem; + } + + &.fiat-amount { + color: rgba(255,255,255,0.8); + } + } + } +} From 5f90bc23bcd64ad799571db32804f6f63d6ac9ca Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 13 Aug 2020 16:13:50 +0200 Subject: [PATCH 20/57] Dynamically load all balances from Safe --- app/components/budget-balances/component.js | 6 +++++ app/components/budget-balances/template.hbs | 19 ++++++-------- app/services/community-funds.js | 28 ++++++++++++++------- app/styles/components/_budget-balances.scss | 7 ++++++ 4 files changed, 40 insertions(+), 20 deletions(-) diff --git a/app/components/budget-balances/component.js b/app/components/budget-balances/component.js index 4c903e1..7ae86bd 100644 --- a/app/components/budget-balances/component.js +++ b/app/components/budget-balances/component.js @@ -1,6 +1,12 @@ import Component from '@glimmer/component'; import { inject as service } from '@ember/service'; +import { alias } from '@ember/object/computed'; export default class BudgetBalancesComponent extends Component { @service communityFunds + @alias('communityFunds.balances') balances; + + get loading () { + return !this.communityFunds.balancesLoaded; + } } diff --git a/app/components/budget-balances/template.hbs b/app/components/budget-balances/template.hbs index 42ffd3a..71ce098 100644 --- a/app/components/budget-balances/template.hbs +++ b/app/components/budget-balances/template.hbs @@ -1,4 +1,4 @@ - +
              @@ -7,15 +7,12 @@ - - - - - - - - - - + {{#each this.balances as |balance|}} + + + + + + {{/each}}
              Token
              ETH{{fmt-crypto-currency this.communityFunds.balanceETH.balance 'ETH'}}{{this.communityFunds.balanceETH.balanceUsd}} USD
              WBTC{{fmt-crypto-currency this.communityFunds.balanceWBTC.balance 'WBTC'}}{{this.communityFunds.balanceWBTC.balanceUsd}} USD
              {{balance.token.symbol}}{{fmt-crypto-currency balance.balance balance.token.symbol}}{{balance.balanceUsd}} USD
              \ No newline at end of file diff --git a/app/services/community-funds.js b/app/services/community-funds.js index 8c6eabd..3f40db1 100644 --- a/app/services/community-funds.js +++ b/app/services/community-funds.js @@ -1,22 +1,22 @@ import Service from '@ember/service'; import { tracked } from '@glimmer/tracking'; +import { A } from '@ember/array'; +import { timeout } from 'ember-concurrency'; import { task } from 'ember-concurrency-decorators'; import config from 'kredits-web/config/environment'; const txServiceBaseUrl = `${config.gnosisSafe.txServiceHost}/api/v1/safes/${config.gnosisSafe.address}`; export default class CommunityFundsService extends Service { - @tracked balanceETH = { balance: 0, balanceUsd: 0, usdConversion: 0 }; - @tracked balanceWBTC = { balance: 0, balanceUsd: 0, usdConversion: 0 }; + @tracked balancesLoaded = false; + @tracked balances = A([]); @task *fetchBalances () { const uri = `${txServiceBaseUrl}/balances/usd/`; yield fetch(uri).then(res => res.json()) - .then(res => { - this.processBalances(res); - }) + .then(res => this.processBalances(res)) .catch(err => { console.log(`[community-funds] Fetching balances failed:`); console.error(err); @@ -24,9 +24,19 @@ export default class CommunityFundsService extends Service { } processBalances (res) { - // TODO proper selection/find - const { balance, balanceUsd, usdConversion } = res[0]; - this.balanceETH = { balance, balanceUsd, usdConversion }; - this.balanceWBTC = res[1]; + for (const balance of res) { + if (balance.token) { + // ERC20 token, has all meta data + this.balances.pushObject(balance); + } else { + // ETH, missing meta data + this.balances.pushObject({ + ...balance, + ...{ token: { name: 'Ether', symbol: 'ETH'} } + }); + } + } + + this.balancesLoaded = true; } } diff --git a/app/styles/components/_budget-balances.scss b/app/styles/components/_budget-balances.scss index 7173b02..05226bd 100644 --- a/app/styles/components/_budget-balances.scss +++ b/app/styles/components/_budget-balances.scss @@ -1,5 +1,12 @@ section#funds { table.token-balances { + opacity: 1; + transition: opacity 0.3s linear; + + &.loading { + opacity: 0; + } + thead { display: none; } From e86541574dbd5af83391b33c3522de3d69196588 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 13 Aug 2020 16:30:39 +0200 Subject: [PATCH 21/57] Format and round the USD value of balances --- app/components/budget-balances/template.hbs | 2 +- app/services/community-funds.js | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/components/budget-balances/template.hbs b/app/components/budget-balances/template.hbs index 71ce098..d8a7de3 100644 --- a/app/components/budget-balances/template.hbs +++ b/app/components/budget-balances/template.hbs @@ -11,7 +11,7 @@ {{balance.token.symbol}} {{fmt-crypto-currency balance.balance balance.token.symbol}} - {{balance.balanceUsd}} USD + ~{{balance.balanceUsd}} USD {{/each}} diff --git a/app/services/community-funds.js b/app/services/community-funds.js index 3f40db1..2d9f0f3 100644 --- a/app/services/community-funds.js +++ b/app/services/community-funds.js @@ -1,7 +1,6 @@ import Service from '@ember/service'; import { tracked } from '@glimmer/tracking'; import { A } from '@ember/array'; -import { timeout } from 'ember-concurrency'; import { task } from 'ember-concurrency-decorators'; import config from 'kredits-web/config/environment'; @@ -25,6 +24,10 @@ export default class CommunityFundsService extends Service { processBalances (res) { for (const balance of res) { + // Format and round the approximate USD value + const lang = navigator.language || navigator.userLanguage; + balance.balanceUsd = Math.round(balance.balanceUsd).toLocaleString(lang); + if (balance.token) { // ERC20 token, has all meta data this.balances.pushObject(balance); From 9f35add07f767266cc8b8644a71bac039fa48e99 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Thu, 10 Sep 2020 16:28:01 +0200 Subject: [PATCH 22/57] WIP Reimbursement UI --- app/components/add-reimbursement/component.js | 25 ++++++- app/components/add-reimbursement/template.hbs | 71 +++++++++++++++++++ app/styles/_forms.scss | 2 + 3 files changed, 97 insertions(+), 1 deletion(-) diff --git a/app/components/add-reimbursement/component.js b/app/components/add-reimbursement/component.js index 79805cf..d151ba7 100644 --- a/app/components/add-reimbursement/component.js +++ b/app/components/add-reimbursement/component.js @@ -1,8 +1,31 @@ - import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { alias } from '@ember/object/computed'; import { inject as service } from '@ember/service'; +import { action } from '@ember/object'; +import { A } from '@ember/array'; export default class AddReimbursementComponent extends Component { @service kredits; + @tracked recipientId = null; + @tracked title = ""; + @tracked total = "0"; + @tracked expenses = A([]);; + + get typeofTotal() { + return typeof this.total; + } + + @alias('kredits.contributorsSorted') contributors; + + @action + submit(e) { + e.preventDefault(); + console.log('submit', e); + // TODO + // amount = parseFloat(this.total) + // token = "WBTC" (or token address) + // title = "Expenses covered by contributor.name" + } } diff --git a/app/components/add-reimbursement/template.hbs b/app/components/add-reimbursement/template.hbs index e69de29..0c64b88 100644 --- a/app/components/add-reimbursement/template.hbs +++ b/app/components/add-reimbursement/template.hbs @@ -0,0 +1,71 @@ +

              + Total: {{this.total}}
              + Total type: {{this.typeofTotal}} +

              + +
              + + + +

              Expense items

              + {{#each this.expenses as |expense|}} + + + + + +
              {{expense.title}} – {{expense.description}}{{fmt-fiat-currency expense.amount expense.currency}}
              +

              TODO: date, url, tags

              + {{/each}} + + + + + +

              + {{input type="submit" value="Submit"}} +

              +
              diff --git a/app/styles/_forms.scss b/app/styles/_forms.scss index 5153b02..ec11982 100644 --- a/app/styles/_forms.scss +++ b/app/styles/_forms.scss @@ -1,5 +1,7 @@ section#add-contributor, section#add-contribution, +section#add-contribution, +section#add-item, // TODO use for all forms for adding data section#signup { form { From 47220643370031bc30ca017b69bea7dfc6e6601c Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Mon, 28 Sep 2020 11:04:37 +0200 Subject: [PATCH 23/57] WIP expense items --- app/components/add-reimbursement/component.js | 22 +++- app/components/add-reimbursement/template.hbs | 107 +++++++++++------- app/models/expense.js | 43 +++++++ app/models/reimbursement.js | 1 - app/styles/_forms.scss | 25 +++- 5 files changed, 152 insertions(+), 46 deletions(-) create mode 100644 app/models/expense.js diff --git a/app/components/add-reimbursement/component.js b/app/components/add-reimbursement/component.js index d151ba7..17d9c38 100644 --- a/app/components/add-reimbursement/component.js +++ b/app/components/add-reimbursement/component.js @@ -4,19 +4,37 @@ import { alias } from '@ember/object/computed'; import { inject as service } from '@ember/service'; import { action } from '@ember/object'; import { A } from '@ember/array'; +import Reimbursement from 'kredits-web/models/reimbursement'; +import Expense from 'kredits-web/models/expense'; export default class AddReimbursementComponent extends Component { @service kredits; @tracked recipientId = null; - @tracked title = ""; - @tracked total = "0"; + @tracked title = ''; + @tracked total = '0'; @tracked expenses = A([]);; + @tracked newExpense = Expense.create(); + + // TODO fetch/apply exchange rate to (W)BTC + currencies = [ + { code: 'EUR' }, + { code: 'USD' }, + { code: 'GBP' } + ]; get typeofTotal() { return typeof this.total; } + get submitButtonEnabled() { + return this.expenses.length > 0; + } + + get submitButtonDisabled() { + return !this.submitButtonEnabled; + } + @alias('kredits.contributorsSorted') contributors; @action diff --git a/app/components/add-reimbursement/template.hbs b/app/components/add-reimbursement/template.hbs index 0c64b88..3dbb710 100644 --- a/app/components/add-reimbursement/template.hbs +++ b/app/components/add-reimbursement/template.hbs @@ -1,8 +1,3 @@ -

              - Total: {{this.total}}
              - Total type: {{this.typeofTotal}} -

              -
              -

              - Expense items -

              - {{#each this.expenses as |expense|}} - - - - - -
              {{expense.title}} – {{expense.description}}{{fmt-fiat-currency expense.amount expense.currency}}
              -

              TODO: date, url, tags

              +

              Expense items

              + {{#if this.expenses}} +
                + {{#each this.expenses as |expense|}} +
              • +
                +

                + {{expense.date}}: + {{expense.title}} +

                +

                {{expense.description}}

                +
                +
                + {{fmt-fiat-currency expense.amount expense.currency}} +
                +
                + +
                +
              • + {{/each}} +
              +

              + +

              {{else}}

              No line items yet.

              - {{/each}} + {{/if}}

              {{input type="submit" value="Submit" disabled=this.submitButtonDisabled title="Submit/propose this reimbursement"}}

              -

              - New expense item -

              -
              -
              - - -
              - - - - - -

              - {{input type="submit" value="Add" disabled=this.addButtonDisabled - class="green" title="Add item to reimbursement"}} -

              -
              + {{#if this.expenseFormVisible}} +

              New expense item

              + + {{/if}} diff --git a/app/components/reimbursement-list/template.hbs b/app/components/reimbursement-list/template.hbs index 0bdd008..82d3404 100644 --- a/app/components/reimbursement-list/template.hbs +++ b/app/components/reimbursement-list/template.hbs @@ -11,14 +11,22 @@ {{sats-to-btc reimbursement.amount}} WBTC

              - +
                {{#each reimbursement.expenses as |expense|}} -
              - - - +
            • +
              +

              + {{expense.date}}: + {{expense.title}} +

              +

              {{expense.description}}

              +
              +
              + {{fmt-fiat-currency expense.amount expense.currency}} +
              +
            • {{/each}} -
              {{expense.title}} – {{expense.description}}{{fmt-fiat-currency expense.amount expense.currency}}
              +
            {{/each}}
          \ No newline at end of file diff --git a/app/models/expense.js b/app/models/expense.js deleted file mode 100644 index cd050af..0000000 --- a/app/models/expense.js +++ /dev/null @@ -1,43 +0,0 @@ -import EmberObject, { computed } from '@ember/object'; -import moment from 'moment'; -import { A } from '@ember/array'; - -export default EmberObject.extend({ - title: null, - description: null, - currency: null, - amount: null, - date: null, - url: null, - tags: null, - - init () { - this._super(...arguments); - this.setDefaultValues(); - }, - - iso8601Date: computed('date', 'time', function() { - return this.time ? `${this.date}T${this.time}` : this.date; - }), - - jsDate: computed('iso8601Date', function() { - return moment(this.iso8601Date).toDate(); - }), - - setDefaultValues () { - this.set('defaultDate', moment().startOf('hour').toDate()); - this.setProperties({ - title: '', - description: '', - currency: 'EUR', - amount: 0, - date: this.defaultDate, - url: null, - tags: A([]) - }); - }, - - serialize () { - return JSON.stringify(this); - } -}); diff --git a/app/styles/_forms.scss b/app/styles/_forms.scss index 443ab72..58e9ec0 100644 --- a/app/styles/_forms.scss +++ b/app/styles/_forms.scss @@ -13,18 +13,19 @@ section#signup { p { font-size: 1.2rem; - margin-bottom: 1.5rem; &.mg-bottom-md { margin-bottom: 2rem; } &.label { + margin-bottom: 1.5rem; font-size: 1rem; margin-bottom: .5rem; } &.actions { + margin-bottom: 1.5rem; padding-top: 1.5rem; text-align: center; a { @@ -38,6 +39,10 @@ section#signup { display: block; margin-bottom: 0.5rem; opacity: 0.7; + + > p { + margin-bottom: 1.5rem; + } } fieldset { diff --git a/app/styles/_item-list.scss b/app/styles/_item-list.scss index bdef14c..548bf3c 100644 --- a/app/styles/_item-list.scss +++ b/app/styles/_item-list.scss @@ -1,7 +1,7 @@ ul.item-list { list-style: none; - li { + > li { padding: 0.8rem 1.2rem; font-size: 1.2rem; background-color: $item-background-color; @@ -19,7 +19,7 @@ ul.item-list { &.loading { @include loading-border-top; - li { + > li { &:first-of-type { border-top: none; } @@ -27,7 +27,7 @@ ul.item-list { } &.spaced { - li { + > li { border-top: 1px solid $item-border-color; margin-bottom: 2rem; } diff --git a/app/styles/app.scss b/app/styles/app.scss index 14dba8f..ba4617f 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -96,6 +96,7 @@ section { @import "components/contribution-list"; @import "components/contributor-list"; @import "components/contributor-profile"; +@import "components/expense-list"; @import "components/external-account-link"; @import "components/loading-spinner"; @import "components/reimbursement-list"; diff --git a/app/styles/components/_budget-balances.scss b/app/styles/components/_budget-balances.scss index 05226bd..83d2d91 100644 --- a/app/styles/components/_budget-balances.scss +++ b/app/styles/components/_budget-balances.scss @@ -25,7 +25,7 @@ section#funds { text-align: right; &.amount { - font-size: 1.6rem; + font-size: 1.5rem; padding-right: 1.2rem; } diff --git a/app/styles/components/_expense-list.scss b/app/styles/components/_expense-list.scss new file mode 100644 index 0000000..b369f5f --- /dev/null +++ b/app/styles/components/_expense-list.scss @@ -0,0 +1,48 @@ +ul.expense-list { + grid-column-start: span 2; + width: 100%; + margin-top: 0.8rem; + border-collapse: collapse; + + li { + display: grid; + grid-template-columns: auto 10rem; + grid-row-gap: 0.5rem; + padding-top: 1.2rem; + border-top: 1px solid $item-border-color; + font-size: 1.2rem; + + &:not(:last-child) { + padding-bottom: 1.2rem; + } + } + + .description { + grid-row-start: 1; + grid-row-end: 3; + } + + .amount { + justify-self: end; + // font-weight: normal; + } + + .actions { + justify-self: end; + } + + h4 { + font-size: 1.2rem; + font-weight: normal; + line-height: 2rem; + } + + p { + line-height: 2rem; + + &.description { + font-size: 1rem; + opacity: 0.7; + } + } +} diff --git a/app/styles/components/_reimbursement-list.scss b/app/styles/components/_reimbursement-list.scss index c5f6458..2423ffd 100644 --- a/app/styles/components/_reimbursement-list.scss +++ b/app/styles/components/_reimbursement-list.scss @@ -1,7 +1,7 @@ ul.reimbursement-list { width: 100%; - li { + > li { display: grid; grid-template-columns: auto 10rem; grid-row-gap: 0.5rem; @@ -17,36 +17,13 @@ ul.reimbursement-list { } .amount { - font-weight: 500; + font-size: 1.5rem; } .symbol { - font-size: 0.8rem; + font-size: 1rem; padding-left: 0.2rem; } } - - table { - grid-column-start: span 2; - width: 100%; - margin-top: 0.8rem; - border-collapse: collapse; - - tr { - border-top: 1px solid $item-border-color; - } - - td { - padding: 0.8rem 0; - - &.amount { - text-align: right; - } - } - - @include media-max(small) { - td.date { display: none; } - } - } } } diff --git a/tests/integration/components/add-expense-item/component-test.js b/tests/integration/components/add-expense-item/component-test.js new file mode 100644 index 0000000..5508b95 --- /dev/null +++ b/tests/integration/components/add-expense-item/component-test.js @@ -0,0 +1,26 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | add-expense-item', function(hooks) { + setupRenderingTest(hooks); + + test('it renders', async function(assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.set('myAction', function(val) { ... }); + + await render(hbs``); + + assert.equal(this.element.textContent.trim(), ''); + + // Template block usage: + await render(hbs` + + template block text + + `); + + assert.equal(this.element.textContent.trim(), 'template block text'); + }); +}); From 7c86edcaaa237e3ee00cad9e0db8bcbfbb4cc17d Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Tue, 29 Sep 2020 17:36:50 +0200 Subject: [PATCH 25/57] Remove expense item from list --- app/components/add-reimbursement/component.js | 9 +++++++++ app/components/add-reimbursement/template.hbs | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/components/add-reimbursement/component.js b/app/components/add-reimbursement/component.js index 8dc305d..d9c76d1 100644 --- a/app/components/add-reimbursement/component.js +++ b/app/components/add-reimbursement/component.js @@ -36,6 +36,15 @@ export default class AddReimbursementComponent extends Component { this.expenseFormVisible = false; } + @action + removeExpenseItem (expenseItem) { + this.expenses.removeObject(expenseItem); + + if (this.expenses.length === 0) { + this.expenseFormVisible = true; + } + } + @action submit (e) { e.preventDefault(); diff --git a/app/components/add-reimbursement/template.hbs b/app/components/add-reimbursement/template.hbs index e42b008..9af5164 100644 --- a/app/components/add-reimbursement/template.hbs +++ b/app/components/add-reimbursement/template.hbs @@ -33,7 +33,7 @@ {{fmt-fiat-currency expense.amount expense.currency}}
          - +
          {{/each}} From 37dc91da57127567e4f98323c4012b8a4412709c Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Tue, 29 Sep 2020 17:39:45 +0200 Subject: [PATCH 26/57] Clearly highlight focused buttons --- app/styles/_buttons.scss | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/styles/_buttons.scss b/app/styles/_buttons.scss index 6ab5574..eb0c2ff 100644 --- a/app/styles/_buttons.scss +++ b/app/styles/_buttons.scss @@ -20,7 +20,7 @@ button, input[type=submit], .button { background-color: rgba(22, 21, 40, 0.8); } - &:active, &.active { + &:focus, &:active, &.active { border-color: $primary-color; } @@ -41,7 +41,7 @@ button, input[type=submit], .button { &:hover { background-color: rgba(40, 21, 21, 0.8); } - &:active, &.active { + &:focus, &:active, &.active { border-color: $red; } } @@ -54,7 +54,7 @@ button, input[type=submit], .button { &:hover { background-color: rgba(21, 40, 21, 0.8); } - &:active, &.active { + &:focus, &:active, &.active { border-color: $green; } } From 083c8736310cad532994f74958486f3d46f2672d Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Tue, 29 Sep 2020 17:57:57 +0200 Subject: [PATCH 27/57] Scroll to current item; remove some obsolete code --- app/components/add-expense-item/component.js | 5 ----- app/components/add-reimbursement/component.js | 8 +++++++- app/components/add-reimbursement/template.hbs | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/components/add-expense-item/component.js b/app/components/add-expense-item/component.js index 6ac06d4..30d4824 100644 --- a/app/components/add-expense-item/component.js +++ b/app/components/add-expense-item/component.js @@ -4,7 +4,6 @@ import { action } from '@ember/object'; import moment from 'moment'; export default class AddExpenseItemComponent extends Component { - // @tracked newExpense = Expense.create(); @tracked amount = '0'; @tracked currency = 'EUR'; @@ -31,9 +30,6 @@ export default class AddExpenseItemComponent extends Component { return !this.submitButtonEnabled; } - setDefaultValues () { - } - @action submit (e) { e.preventDefault(); @@ -54,6 +50,5 @@ export default class AddExpenseItemComponent extends Component { } this.args.addExpenseItem(expense); - this.resetProperties(); } } diff --git a/app/components/add-reimbursement/component.js b/app/components/add-reimbursement/component.js index d9c76d1..a30e87f 100644 --- a/app/components/add-reimbursement/component.js +++ b/app/components/add-reimbursement/component.js @@ -4,6 +4,7 @@ import { alias } from '@ember/object/computed'; import { inject as service } from '@ember/service'; import { action } from '@ember/object'; import { A } from '@ember/array'; +import { scheduleOnce } from '@ember/runloop'; import Reimbursement from 'kredits-web/models/reimbursement'; export default class AddReimbursementComponent extends Component { @@ -25,9 +26,15 @@ export default class AddReimbursementComponent extends Component { return !this.submitButtonEnabled; } + scrollToExpenseItemForm () { + const anchor = document.getElementById('new-expense-item'); + anchor.scrollIntoView(); + } + @action showExpenseForm () { this.expenseFormVisible = true; + scheduleOnce('afterRender', this, this.scrollToExpenseItemForm); } @action @@ -48,7 +55,6 @@ export default class AddReimbursementComponent extends Component { @action submit (e) { e.preventDefault(); - console.log('submit', e); // TODO // amount = parseFloat(this.total) // token = "WBTC" (or token address) diff --git a/app/components/add-reimbursement/template.hbs b/app/components/add-reimbursement/template.hbs index 9af5164..7523299 100644 --- a/app/components/add-reimbursement/template.hbs +++ b/app/components/add-reimbursement/template.hbs @@ -51,7 +51,7 @@

          {{#if this.expenseFormVisible}} -

          New expense item

          +

          New expense item

          {{/if}} From 326d46b1a115f668812ac5698324212fd88c457d Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Tue, 29 Sep 2020 18:09:48 +0200 Subject: [PATCH 28/57] Validate total amount --- app/components/add-reimbursement/component.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/components/add-reimbursement/component.js b/app/components/add-reimbursement/component.js index a30e87f..5920133 100644 --- a/app/components/add-reimbursement/component.js +++ b/app/components/add-reimbursement/component.js @@ -18,8 +18,18 @@ export default class AddReimbursementComponent extends Component { @tracked expenses = A([]); @tracked expenseFormVisible = true; + get isValidTotal () { + const amount = parseFloat(this.total); + if (Number.isNaN(amount)) { + return false; + } else { + return amount > 0; + } + } + get submitButtonEnabled () { - return this.expenses.length > 0; + return this.isValidTotal && + (this.expenses.length > 0); } get submitButtonDisabled () { From 444ec62a66029a7e213607ee2c8ccf8fd7329b48 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Tue, 29 Sep 2020 18:37:55 +0200 Subject: [PATCH 29/57] Validate expense/reimbursement forms Adds some general helpers and styles for minimalistic form validation. --- app/components/add-expense-item/component.js | 56 +++++++++++++++---- app/components/add-expense-item/template.hbs | 18 ++++-- app/components/add-reimbursement/component.js | 12 ++-- app/components/add-reimbursement/template.hbs | 9 ++- app/styles/_forms.scss | 7 ++- app/utils/is-valid-amount.js | 8 +++ .../add-expense-item/component-test.js | 19 ++----- .../add-reimbursement/component-test.js | 8 +-- tests/unit/utils/is-valid-amount-test.js | 22 ++++++++ 9 files changed, 114 insertions(+), 45 deletions(-) create mode 100644 app/utils/is-valid-amount.js create mode 100644 tests/unit/utils/is-valid-amount-test.js diff --git a/app/components/add-expense-item/component.js b/app/components/add-expense-item/component.js index 30d4824..eb1f3e1 100644 --- a/app/components/add-expense-item/component.js +++ b/app/components/add-expense-item/component.js @@ -2,6 +2,7 @@ import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking'; import { action } from '@ember/object'; import moment from 'moment'; +import isValidAmount from 'kredits-web/utils/is-valid-amount'; export default class AddExpenseItemComponent extends Component { // @tracked newExpense = Expense.create(); @@ -22,6 +23,14 @@ export default class AddExpenseItemComponent extends Component { { code: 'GBP' } ]; + get isValidAmount () { + return isValidAmount(this.amount); + } + + get amountInputClass () { + return this.isValidTotal ? 'valid' : ''; + } + get submitButtonEnabled () { return true; } @@ -30,6 +39,27 @@ export default class AddExpenseItemComponent extends Component { return !this.submitButtonEnabled; } + validateForm () { + const formEl = document.querySelector('form#add-expense-item'); + let validity = true; + + if (!this.isValidAmount) { + document.querySelector('input[name=expense-amount]').classList.add('invalid'); + validity = false; + } + + if (!formEl.checkValidity()) { + document.querySelectorAll('form#add-expense-item input').forEach(i => { + if (!i.validity.valid) { + i.classList.add('invalid'); + validity = false; + } + }) + } + + return validity; + } + @action submit (e) { e.preventDefault(); @@ -38,17 +68,21 @@ export default class AddExpenseItemComponent extends Component { this.date[0] : this.date; const [ date ] = dateInput.toISOString().split('T'); - // TODO validate form - const expense = { - amount: parseFloat(this.amount), - currency: this.currency, - date: date, - title: this.title, - description: this.description, - url: this.url, - tags: this.tags.split(',').map(t => t.trim()) - } + const isValid = this.validateForm(); - this.args.addExpenseItem(expense); + if (isValid) { + const expense = { + amount: parseFloat(this.amount), + currency: this.currency, + date: date, + title: this.title, + description: this.description, + url: this.url, + tags: this.tags.split(',').map(t => t.trim()) + } + this.args.addExpenseItem(expense); + } else { + return false; + } } } diff --git a/app/components/add-expense-item/template.hbs b/app/components/add-expense-item/template.hbs index ddc176c..91f25bd 100644 --- a/app/components/add-expense-item/template.hbs +++ b/app/components/add-expense-item/template.hbs @@ -1,10 +1,15 @@ -
          +

        - +

        {{else}}

        No line items yet.

        @@ -72,11 +74,11 @@

        {{#if this.inProgress}} - {{input type="submit" value="Submitting..." disabled=true - title="Submit/propose this reimbursement"}} + {{else}} - {{input type="submit" value="Submit" disabled=this.submitButtonDisabled - title="Submit/propose this reimbursement"}} + {{/if}}

        From 087cb706d23e51073b39ab56d40f55e8bd6bd8ff Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Sat, 31 Oct 2020 13:30:44 +0100 Subject: [PATCH 54/57] Fix JS linting errors --- app/models/reimbursement.js | 1 - .../add-expense-item/component-test.js | 30 +++++++++---------- .../budget-balances/component-test.js | 26 ++++++++-------- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/app/models/reimbursement.js b/app/models/reimbursement.js index 0e4c6dd..ef56068 100644 --- a/app/models/reimbursement.js +++ b/app/models/reimbursement.js @@ -1,6 +1,5 @@ import EmberObject, { computed } from '@ember/object'; import moment from 'moment'; -import { notEmpty } from '@ember/object/computed'; import { isPresent } from '@ember/utils'; export default EmberObject.extend({ diff --git a/tests/integration/components/add-expense-item/component-test.js b/tests/integration/components/add-expense-item/component-test.js index cb190b3..7a5df8d 100644 --- a/tests/integration/components/add-expense-item/component-test.js +++ b/tests/integration/components/add-expense-item/component-test.js @@ -1,15 +1,15 @@ -import { module, test } from 'qunit'; -import { setupRenderingTest } from 'ember-qunit'; -import { render } from '@ember/test-helpers'; -import { hbs } from 'ember-cli-htmlbars'; - -module('Integration | Component | add-expense-item', function(hooks) { - setupRenderingTest(hooks); - - // test('it renders', async function(assert) { - // Set any properties with this.set('myProperty', 'value'); - // Handle any actions with this.set('myAction', function(val) { ... }); - // await render(hbs``); - // assert.equal(this.element.textContent.trim(), ''); - // }); -}); +// import { module, test } from 'qunit'; +// import { setupRenderingTest } from 'ember-qunit'; +// import { render } from '@ember/test-helpers'; +// import { hbs } from 'ember-cli-htmlbars'; +// +// module('Integration | Component | add-expense-item', function(hooks) { +// setupRenderingTest(hooks); +// +// test('it renders', async function(assert) { +// Set any properties with this.set('myProperty', 'value'); +// Handle any actions with this.set('myAction', function(val) { ... }); +// await render(hbs``); +// assert.equal(this.element.textContent.trim(), ''); +// }); +// }); diff --git a/tests/integration/components/budget-balances/component-test.js b/tests/integration/components/budget-balances/component-test.js index c786b6e..6e6345b 100644 --- a/tests/integration/components/budget-balances/component-test.js +++ b/tests/integration/components/budget-balances/component-test.js @@ -1,13 +1,13 @@ -import { module, test } from 'qunit'; -import { setupRenderingTest } from 'ember-qunit'; -import { render } from '@ember/test-helpers'; -import { hbs } from 'ember-cli-htmlbars'; - -module('Integration | Component | budget-balances', function(hooks) { - setupRenderingTest(hooks); - - // test('it renders', async function(assert) { - // await render(hbs``); - // assert.equal(this.element.textContent.trim(), ''); - // }); -}); +// import { module, test } from 'qunit'; +// import { setupRenderingTest } from 'ember-qunit'; +// import { render } from '@ember/test-helpers'; +// import { hbs } from 'ember-cli-htmlbars'; +// +// module('Integration | Component | budget-balances', function(hooks) { +// setupRenderingTest(hooks); +// +// test('it renders', async function(assert) { +// await render(hbs``); +// assert.equal(this.element.textContent.trim(), ''); +// }); +// }); From 2a8fd3b001ede25b2538db1d8e4652036d2414f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Tue, 17 Nov 2020 12:47:43 +0100 Subject: [PATCH 55/57] Update app/components/topbar-account-panel/component.js Co-authored-by: Garret Alfert --- app/components/topbar-account-panel/component.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/components/topbar-account-panel/component.js b/app/components/topbar-account-panel/component.js index b4ad5dd..ed1bcfb 100644 --- a/app/components/topbar-account-panel/component.js +++ b/app/components/topbar-account-panel/component.js @@ -34,7 +34,6 @@ export default Component.extend({ 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); From f3f158ff262df47f7dc015dd3850bbbaf030764f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Tue, 17 Nov 2020 13:38:47 +0100 Subject: [PATCH 56/57] Update app/services/kredits.js Co-authored-by: Garret Alfert --- app/services/kredits.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/services/kredits.js b/app/services/kredits.js index 27faa93..2721da0 100644 --- a/app/services/kredits.js +++ b/app/services/kredits.js @@ -482,7 +482,6 @@ export default Service.extend({ await this.browserCache[collection].setItem(o.id, o.serialize()); } console.debug(`[kredits] Cached ${this[collection].length} ${collection} in browser storage`); - return Promise.resolve(); }, async loadObjectsFromCache (objectClass) { From aed29ff9826442ff35604ae9bfd0c3f24f6bb361 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Tue, 17 Nov 2020 13:40:44 +0100 Subject: [PATCH 57/57] Remove obsolete property from class and template Co-authored-by: Garret Alfert --- app/components/add-expense-item/component.js | 8 -------- app/components/add-expense-item/template.hbs | 4 ++-- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/app/components/add-expense-item/component.js b/app/components/add-expense-item/component.js index 225ac18..66512fa 100644 --- a/app/components/add-expense-item/component.js +++ b/app/components/add-expense-item/component.js @@ -29,14 +29,6 @@ export default class AddExpenseItemComponent extends Component { return this.isValidTotal ? 'valid' : ''; } - get submitButtonEnabled () { - return true; - } - - get submitButtonDisabled () { - return !this.submitButtonEnabled; - } - validateForm () { const formEl = document.querySelector('form#add-expense-item'); const inputFields = formEl.querySelectorAll('input'); diff --git a/app/components/add-expense-item/template.hbs b/app/components/add-expense-item/template.hbs index ef95da7..cb2bb13 100644 --- a/app/components/add-expense-item/template.hbs +++ b/app/components/add-expense-item/template.hbs @@ -63,7 +63,7 @@

        - +

        \ No newline at end of file