Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fabo/1294 undelegation modal #1367

Merged
merged 36 commits into from
Oct 5, 2018
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
b22ee0a
copied staking modal
Sep 26, 2018
defec9f
unstaking working
Sep 26, 2018
3a72ac8
copied unstake modal spec
Sep 26, 2018
f06915c
Copy ModalUnstake tests in PageValidator.spec.js and start adapting t…
Sep 26, 2018
fdc3f5d
Merge branch 'develop' into fabo/1294-undelegation-modal
faboweb Sep 26, 2018
4e47112
Merge branch 'develop' into fabo/1294-undelegation-modal
jbibla Sep 27, 2018
4bff2d2
Make all unit tests pass for unstaking.
Sep 27, 2018
f38db9f
fix status color missing
Sep 28, 2018
5a5df5d
Merge remote-tracking branch 'origin/develop' into fabo/1294-undelega…
Sep 28, 2018
05a4324
added ux updates to modal unstake
Sep 28, 2018
2740908
changelog
Sep 28, 2018
0a55983
linted
Sep 28, 2018
885ed25
fixed tests
Sep 28, 2018
2e55de3
fixed snapshots
Sep 28, 2018
7bea969
Add E2E test for unstaking.
Oct 1, 2018
47d6078
fix less then 0.01 displaying
Oct 1, 2018
d52ea53
reverted disabling of unstake button
Oct 1, 2018
2abd961
fixed snapshot
Oct 1, 2018
c274d74
Merge remote-tracking branch 'refs/remotes/origin/develop'
Oct 1, 2018
82e31fa
Merge remote-tracking branch 'refs/remotes/origin/develop'Conflicts: …
Oct 1, 2018
9c1b694
linted
Oct 1, 2018
4a96733
fixed e2e tests
Oct 1, 2018
43f5d88
fix e2e tests
Oct 1, 2018
86a9fe0
fix snapshot
Oct 1, 2018
f157c9e
fix naming
Oct 1, 2018
d7693f7
uncommented console error file
Oct 1, 2018
e9e5517
Merge branch 'develop' into fabo/1294-undelegation-modal
faboweb Oct 2, 2018
685c886
merged develop
Oct 2, 2018
39a96dc
Merge remote-tracking branch 'origin/develop' into fabo/1294-undelega…
Oct 2, 2018
0374842
fixed
Oct 4, 2018
40fdadd
add a delegation to the validator page snapshot
Oct 4, 2018
6f30319
fixed merge conflicts
Oct 4, 2018
99032b0
Merge branch 'develop' into fabo/1294-undelegation-modal
faboweb Oct 4, 2018
6fe71a6
close signal, disable button, denom and tests
Oct 5, 2018
ca2a054
fix unit tests
Oct 5, 2018
aed26e5
Merge branch 'develop' into fabo/1294-undelegation-modal
fedekunze Oct 5, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* more tests for new staking modal @NodeGuy
* Add commission and uptime to LiValidator @fedekunze
* Delete old bonding page @fedekunze
* added unstake modal @faboweb

### Changed

Expand Down
21 changes: 10 additions & 11 deletions app/src/renderer/components/staking/LiValidator.vue
Original file line number Diff line number Diff line change
Expand Up @@ -124,18 +124,17 @@ export default {

// status: validator
return `This validator is actively validating`
},
faboweb marked this conversation as resolved.
Show resolved Hide resolved
statusColor() {
// status: jailed
if (this.delegate.revoked) return `red`

// status: candidate
if (parseFloat(this.delegate.voting_power) === 0) return `yellow`

// status: validator
return `green`
}
// TODO enable once we decide on limits
// statusColor() {
// // status: jailed
// if (this.delegate.revoked) return "red"
//
// // status: candidate
// if (parseFloat(this.delegate.voting_power) === 0) return "yellow"
//
// // status: validator
// return "green"
// }
},
data: () => ({ num, shortAddress })
}
Expand Down
117 changes: 117 additions & 0 deletions app/src/renderer/components/staking/ModalUnstake.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<template lang="pug">
.modal-unstake#modal-unstake(v-click-outside="close")
//- Header
.stake-header
img.icon(class='stake-atom' src="~assets/images/cosmos-logo.png")
span.tm-modal-title Unstake
.tm-modal-icon.tm-modal-close(@click="close()")
i.material-icons close

