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

peng/create modal for fullscreen error #508

Merged
merged 12 commits into from
Mar 2, 2018
3 changes: 3 additions & 0 deletions app/src/renderer/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@
modal-help
session(v-else)
notifications(:notifications='notifications' theme='cosmos')
modal-error(v-if="config.modals.error.active")
</template>

<script>
import { mapGetters } from 'vuex'
import AppHeader from 'common/AppHeader'
import AppFooter from 'common/AppFooter'
import Notifications from '@nylira/vue-notifications'
import ModalError from 'common/NiModalError'
import ModalHelp from 'common/NiModalHelp'
import Session from 'common/NiSession'
import store from './vuex/store'
Expand All @@ -23,6 +25,7 @@ export default {
components: {
AppHeader,
AppFooter,
ModalError,
ModalHelp,
Notifications,
Session
Expand Down
122 changes: 122 additions & 0 deletions app/src/renderer/components/common/NiModalError.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<template lang="pug">
.ni-modal-error__wrapper
.ni-modal-error
.ni-modal-error__icon: i.material-icons {{ errorIcon }}
.ni-modal-error__title {{ errorTitle }}
.ni-modal-error__body {{ errorBody }}
.ni-modal-error__footer
btn#ni-modal-error__btn-issue(
size="lg"
icon="bug_report"
color="primary"
value="Create an issue"
type="anchor"
:href="issueUrl")
btn#ni-modal-error__btn-logs(
size="lg"
icon="info_outline"
value="View app logs"
@click.native="viewLogs")
</template>

<script>
import { remote, shell } from 'electron'
import Btn from '@nylira/vue-button'
export default {
name: 'ni-modal-error',
components: {
Btn
},
computed: {
errorIcon () {
if (this.icon) return this.icon
else return 'error_outline'
},
errorTitle () {
if (this.title) return this.title
else return 'Voyager ran into an error'
},
errorBody () {
if (this.body) return this.body
else return 'Voyager has encountered a critical error that blocks the app from running. Please create an issue and include a copy of the app logs.'
}
},
data: () => ({
logPath: '',
chatUrl: 'https://web.telegram.org/#/im?p=@cosmosproject',
issueUrl: 'https://github.com/cosmos/voyager/issues'
}),
methods: {
viewLogs () {
shell.openItem(this.logPath)
}
},
mounted () {
this.logPath = remote.app.getPath('home') + '/.Cosmos/main.log'
},
props: ['icon', 'title', 'body']
}
</script>

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

.ni-modal-error__wrapper
position absolute
top 0
left 0

z-index z(modalError)
background app-bg
width 100vw
height 100vh
max-width 100%

display flex
align-items center
justify-content center

.ni-modal-error
padding 1.5rem
max-width 40rem

.ni-modal-error__icon
position fixed
top 0
left 0
z-index z(below)
i.material-icons
font-size 25vw + 25vh
line-height 1
color bc-dim

.ni-modal-error__title
font-size h1
font-weight 500
line-height 1
margin-bottom 1.5rem

.ni-modal-error__body
font-size lg
color dim
margin-bottom 3rem

.ni-modal-error__footer
.ni-btn
width 100%
margin-right 1.5rem
margin-bottom 1rem
max-width 14rem
&:last-child
margin-bottom 0

@media screen and (min-width: 768px)
.ni-modal-error__icon i.material-icons
font-size 20vw + 20vh

.ni-modal-error__body
margin-bottom 4.5rem

.ni-modal-error__footer .ni-btn
margin-bottom 0
</style>
1 change: 1 addition & 0 deletions app/src/renderer/styles/variables.styl
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ h6 = 0.75rem
// z-index

