Compare commits

...

21 Commits

Author SHA1 Message Date
Râu Cao 8cc3da40b7 2.0.0 2023-08-14 18:28:02 +02:00
Râu Cao bdeab512b6 Upgrade kredits-contracts 2023-08-14 17:57:04 +02:00
Râu Cao 97ebebe28c Merge pull request #214 from 67P/chore/remove_last_ethereum_bits
Remove mentions of Ethereum from UI and code, refactor wallet connect
2023-08-14 17:53:44 +02:00
Râu Cao d5edb93ec5 Use new hubot URL 2023-08-14 17:50:47 +02:00
Râu Cao 0ecc4079c2 Ember code updates 2023-08-14 17:50:10 +02:00
Râu Cao 3f080cf553 Open external link in new tab
closes #170
2023-02-02 12:32:50 +08:00
Râu Cao 0bdb4d2021 Connect wallet and fill in address during signup
In case there's a wallet available, ask the user to connect it and fill
in their account address in the form field.

Also, check the status code when submitting it to the back-end and show
an error message instead of the success/completion page in case the
contributor could not be created.
2023-01-21 12:39:14 +08:00
Râu Cao 1e7d8491f9 Refactor wallet connect, automatically propose network 2023-01-20 17:29:20 +08:00
Râu Cao 4356288497 Rename signup route, address property 2023-01-20 17:29:20 +08:00
Râu Cao 87bf8ff2df Inspect user txs on RSK explorer 2023-01-20 17:29:20 +08:00
Râu Cao 26975636a0 Update README 2023-01-20 17:29:17 +08:00
Râu Cao dad56a7b31 Merge pull request #212 from 67P/bugfix/load_contributor
Fix dashboard hanging when loading app from contributor URL
2023-01-20 17:29:05 +08:00
Râu Cao d069fa02ab Add links 2023-01-15 14:41:25 +08:00
Râu Cao d219abc358 RSK -> Rootstock 2023-01-15 14:39:54 +08:00
Râu Cao 13989bf973 Update README
refs #18
2023-01-15 14:38:43 +08:00
Râu Cao b3ab69d599 Update CI badge in README 2023-01-15 14:28:19 +08:00
Râu Cao fe3816501c Fix dashboard hanging when loading app from contributor URL
Loading the app from /dashboard/contributors/:id is failing, because the
contributors are loaded later. This fetches the requested contributor
separately when launching the app from a contributor profile URL.
2023-01-15 14:24:51 +08:00
Râu Cao 854402aa73 Merge pull request #213 from 67P/feature/github_actions_ci
Switch from Travis CI to GitHub Actions
2023-01-15 14:24:14 +08:00
Râu Cao abc19c715b Fix double builds in CI 2023-01-15 14:20:48 +08:00
Râu Cao b6434ac8d2 Remove Travis config 2023-01-15 14:17:30 +08:00
Râu Cao 4788b8c51c Add GitHub Actions CI config 2023-01-15 14:17:09 +08:00
32 changed files with 710 additions and 468 deletions
+30
View File
@@ -0,0 +1,30 @@
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
name: CI
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm install
- run: npm test
-21
View File
@@ -1,21 +0,0 @@
---
language: node_js
node_js:
- "14"
- "16"
sudo: false
dist: precise
notifications:
email: false
addons:
chrome: stable
cache:
npm: false
branches:
only:
- master
+12 -6
View File
@@ -1,9 +1,15 @@
[![Build Status](https://travis-ci.org/67P/kredits-web.svg?branch=master)](https://travis-ci.org/67P/kredits-web)
[![Build Status](https://github.com/67P/kredits-web/actions/workflows/ci.yml/badge.svg)](https://github.com/67P/kredits-web/actions/workflows/ci.yml?query=branch%3Amaster)
# kredits-web
# Kredits Web
This README outlines the details of collaborating on this Ember application.
A short introduction of this app could easily go here.
This is the main Web UI for Kosmos [Kredits](https://wiki.kosmos.org/Kredits).
It provides an overview of contributors and contributions, as well as the
community's budget, expenses, and reimbursements.
It is an unhosted Web app, fetching all data from
[Rootstock](https://rootstock.io/) and [IPFS](https://ipfs.tech/), and caching
it in the browser's local database. As such, you can run the app directly from
the `/release` directory on any Web server that can serve static assets.
## Development
@@ -24,7 +30,7 @@ You will need the following things properly installed on your computer.
### Building/running for development
* `ember serve` - by default kredits-web connects to the Ethreum Kovan network
* `npm start` - by default Kredits Web connects to the Rootstock testnet network
* Visit your app at [http://localhost:4200](http://localhost:4200).
* Visit your tests at [http://localhost:4200/tests](http://localhost:4200/tests).
@@ -48,7 +54,7 @@ Make use of the many generators for code, try `ember help generate` for more det
### Building
* `ember build` (development)
* `ember build --environment production` (production)
* `npm run build` (production)
### Deploying
+1 -1
View File
@@ -1,6 +1,6 @@
<form onsubmit={{action "submit"}}>
<p>
<label for="c-account">Ethereum account</label>
<label for="c-account">Rootstock account</label>
<Input @type="text"
@value={{this.account}}
name="account" id="c-account"
@@ -1,45 +1,37 @@
import Component from '@ember/component';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
import { computed } from '@ember/object';
import { action } from '@ember/object';
import { isPresent } from '@ember/utils';
export default Component.extend({
export default class TopbarAccountPanelComponent extends Component {
@service router;
@service kredits;
tagName: '',
@tracked setupInProgress = false;
kredits: service(),
router: service(),
setupInProgress: false,
userHasEthereumWallet: computed(function() {
get userHasWallet () {
return isPresent(window.ethereum);
}),
showConnectButton: computed('userHasEthereumWallet',
'kredits.hasAccounts', function() {
return this.userHasEthereumWallet &&
!this.kredits.hasAccounts;
}),
actions: {
signup() {
this.router.transitionTo('signup');
},
async connectAccount() {
try {
await window.ethereum.enable();
this.set('setupInProgress', true);
await this.kredits.setup();
this.set('setupInProgress', false);
} catch (error) {
this.set('setupInProgress', false);
console.log('Opening Ethereum wallet failed:', error);
}
}
}
});
get walletConnected () {
return this.userHasWallet && this.kredits.hasAccounts;
}
get walletDisconnected () {
return this.userHasWallet && !this.kredits.hasAccounts;
}
@action
signup () {
this.router.transitionTo('signup');
}
@action
async connectWallet () {
this.setupInProgress = true;
await this.kredits.connectWallet();
this.setupInProgress = false;
}
}
@@ -2,16 +2,15 @@
{{#if this.setupInProgress}}
Connecting account...
{{else}}
{{#if (and this.kredits.hasAccounts this.kredits.currentUser)}}
{{#if (and this.walletConnected this.kredits.currentUser)}}
{{this.kredits.currentUser.name}}
{{#if this.kredits.currentUserIsCore}}
<span class="core-flag">(core)</span>
{{/if}}
{{else}}
<span class="anonymous">Anonymous</span>
<button onclick={{action "signup"}} class="small" type="button">Sign up</button>
{{#if this.showConnectButton}}
<button onclick={{action "connectAccount"}} class="small green" type="button">Connect account</button>
<button onclick={{action "signup"}} id="signup"
class="small" type="button">Sign up</button>
{{#if this.walletDisconnected}}
<button onclick={{action "connectWallet"}} id="connect"
class="small green" type="button">Connect wallet</button>
{{/if}}
{{/if}}
{{/if}}
+50
View File
@@ -0,0 +1,50 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import config from 'kredits-web/config/environment';
import { isAddress } from 'web3-utils';
export default class AccountController extends Controller {
@service kredits;
@tracked accountAddress = null;
get isValidEthAccount () {
return isAddress(this.accountAddress);
}
get signupButtonDisabled () {
return !this.isValidEthAccount;
}
@action
completeSignup () {
const payload = {
accessToken: this.kredits.githubAccessToken,
account: this.accountAddress
}
fetch(config.githubSignupUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
})
.then(res => res.json())
.then(data => {
if (data.error) {
alert('Creating profile failed. We have been notified about this error and will take a look soon. Sorry!');
console.warn('Creating contributor profile failed:',
JSON.parse(data.error.body).error.message)
return false;
} else {
console.log('[signup/account] Created contributor:', data);
this.kredits.githubAccessToken = null;
this.accountAddress = null;
this.transitionToRoute('signup.complete');
}
})
}
}
-49
View File
@@ -1,49 +0,0 @@
import Controller from '@ember/controller';
import { computed } from '@ember/object';
import { alias, not } from '@ember/object/computed';
import { isAddress } from 'web3-utils';
import { inject as service } from '@ember/service';
import config from 'kredits-web/config/environment';
export default Controller.extend({
kredits: service(),
ethAddress: null,
githubAccessToken: alias('kredits.githubAccessToken'),
isValidEthAccount: computed('ethAddress', function() {
return isAddress(this.ethAddress);
}),
signupButtonDisabled: not('isValidEthAccount'),
actions: {
completeSignup () {
const payload = {
accessToken: this.githubAccessToken,
account: this.ethAddress
}
fetch(config.githubSignupUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
})
.then(res => res.json())
.then(data => {
console.log('Created contributor:', data);
this.setProperties({
githubAccessToken: null,
ethAddress: null
});
this.transitionToRoute('signup.complete');
});
}
}
});
+6 -8
View File
@@ -1,14 +1,12 @@
import Controller from '@ember/controller';
import { action } from '@ember/object';
import config from 'kredits-web/config/environment';
export default Controller.extend({
actions: {
connectGithub () {
window.location = config.githubConnectUrl;
}
export default class IndexController extends Controller {
@action
connectGithub () {
window.location = config.githubConnectUrl;
}
});
}
+1 -1
View File
@@ -26,7 +26,7 @@ Router.map(function() {
});
this.route('signup', function() {
this.route('github');
this.route('eth-account');
this.route('account');
this.route('complete');
});
this.route('budget', function() {
+7 -1
View File
@@ -8,7 +8,13 @@ export default Route.extend({
contributors: alias('kredits.contributors'),
model (params) {
return this.contributors.findBy('id', params.id);
const contributor = this.contributors.findBy('id', params.id);
if (contributor) {
return contributor;
} else {
return this.kredits.fetchContributor(params.id);
}
},
setupController (controller, model) {
+23
View File
@@ -0,0 +1,23 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
import { isEmpty } from '@ember/utils';
export default class SignupAccountRoute extends Route {
@service kredits;
async setupController (controller) {
if (!window.ethereum) return;
if (this.kredits.hasAccounts) {
controller.accountAddress = this.kredits.currentUserAccounts.firstObject;
} else {
return this.kredits.connectWallet();
}
}
redirect () {
if (isEmpty(this.kredits.githubAccessToken)) {
this.transitionTo('signup.index');
}
}
}
-17
View File
@@ -1,17 +0,0 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
import { isEmpty } from '@ember/utils';
export default Route.extend({
kredits: service(),
redirect () {
this._super(...arguments);
if (isEmpty(this.kredits.githubAccessToken)) {
this.transitionTo('signup.index');
}
}
});
+1 -1
View File
@@ -22,7 +22,7 @@ export default Route.extend({
this.kredits.set('githubAccessToken', accessToken);
this.transitionTo('signup.eth-account');
this.transitionTo('signup.account');
}
});
+2 -2
View File
@@ -4,8 +4,8 @@ import config from 'kredits-web/config/environment';
function createStore(name) {
let networkName;
if (config.web3RequiredNetworkName) {
networkName = config.web3RequiredNetworkName.toLocaleLowerCase().replace(' ', '-');
if (config.web3NetworkName) {
networkName = config.web3NetworkName.toLocaleLowerCase().replace(' ', '-');
} else {
networkName = 'custom';
}
+52 -24
View File
@@ -5,7 +5,7 @@ import Service from '@ember/service';
import EmberObject from '@ember/object';
import { computed } from '@ember/object';
import { alias, filterBy, notEmpty, sort } from '@ember/object/computed';
import { isEmpty, isPresent } from '@ember/utils';
import { isEmpty } from '@ember/utils';
import { inject as service } from '@ember/service';
import { task, taskGroup } from 'ember-concurrency';
@@ -15,6 +15,7 @@ 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 switchNetwork from 'kredits-web/utils/switch-network';
import config from 'kredits-web/config/environment';
import Contributor from 'kredits-web/models/contributor';
@@ -55,6 +56,21 @@ export default Service.extend({
this.set('contributors', []);
this.set('contributions', []);
this.set('reimbursements', []);
if (window.ethereum) {
window.ethereum.on('chainChanged', this.handleUserChainChanged);
window.ethereum.on('accountsChanged', this.handleAccountsChanged);
}
},
handleUserChainChanged (chainId) {
console.log('User-provided chain ID changed to', chainId);
window.location.reload();
},
handleAccountsChanged (accounts) {
console.log('User-provided accounts changed to', accounts);
window.location.reload();
},
// This is called in the application route's beforeModel(). So it is
@@ -64,7 +80,7 @@ export default Service.extend({
let ethProvider;
return new Promise(resolve => {
function instantiateWithoutAccount () {
function instantiateWithoutWallet () {
console.debug('[kredits] Creating new instance from npm module class');
console.debug(`[kredits] providerURL: ${config.web3ProviderUrl}`);
ethProvider = new ethers.providers.JsonRpcProvider(config.web3ProviderUrl);
@@ -74,44 +90,50 @@ export default Service.extend({
});
}
async function instantiateWithAccount (web3Provider, context) {
async function instantiateWithWallet (web3Provider, context) {
console.debug('[kredits] Using user-provided Web3 instance, e.g. from Metamask');
ethProvider = new ethers.providers.Web3Provider(web3Provider);
ethProvider = new ethers.providers.Web3Provider(web3Provider);
const network = await ethProvider.getNetwork();
const accounts = await ethProvider.listAccounts();
const chainId = config.web3ChainId;
const network = await ethProvider.getNetwork();
if (isPresent(config.web3RequiredChainId) &&
network.chainId !== config.web3RequiredChainId) {
return instantiateWithoutAccount();
}
if (isEmpty(accounts)) return instantiateWithoutWallet();
ethProvider.listAccounts().then(accounts => {
if (network.chainId !== chainId) {
return switchNetwork();
} else {
context.set('currentUserAccounts', accounts);
const ethSigner = accounts.length === 0 ? null : ethProvider.getSigner();
resolve({
ethProvider,
ethSigner
});
});
}
}
if (window.ethereum) {
if (window.ethereum.isConnected()) {
instantiateWithAccount(window.ethereum, this);
} else {
instantiateWithoutAccount();
}
}
// Legacy dapp browsers...
else if (window.web3) {
instantiateWithAccount(window.web3.currentProvider, this);
}
// Non-dapp browsers...
else {
instantiateWithoutAccount();
instantiateWithWallet(window.ethereum, this);
} else {
instantiateWithoutWallet();
}
});
},
async connectWallet () {
const provider = new ethers.providers.Web3Provider(window.ethereum);
const network = await provider.getNetwork();
const chainId = config.web3ChainId;
const chainIdHex = `0x${Number(chainId).toString(16)}`;
try {
await window.ethereum.request({ method: 'eth_requestAccounts' });
if (network.chainId !== chainId) await switchNetwork(chainIdHex);
} catch (err) {
console.log('Connecting wallet failed:', err);
return false;
}
},
async setup () {
const kredits = await this.getEthProvider().then(providerAndSigner => {
return new Kredits(providerAndSigner.ethProvider, providerAndSigner.ethSigner, {
@@ -274,6 +296,12 @@ export default Service.extend({
});
},
async fetchContributor (id) {
console.debug(`[kredits] Fetching contributor from the network`);
return this.kredits.Contributor.getById(id)
.then(data => this.loadContributorFromData(data))
},
fetchContributors () {
console.debug(`[kredits] Fetching all contributors from the network`);
return this.kredits.Contributor.all()
+30 -26
View File
@@ -45,14 +45,16 @@
</div>
</section>
<section id="contributions-by-type">
<header>
<h2>Contributions by type</h2>
</header>
<div class="content">
<ChartContributionsByType @contributions={{this.contributions}} />
</div>
</section>
{{#if this.contributionsConfirmed}}
<section id="contributions-by-type">
<header>
<h2>Contributions by type</h2>
</header>
<div class="content">
<ChartContributionsByType @contributions={{this.contributions}} />
</div>
</section>
{{/if}}
</div>
<div id="contributions">
@@ -87,24 +89,26 @@
</section>
{{/if}}
<section id="contributions-confirmed">
<header class="with-nav">
<h2>Confirmed Contributions</h2>
<nav>
<button type="button"
onclick={{action "toggleQuickFilterConfirmed"}}
class="small {{if this.showQuickFilterConfirmed "active"}}">
filter
</button>
</nav>
</header>
<div class="content">
<ContributionList @contributions={{this.contributionsConfirmedSorted}}
@vetoContribution={{action "vetoContribution"}}
@selectedContributionId={{this.selectedContributionId}}
@showQuickFilter={{this.showQuickFilterConfirmed}} />
</div>
</section>
{{#if this.contributionsConfirmed}}
<section id="contributions-confirmed">
<header class="with-nav">
<h2>Confirmed Contributions</h2>
<nav>
<button type="button"
onclick={{action "toggleQuickFilterConfirmed"}}
class="small {{if this.showQuickFilterConfirmed "active"}}">
filter
</button>
</nav>
</header>
<div class="content">
<ContributionList @contributions={{this.contributionsConfirmedSorted}}
@vetoContribution={{action "vetoContribution"}}
@selectedContributionId={{this.selectedContributionId}}
@showQuickFilter={{this.showQuickFilterConfirmed}} />
</div>
</section>
{{/if}}
{{#if this.showFullContributionSync}}
<section id="sync-all-contributions">
@@ -31,7 +31,7 @@
<div class="actions">
<p>
<a href="https://rinkeby.etherscan.io/address/{{this.model.account}}" class="button small" target="_blank" rel="noopener noreferrer">Inspect Ethereum transactions</a>
<a href="https://explorer.testnet.rsk.co/address/{{this.model.account}}" class="button small" target="_blank" rel="noopener noreferrer">Inspect Rootstock transactions</a>
{{#if this.model.ipfsHash}}
<a href="{{this.ipfsGatewayUrl}}/{{this.model.ipfsHash}}" class="button small" target="_blank" rel="noopener noreferrer">Inspect IPFS profile</a>
{{/if}}
+30
View File
@@ -0,0 +1,30 @@
<header>
<h2>Complete your contributor profile</h2>
</header>
<div class="content text-lg">
<p class="mb-8">
Kredits allow you to to earn rewards for your contributions, in the form of
dynamic open-source grants. As a regular contributor, you can also take
part in the community's project governance and finances.
</p>
<p>
In order to interact with the system you will need a
<a href="https://rootstock.io" target="_blank" rel="noopener noreferrer">Rootstock</a>
wallet/account.
</p>
<form>
<p>
<label>
Rootstock address:<br>
<Input @type="text" @value={{this.accountAddress}} placeholder="0xF18E631Ea191aE4ebE70046Fcb01a436554421BA4" class={{if this.isValidEthAccount "valid" ""}} />
</label>
</p>
</form>
<p class="actions">
<button {{on "click" (fn this.completeSignup)}}
disabled={{this.signupButtonDisabled}}
type="button">
Complete my profile
</button>
</p>
</div>
+2 -1
View File
@@ -7,7 +7,8 @@
</p>
<p>
Why not say hi to your fellow contributors
<a href="https://wiki.kosmos.org/Main_Page#Community_.2F_Getting_in_touch_.2F_Getting_involved">in one of our chat rooms</a>?.
<a href="https://wiki.kosmos.org/Main_Page#Community_.2F_Getting_in_touch_.2F_Getting_involved"
target="_blank" rel="noopener noreferrer">in one of our chat rooms</a>?.
</p>
<p class="actions">
<LinkTo @route="dashboard" class="button small">Return to dashboard</LinkTo>
-24
View File
@@ -1,24 +0,0 @@
<header>
<h2>Complete your contributor profile</h2>
</header>
<div class="content text-lg">
<p class="mb-8">
Kredits allow you to take part in project governance, and to earn rewards for
your contributions. For both, you will need an Ethereum wallet/account.
</p>
<form>
<p>
<label>
Ethereum account:<br>
<Input @type="text" @value={{this.ethAddress}} placeholder="0xF18E631Ea191aE4ebE70046Fcb01a436554421BA4" class={{if this.isValidEthAccount "valid" ""}} />
</label>
</p>
</form>
<p class="actions">
<button disabled={{this.signupButtonDisabled}}
onclick={{action "completeSignup"}}
type="button">
Complete my profile
</button>
</p>
</div>
+29
View File
@@ -0,0 +1,29 @@
import config from 'kredits-web/config/environment';
export default async function () {
const networkName = config.web3NetworkName;
const chainId = config.web3ChainId;
const chainIdHex = `0x${Number(chainId).toString(16)}`;
try {
await window.ethereum.request({
method: 'wallet_switchEthereumChain',
params: [{ chainId: chainIdHex }]
});
} catch (err) {
// This error code indicates that the chain has not been added to MetaMask
if (err.code === 4902) {
await window.ethereum.request({
method: 'wallet_addEthereumChain',
params: [{
chainId: chainIdHex,
chainName: networkName,
rpcUrls: [ config.web3ProviderUrl ],
nativeCurrency: { name: 'tRBTC', symbol: 'tRBTC', decimals: 18 }
}]
});
} else {
console.warn('Failed to switch chains:', err.message);
}
}
}
+10 -5
View File
@@ -26,11 +26,11 @@ module.exports = function(environment) {
},
web3ProviderUrl: 'https://rsk-testnet.kosmos.org',
web3RequiredChainId: 31,
web3RequiredNetworkName: 'RSK Testnet',
web3ChainId: 31,
web3NetworkName: 'RSK Testnet',
githubConnectUrl: 'https://hal8000.chat.kosmos.org/kredits/signup/connect/github',
githubSignupUrl: 'https://hal8000.chat.kosmos.org/kredits/signup/github',
githubConnectUrl: 'https://hal8000.kosmos.chat/kredits/signup/connect/github',
githubSignupUrl: 'https://hal8000.kosmos.chat/kredits/signup/github',
ipfs: {
host: 'ipfs.kosmos.org',
@@ -82,7 +82,12 @@ module.exports = function(environment) {
if (process.env.WEB3_PROVIDER_URL) {
ENV.web3ProviderUrl = process.env.WEB3_PROVIDER_URL;
ENV.web3RequiredChainId = null;
}
if (process.env.WEB3_CHAIN_ID) {
ENV.web3ChainId = parseInt(process.env.WEB3_CHAIN_ID);
}
if (process.env.WEB3_NETWORK_NAME) {
ENV.web3NetworkName = process.env.WEB3_NETWORK_NAME;
}
return ENV;
+9 -9
View File
@@ -1,12 +1,12 @@
{
"name": "kredits-web",
"version": "2.0.0-beta.3",
"version": "2.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "kredits-web",
"version": "2.0.0-beta.3",
"version": "2.0.0",
"license": "MIT",
"devDependencies": {
"@babel/eslint-parser": "^7.19.1",
@@ -14,7 +14,7 @@
"@ember/optional-features": "^1.3.0",
"@glimmer/component": "^1.0.0",
"@glimmer/tracking": "^1.0.0",
"@kredits/contracts": "^7.0.1",
"@kredits/contracts": "^7.3.0",
"babel-preset-es2015": "^6.22.0",
"broccoli-asset-rev": "^3.0.0",
"ember-auto-import": "^1.12.1",
@@ -3067,9 +3067,9 @@
"license": "MIT"
},
"node_modules/@kredits/contracts": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@kredits/contracts/-/contracts-7.0.1.tgz",
"integrity": "sha512-4IhNQoPc1BCT63NKyDOmV+ryb82FKNbIqfDyTdant6WTI9lfkIAnI8Et+ynQmqxx3Efez5hqoDZtEhCijcuIng==",
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/@kredits/contracts/-/contracts-7.3.0.tgz",
"integrity": "sha512-7Bo2LFEqGIK39G54AStas1RWouBOp+r7Vcv2vP1uLbY01Usea8SHvd2OjLP6nFgsQa0n/rto9oremHv5IAylrQ==",
"dev": true,
"dependencies": {
"@kosmos/schemas": "^3.1.0",
@@ -26066,9 +26066,9 @@
"dev": true
},
"@kredits/contracts": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@kredits/contracts/-/contracts-7.0.1.tgz",
"integrity": "sha512-4IhNQoPc1BCT63NKyDOmV+ryb82FKNbIqfDyTdant6WTI9lfkIAnI8Et+ynQmqxx3Efez5hqoDZtEhCijcuIng==",
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/@kredits/contracts/-/contracts-7.3.0.tgz",
"integrity": "sha512-7Bo2LFEqGIK39G54AStas1RWouBOp+r7Vcv2vP1uLbY01Usea8SHvd2OjLP6nFgsQa0n/rto9oremHv5IAylrQ==",
"dev": true,
"requires": {
"@kosmos/schemas": "^3.1.0",
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "kredits-web",
"version": "2.0.0-beta.3",
"version": "2.0.0",
"private": true,
"description": "Contribution dashboard of the Kosmos project",
"repository": "https://github.com/67P/kredits-web",
@@ -17,7 +17,7 @@
"start": "ember serve",
"test": "npm-run-all lint:* test:*",
"test:ember": "ember test",
"start:local": "WEB3_PROVIDER_URL=http://localhost:8545 ember serve",
"start:local": "WEB3_PROVIDER_URL=http://localhost:8545 WEB3_CHAIN_ID=1337 WEB3_NETWORK_NAME='Hardhat Devchain' ember serve",
"build": "ember build --environment=production",
"build-prod": "rm -rf release/* && ember build -prod --output-path release",
"preversion": "npm test",
@@ -30,7 +30,7 @@
"@ember/optional-features": "^1.3.0",
"@glimmer/component": "^1.0.0",
"@glimmer/tracking": "^1.0.0",
"@kredits/contracts": "^7.0.1",
"@kredits/contracts": "^7.3.0",
"babel-preset-es2015": "^6.22.0",
"broccoli-asset-rev": "^3.0.0",
"ember-auto-import": "^1.12.1",
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+3 -3
View File
@@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="kredits-web/config/environment" content="%7B%22modulePrefix%22%3A%22kredits-web%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22auto%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_DEFAULT_ASYNC_OBSERVERS%22%3Atrue%2C%22_JQUERY_INTEGRATION%22%3Afalse%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22name%22%3A%22kredits-web%22%2C%22version%22%3A%222.0.0-beta.3%2Bd90ddd46%22%7D%2C%22web3ProviderUrl%22%3A%22https%3A%2F%2Frsk-testnet.kosmos.org%22%2C%22web3RequiredChainId%22%3A31%2C%22web3RequiredNetworkName%22%3A%22RSK%20Testnet%22%2C%22githubConnectUrl%22%3A%22https%3A%2F%2Fhal8000.chat.kosmos.org%2Fkredits%2Fsignup%2Fconnect%2Fgithub%22%2C%22githubSignupUrl%22%3A%22https%3A%2F%2Fhal8000.chat.kosmos.org%2Fkredits%2Fsignup%2Fgithub%22%2C%22ipfs%22%3A%7B%22host%22%3A%22ipfs.kosmos.org%22%2C%22port%22%3A%225444%22%2C%22protocol%22%3A%22https%22%2C%22gatewayUrl%22%3A%22https%3A%2F%2Fipfs.kosmos.org%2Fipfs%22%7D%2C%22tokens%22%3A%7B%22BTC%22%3A%220x2260fac5e5542a773aa44fbcfedf7c193bc2c599%22%7D%2C%22btcBalanceAPI%22%3A%22https%3A%2F%2Fapi.kosmos.org%2Fkredits%2Fonchain_btc_balance%22%2C%22corsProxy%22%3A%22https%3A%2F%2Fcors.5apps.com%2F%3Furi%3D%22%2C%22exportApplicationGlobal%22%3Afalse%7D" />
<meta name="kredits-web/config/environment" content="%7B%22modulePrefix%22%3A%22kredits-web%22%2C%22environment%22%3A%22production%22%2C%22rootURL%22%3A%22%2F%22%2C%22locationType%22%3A%22auto%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%2C%22EXTEND_PROTOTYPES%22%3A%7B%22Date%22%3Afalse%7D%2C%22_APPLICATION_TEMPLATE_WRAPPER%22%3Afalse%2C%22_DEFAULT_ASYNC_OBSERVERS%22%3Atrue%2C%22_JQUERY_INTEGRATION%22%3Afalse%2C%22_TEMPLATE_ONLY_GLIMMER_COMPONENTS%22%3Atrue%7D%2C%22APP%22%3A%7B%22name%22%3A%22kredits-web%22%2C%22version%22%3A%222.0.0%2Bbdeab512%22%7D%2C%22web3ProviderUrl%22%3A%22https%3A%2F%2Frsk-testnet.kosmos.org%22%2C%22web3ChainId%22%3A31%2C%22web3NetworkName%22%3A%22RSK%20Testnet%22%2C%22githubConnectUrl%22%3A%22https%3A%2F%2Fhal8000.kosmos.chat%2Fkredits%2Fsignup%2Fconnect%2Fgithub%22%2C%22githubSignupUrl%22%3A%22https%3A%2F%2Fhal8000.kosmos.chat%2Fkredits%2Fsignup%2Fgithub%22%2C%22ipfs%22%3A%7B%22host%22%3A%22ipfs.kosmos.org%22%2C%22port%22%3A%225444%22%2C%22protocol%22%3A%22https%22%2C%22gatewayUrl%22%3A%22https%3A%2F%2Fipfs.kosmos.org%2Fipfs%22%7D%2C%22tokens%22%3A%7B%22BTC%22%3A%220x2260fac5e5542a773aa44fbcfedf7c193bc2c599%22%7D%2C%22btcBalanceAPI%22%3A%22https%3A%2F%2Fapi.kosmos.org%2Fkredits%2Fonchain_btc_balance%22%2C%22corsProxy%22%3A%22https%3A%2F%2Fcors.5apps.com%2F%3Furi%3D%22%2C%22exportApplicationGlobal%22%3Afalse%7D" />
<link integrity="" rel="stylesheet" href="/assets/vendor-ca96b2e19fc9f356e3dbad90c9f3f323.css">
<link integrity="" rel="stylesheet" href="/assets/kredits-web-f21602587acec9a1744c244385a83592.css">
@@ -24,8 +24,8 @@
<body>
<script src="/assets/vendor-4ee536ded971436a83d35253df25f2cb.js" integrity="sha256-yb+pC9iuZ8WcQwk9VuDNhSlWguL7BEABsEOEhBpwUC0= sha512-50LApx5XqeKHu/FMaljzqhAMPgkqSiy2rDhUcViYBcXWBBYmilFirup/iWvLiNCdfr5ct9wk7+tU9iShdSgDww==" ></script>
<script src="/assets/kredits-web-89113e4d5c371829e3d1b05e86cbab9b.js" integrity="sha256-aabl6JZt69T2BZIv4yXcRFfmhWCyEhVA2V4g1ZzkZ6s= sha512-aD0s+kWNsXdHJFxIkgncvwNZVhtARosjjKnbLE0w1ihSrvRoptWXV1SgySdZIHKxFgbNmJGA2oQOzhBKIoqvVg==" ></script>
<script src="/assets/vendor-4d87b3e0995c5bb18e46836a089900a4.js" integrity="sha256-5WmWY05Kd+n98Sw0GwuaWodmDVBZ2yVGGtC/2owVfQE= sha512-tiGPA5zvfhnSC9LPTmpvXJmOu30yhsdPqSiZJMPGmE/ez/xJLMaM29vjs4Cs74cDf6fX4uYSGRIu1KfOyGpJYA==" ></script>
<script src="/assets/kredits-web-ae44ce0c1a892c2da424f8002b037b86.js" integrity="sha256-ZT6R9QwhnMEgs1X3pmlX6Oh5N4zJgXWLF8al8PTOKqk= sha512-BYrlNe9cti4ZEcp//b5FhPGvmAE08vTEC3WT15EpTqTXccNkOqFJuiGob+ymxIDfDzVU6vN8szxCTBOUe61Tmw==" ></script>
</body>
@@ -3,37 +3,90 @@ import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
function stubWalletApi () {
window.ethereum = {
on: function() { return true; },
request: function() { return Promise.resolve(); }
}
}
module('Integration | Component | topbar-account-panel', function(hooks) {
setupRenderingTest(hooks);
test('unknown user without wallet (or no permission to get wallet/account info)', async function(assert) {
test('Unknown user without wallet', async function(assert) {
await render(hbs`<TopbarAccountPanel />`);
assert.ok(this.element.textContent.trim().match(/^Anonymous/));
assert.ok(
this.element.textContent.trim().match(/^Anonymous/),
'shows current user as anonymous'
);
assert.equal(
this.element.querySelectorAll('button#signup').length, 1,
'signup button is visible'
);
assert.equal(
this.element.querySelectorAll('button#connect').length, 0,
'connect button is not visible'
);
});
test('unknown user with Ethereum wallet', async function(assert) {
test('Unknown user with disconnected wallet', async function(assert) {
stubWalletApi();
let service = this.owner.lookup('service:kredits');
service.set('currentUserAccounts', []);
await render(hbs`<TopbarAccountPanel />`);
assert.ok(
this.element.textContent.trim().match(/^Anonymous/),
'shows current user as anonymous'
);
assert.equal(
this.element.querySelectorAll('button#signup').length, 1,
'signup button is visible'
);
assert.equal(
this.element.querySelectorAll('button#connect').length, 1,
'connect button is visible'
);
});
test('Unknown user with connected wallet', async function(assert) {
stubWalletApi();
let service = this.owner.lookup('service:kredits');
service.set('currentUserAccounts', [{ foo: 'bar' }]);
await render(hbs`<TopbarAccountPanel />`);
assert.ok(this.element.textContent.trim().match(/^Anonymous/));
assert.ok(
this.element.textContent.trim().match(/^Anonymous/),
'shows current user as anonymous'
);
assert.equal(
this.element.querySelectorAll('button#signup').length, 1,
'signup button is visible'
);
assert.equal(
this.element.querySelectorAll('button#connect').length, 0,
'connect button is not visible'
);
});
test('known contributor', async function(assert) {
test('Known contributor', async function(assert) {
stubWalletApi();
let service = this.owner.lookup('service:kredits');
service.set('currentUserAccounts', [{ foo: 'bar' }]);
service.set('currentUser', {
name: 'Dorian Nakamoto',
isCore: false
});
service.set('currentUser', { name: 'Dorian Nakamoto', isCore: false });
await render(hbs`<TopbarAccountPanel />`);
assert.dom(this.element).hasText('Dorian Nakamoto');
service.set('currentUser.isCore', true);
await render(hbs`<TopbarAccountPanel />`);
assert.equal(this.element.querySelectorAll('span.core-flag').length, 1);
assert.dom(this.element).hasText(
'Dorian Nakamoto', 'shows current user\'s name'
);
assert.equal(
this.element.querySelectorAll('button#signup').length, 0,
'signup button is not visible'
);
assert.equal(
this.element.querySelectorAll('button#connect').length, 0,
'connect button is not visible'
);
});
});
@@ -1,11 +1,11 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
module('Unit | Route | signup/eth-account', function(hooks) {
module('Unit | Route | signup/account', function(hooks) {
setupTest(hooks);
test('it exists', function(assert) {
let route = this.owner.lookup('route:signup/eth-account');
let route = this.owner.lookup('route:signup/account');
assert.ok(route);
});
});