//- To
tm-form-group.stake-form-group(
field-id='to' field-label='To')
tm-field#to(
readonly v-model="to")

//- Amount
tm-form-group.stake-form-group(
field-id='amount'
field-label='Amount'
)
tm-field#amount(
:max="maximum"
:min="0"
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
type="number"
v-focus
v-model="amount")

//- Footer
.stake-footer
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
tm-btn(
@click.native="onUnstake"
:disabled="$v.amount.$invalid"
color="primary"
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
size="lg"
value="Unstake"
)
</template>

<script>
import ClickOutside from "vue-click-outside"
import { required, between } from "vuelidate/lib/validators"
import Modal from "common/TmModal"
import { TmBtn, TmField, TmFormGroup, TmFormMsg } from "@tendermint/ui"

export default {
props: [`maximum`, `to`],
components: {
Modal,
TmBtn,
TmField,
TmFormGroup,
TmFormMsg
},
data: () => ({
amount: 0
}),
validations() {
return {
amount: {
required,
between: between(0, this.maximum)
}
}
},
methods: {
close() {
this.$emit(`update:showModalUnstake`, false)
},
onUnstake() {
this.$emit(`submitUndelegation`, {
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
amount: this.amount
})

this.close()
}
},
directives: {
ClickOutside
}
}
</script>

<style lang="stylus">
@import '~variables'

.modal-unstake
background var(--app-nav)
display flex
flex-direction column
height 50%
justify-content space-between
left 50%
padding 2em
position fixed
top 50%
width 40%
z-index z(modal)

.stake-header
align-items center
display flex

.stake-atom
height 3em
width 3em

.stake-form-group
display block
padding 0

.stake-footer
display flex
justify-content flex-end

button
margin-left 1em
</style>
99 changes: 94 additions & 5 deletions app/src/renderer/components/staking/PageValidator.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,15 @@ tm-page
//- TODO replace with address component when ready
anchor-copy.validator-profile__header__name__address(:value="validator.owner" :label="shortAddress(validator.owner)")
.column.validator-profile__header__actions
tm-btn(id="stake-btn" value="Stake" color="primary" @click.native="onStake()")
tm-btn(v-if="config.devMode" value="Unstake" color="secondary")
tm-btn(id="stake-btn" value="Stake" color="primary" @click.native="onStake")

tm-btn(
id="unstake-btn"
value="Unstake"
color="secondary"
@click.native="onUnstake"
)

.row.validator-profile__header__data
dl.colored_dl
dt My Stake
Expand Down Expand Up @@ -91,30 +98,61 @@ tm-page
:to="validator.owner"
)

modal-unstake(
v-if="showModalUnstake"
v-on:submitUndelegation="submitUndelegation"
:showModalUnstake.sync="showModalUnstake"
:maximum="myBond"
:to="this.wallet.address"
)

tm-modal(:close="closeCannotStake" icon="warning" v-if="showCannotStake")
div(slot='title') Cannot Stake
p You have no {{ bondingDenom }}s to stake.
div(slot='footer')
tmBtn(id="no-atoms-modal__btn" @click.native="closeCannotStake()" value="OK")
tmBtn(
id="no-atoms-modal__btn"
@click.native="closeCannotStake"
value="OK"
)

tm-modal(
fedekunze marked this conversation as resolved.
Show resolved Hide resolved
:close="closeCannotUnstake"
icon="warning"
v-if="showCannotUnstake"
)
div(slot='title') Cannot Unstake
p You have no {{ bondingDenom }}s staked with this validator.
div(slot='footer')
tmBtn(
id="no-bond-modal__btn"
@click.native="closeCannotUnstake"
value="OK"
)
</template>