z-layers = {
modalError: 1002,
modalHelp: 1001,
modal: 1000,
appHeader: 100,
Expand Down
6 changes: 6 additions & 0 deletions app/src/renderer/vuex/modules/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ export default ({ commit }) => {
// TODO: change to atom
bondingDenom: 'fermion',
modals: {
error: {
active: false
},
help: {
active: false
},
Expand All @@ -25,6 +28,9 @@ export default ({ commit }) => {
setDevMode (state, value) {
state.devMode = value
},
setModalError (state, value) {
state.modals.error.active = value
},
setModalHelp (state, value) {
state.modals.help.active = value
},
Expand Down
80 changes: 80 additions & 0 deletions test/unit/specs/components/common/NiModalError.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { mount } from '@vue/test-utils'
import htmlBeautify from 'html-beautify'
import NiModalError from 'common/NiModalError'

jest.mock('electron', () => ({
remote: {
app: {
getPath: () => { return '$HOME' }
}
}
}))

describe('NiModalError', () => {
let wrapper

beforeEach(() => {
wrapper = mount(NiModalError)
})

it('has the expected html structure', () => {
expect(htmlBeautify(wrapper.html())).toMatchSnapshot()
})

it('has an icon', () => {
expect(wrapper.find('.ni-modal-error__icon i.material-icons').text().trim())
.toBe('error_outline')
})

it('shows an icon if specified', () => {
wrapper = mount(NiModalError, {
propsData: {
icon: 'icon-x'
}
})
expect(wrapper.find('.ni-modal-error__icon i.material-icons').text().trim())
.toBe('icon-x')
})

it('has a title', () => {
expect(wrapper.find('.ni-modal-error__title').text().trim())
.toBe('Voyager ran into an error')
})

it('shows a title if specified', () => {
wrapper = mount(NiModalError, {
propsData: {
title: 'title-x'
}
})
expect(wrapper.find('.ni-modal-error__title').text().trim())
.toBe('title-x')
})

it('has a body', () => {
expect(wrapper.find('.ni-modal-error__body').text().trim())
.toContain('Voyager has encountered a critical error that blocks the app from running. Please create an issue and include a copy of the app logs.')
})

it('shows a body if specified', () => {
wrapper = mount(NiModalError, {
propsData: {
body: 'body-x'
}
})
expect(wrapper.find('.ni-modal-error__body').text().trim())
.toBe('body-x')
})

it('knows the path to the app log', () => {
expect(wrapper.vm.logPath).toBe('$HOME/.Cosmos/main.log')
})

it('has a button to create an issue', () => {
wrapper.find('#ni-modal-error__btn-issue').trigger('click')
})

it('has a button to view the app logs', () => {
wrapper.find('#ni-modal-error__btn-logs').trigger('click')
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`NiModalError has the expected html structure 1`] = `
"<div class=\\"ni-modal-error__wrapper\\">
<div class=\\"ni-modal-error\\">
<div class=\\"ni-modal-error__icon\\">
<i class=\\"material-icons\\">error_outline</i>
</div>
<div class=\\"ni-modal-error__title\\">
Voyager ran into an error
</div>
<div class=\\"ni-modal-error__body\\">
Voyager has encountered a critical error that blocks the app from running. Please create an issue and include a copy of the app logs.
</div>
<div class=\\"ni-modal-error__footer\\">
<a class=\\"ni-btn\\" id=\\"ni-modal-error__btn-issue\\" href=\\"https://github.com/cosmos/voyager/issues\\"><span class=\\"ni-btn__container ni-btn--size-lg ni-btn--primary\\"><i aria-hidden=\\"true\\" class=\\"ni-btn__icon material-icons\\">bug_report</i><span class=\\"ni-btn__value\\">Create an issue</span></span></a><button class=\\"ni-btn\\" id=\\"ni-modal-error__btn-logs\\"><span class=\\"ni-btn__container ni-btn--size-lg\\"><i aria-hidden=\\"true\\" class=\\"ni-btn__icon material-icons\\">info_outline</i>
<!---->
<span class=\\"ni-btn__value\\">View app logs</span></span></button>
</div>
</div>
</div>"
`;