<script>
import BigNumber from "bignumber.js"
import { calculateTokens } from "scripts/common"
import { mapGetters } from "vuex"
import { TmBtn, TmListItem, TmPage, TmPart, TmToolBar } from "@tendermint/ui"
import { TmDataError } from "common/TmDataError"
import { shortAddress, ratToBigNumber } from "scripts/common"
import ModalStake from "staking/ModalStake"
import ModalUnstake from "staking/ModalUnstake"
import numeral from "numeral"
import AnchorCopy from "common/AnchorCopy"
import TmBalance from "common/TmBalance"
import TmModal from "common/TmModal"
export default {
name: `page-validator`,
components: {
AnchorCopy,
ModalStake,
ModalUnstake,
TmBtn,
TmListItem,
TmBalance,
TmModal,
TmPage,
TmPart,
TmToolBar,
Expand All @@ -123,7 +161,9 @@ export default {
},
data: () => ({
showCannotStake: false,
showCannotUnstake: false,
showModalStake: false,
showModalUnstake: false,
shortAddress,
tabIndex: 1
}),
Expand Down Expand Up @@ -153,7 +193,10 @@ export default {
: 0
},
myBond() {
return this.delegation.committedDelegates[this.validator.owner] || 0
return calculateTokens(
this.validator,
this.delegation.committedDelegates[this.validator.owner] || 0
)
},
powerRatio() {
return ratToBigNumber(this.validator.tokens)
Expand Down Expand Up @@ -202,13 +245,23 @@ export default {
closeCannotStake() {
this.showCannotStake = false
},
closeCannotUnstake() {
this.showCannotUnstake = false
},
onStake() {
if (this.availableAtoms > 0) {
this.showModalStake = true
} else {
this.showCannotStake = true
}
},
onUnstake() {
if (this.myBond.isEqualTo(BigNumber(0))) {
this.showCannotUnstake = true
} else {
this.showModalUnstake = true
}
},
async submitDelegation({ amount }) {
try {
await this.$store.dispatch(`submitDelegation`, {
Expand Down Expand Up @@ -243,6 +296,42 @@ export default {
}
}
},
async submitUndelegation({ amount }) {
try {
await this.$store.dispatch(`submitDelegation`, {
unbondings: [
{
atoms: -amount,
delegate: this.validator
}
]
})

this.$store.commit(`notify`, {
title: `Successful Unstaking!`,
body: `You have successfully unstaked ${amount} ${
this.bondingDenom
}s.`
})
} catch (exception) {
const { message } = exception
let errData = message.split(`\n`)[5]

if (errData) {
let parsedErr = errData.split(`"`)[1]

this.$store.commit(`notifyError`, {
title: `Error While Unstaking ${this.bondingDenom}s`,
body: parsedErr[0].toUpperCase() + parsedErr.slice(1)
})
} else {
this.$store.commit(`notifyError`, {
title: `Error While Unstaking ${this.bondingDenom}s`,
body: message
})
}
}
},
pretty(num) {
return numeral(num).format(`0,0.00`)
},
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
"user-home": "2.0.0",
"varint": "5.0.0",
"vue": "2.5.16",
"vue-click-outside": "1.0.7",
"vue-directive-tooltip": "1.4.5",
"vue-electron": "1.0.6",
"vue-router": "3.0.1",
Expand Down
38 changes: 36 additions & 2 deletions test/e2e/staking.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,42 @@ test(`staking`, async function(t) {
// Go back to Staking page.
.click(`//a//*[. = 'Staking']`)

// Why is this necessary? See
// https://github.com/jprichardson/tape-promise#example-asyncawait
// Shouldn't be necessary but see
// https://github.com/jprichardson/tape-promise/issues/17#issuecomment-425276035.
t.end()
})

t.test(`Unstake`, async t => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 @NodeGuy

await app.client
// Select the Validators tab.
.click(`//a[. = 'Validators']`)

// Select the second validator.
.click(`//*[. = 'local_1']`)

// For some reason we need to sleep at this point in order to prevent the
// following error:
//
// Element <span class="tm-btn__container tm-btn--primary">...</span> is not
// clickable at point (960, 219). Other element would receive the click:
// <div class="ps__rail-y" style="top: 0px; height: 557px; right:
// 0px;">...</div>
await sleep(500)

await app.client
.click(`//button/*[. = 'Unstake']`)
.setValue(`#amount`, 5)
.click(`//*[@id = 'modal-unstake']//button//*[. = 'Unstake']`)
.waitForVisible(
`//*[. = 'You have successfully unstaked 5 Steaks.']`,
5 * 1000
)

// Go back to Staking page.
.click(`//a//*[. = 'Staking']`)

// Shouldn't be necessary but see
// https://github.com/jprichardson/tape-promise/issues/17#issuecomment-425276035.
t.end()
})

Expand Down
Loading