Skip to content

Commit

Permalink
[SDPA-3209] Added error capture and UI handling (#560)
Browse files Browse the repository at this point in the history
* [SDPA-3209] Added error capture and UI handling

* Fixed lagoon condition and updated tests
  • Loading branch information
tim-yao authored Nov 1, 2019
1 parent 1b34b83 commit 039b446
Show file tree
Hide file tree
Showing 21 changed files with 493 additions and 55 deletions.
1 change: 1 addition & 0 deletions packages/components/Atoms/Global/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ This is a globally available options object to allow passing options between rip

```js
nuxt: false, // enable if using in SSR environment eg: nuxt
isDev: false, // set to true to enable dev mode, used to show Ripple component errors if have.
hostname: 'localhost', // set hostname for rpl-link etc
origin: '', // URL with protocol://host(:port) e.g. http://localhost:3000
quickexit: false, // enable quick exit feature
Expand Down
34 changes: 34 additions & 0 deletions packages/components/Atoms/Global/components/DevError.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<template>
<ol class="rpl-dev-error" v-if="rplOptions.isDev">
<li v-for="(error, index) in errors" :key="index" >
{{ error }}
</li>
</ol>
</template>

<script>
export default {
name: 'RplDevError',
props: {
errors: {
type: Array,
default: function () {
return []
}
}
}
}
</script>

<style lang="scss">
@import "~@dpc-sdp/ripple-global/scss/settings";
$rpl-dev-error-bg-color: $rpl-danger-bg-color !default;
$rpl-dev-error-text-color: $rpl-danger-color !default;
.rpl-dev-error {
background-color: $rpl-dev-error-bg-color;
color: $rpl-dev-error-text-color;
padding: $rpl-space-4 $rpl-space-4 * 2;
}
</style>
52 changes: 52 additions & 0 deletions packages/components/Atoms/Global/components/dev-error.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Story, Preview, Meta } from '@storybook/addon-docs/blocks';
import RplDevError from './DevError.vue'

<Meta title="Atoms/Global/Dev error"/>

# Docs for dev error

This is a component not for end users. It shows errors to devs or testers in Ripple dev mode only.

It will render a error message if the `isDev` in `rplOptions` is set to `true`.
For more about `rplOptions` and `isDev`, check out [@dpc-sdp/ripple-global Docs](https://github.com/dpc-sdp/ripple/tree/develop/packages/components/Atoms/Global#rploptions).

<Preview>
<Story name="Dev error in dev mode">
{{
components: { RplDevError },
template: '<rpl-dev-error :errors="errors" />',
data () {
return {
errors: ['Something wrong', 'Another error']
}
},
created () {
// You shouldn't set `isDev` in created and destoryed as here.
// This is just for demo purpose.
// You should set it in Ripple global plugins.
this.rplOptions.isDev = true
},
destroyed () {
// This is just for demo purpose.
// You should set it in Ripple global plugins.
this.rplOptions.isDev = false
}
}}
</Story>
</Preview>

It will not be rendered if `rplOptions.isDev` is set to `false`( by default).

<Preview>
<Story name="Dev error in none dev mode">
{{
components: { RplDevError },
template: '<rpl-dev-error :errors="errors" />',
data () {
return {
errors: ['Something wrong', 'Another error']
}
}
}}
</Story>
</Preview>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

import RplDivider from './Divider.vue'

export default { title: 'Atoms | Global' }

export const divider = () => ({
components: { RplDivider },
template: '<rpl-divider />'
})
4 changes: 3 additions & 1 deletion packages/components/Atoms/Global/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import RplDivider from './components/Divider.vue'
import RplDevError from './components/DevError.vue'

const RplGlobal = {
// Provide plugin for Vue to inject options.
install (Vue, options) {
const rplOptions = {
nuxt: false,
isDev: false, // Set to true to display error when error captured.
hostname: 'localhost',
origin: '', // URL with protocol://host(:port) e.g. http://localhost:3000
quickexit: false,
Expand All @@ -27,4 +29,4 @@ const RplGlobal = {

export default RplGlobal

export { RplDivider }
export { RplDivider, RplDevError }
70 changes: 70 additions & 0 deletions packages/components/Atoms/Global/mixins/catch-child-error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/**
* A Vue mixin to capture child component's error.
*
* Useful to e.g. grid col component want to hide itself if the child component has a error.
*
* Use within a component:
*
* import catchChildError from '@dpc-sdp/ripple-global/mixins/catch-child-error'
*
* export default {
* name: 'my-component',
* mixins: [catchChildError],
* ...
*
* Then you can capture child errors, by set `catchChildError` Boolean prop.
* If you didn't set `catchChildError`, it won't catch error by default. The error will go to next parent.
*
* <my-component catchChildError>
* <child-component></child-component>
* </my-component>
*
* Inside component template you can display some error:
*
* <div v-if="gotChildError">
* We got a problem!
* </div>
*
* You can use "RplDevError" component display the error, which will be render in dev mode only.
*
* <rpl-dev-error v-if="gotChildError" :errors="childErrors" />
*
* This mixin also provide a error class, add it like below.
* If there is no error captured, no class will be added, otherwise it will add "rpl-child-component-error".
* You can then apply your own style when error captured.
*
* <div class="my-component" :class="childErrorClass">
*/

const catchChildError = {
data: function () {
return {
gotChildError: false,
childErrorClass: '',
childErrors: []
}
},
props: {
catchChildError: {
type: Boolean,
default: false
}
},
methods: {
interceptError (error) {
if (this.catchChildError) {
this.gotChildError = true
this.childErrors.push(error)
this.childErrorClass = 'rpl-child-component-error'
return false
} else {
return true
}
}
},
errorCaptured (error) {
return this.interceptError(error)
}
}

export default catchChildError
11 changes: 8 additions & 3 deletions packages/components/Atoms/Global/scss/settings/_color.scss
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@ $rpl-colors: (
'black': #000
) !default;

$rpl-success-bg-color: rgba(rpl-color('success'), .07);
$rpl-warning-bg-color: rgba(rpl-color('warning'), .07);
$rpl-danger-bg-color: rgba(rpl-color('danger'), .07);
$rpl-success-bg-color: rgba(rpl-color('success'), .07) !default;
$rpl-warning-bg-color: rgba(rpl-color('warning'), .07) !default;
$rpl-danger-bg-color: rgba(rpl-color('danger'), .07) !default;
$rpl-success-color: rpl-color('success') !default;
$rpl-warning-color: rpl-color('warning') !default;
$rpl-danger-color: rpl-color('danger') !default;

$rpl-child-component-error-bg-color: $rpl-warning-bg-color !default;

$rpl-gradients: (
'primary_gradient': linear-gradient(90deg, rpl-color('primary') 0%, rpl-color('secondary') 100%),
Expand Down
13 changes: 0 additions & 13 deletions packages/components/Atoms/Global/stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import SColors from './../../../../src/storybook-components/Colors.vue'
import SFonts from './../../../../src/storybook-components/Fonts.vue'
import STypography from './../../../../src/storybook-components/Typography.vue'
import SBreakpoints from './../../../../src/storybook-components/Breakpoints.vue'
// import RplDivider from './components/Divider.vue'

storiesOf('Atoms/Global', module).add('Colors', () => ({
components: { SColors },
Expand Down Expand Up @@ -112,15 +111,3 @@ storiesOf('Atoms/Global', module)
}
}
}))

// TODO: For some reason this throws an error when enabled, need to investigate why
// storiesOf('Atoms/Global', module)
// .addParameters({
// readme: {
// sidebar: readme
// }
// })
// .add('Divider', ({
// components: { RplDivider },
// template: '<rpl-divider />'
// }))
33 changes: 31 additions & 2 deletions packages/components/Atoms/Grid/Col.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,28 @@
<template>
<div :class="colClass">
<div :class="[colClass, childErrorClass]" >
<slot></slot>
<rpl-dev-error v-if="gotChildError" :errors="childErrors" />
</div>
</template>

<script>
import catchChildError from '@dpc-sdp/ripple-global/mixins/catch-child-error'
import { RplDevError } from '@dpc-sdp/ripple-global'
export default {
props: {
'cols': String,
'cols': {
type: String,
default: 'full'
},
'colsBp': Object,
'pull': Object,
'push': Object
},
components: {
RplDevError
},
mixins: [catchChildError],
computed: {
colClass: function () {
let colClass = 'rpl-col'
Expand All @@ -30,3 +41,21 @@ export default {
}
}
</script>

<style lang="scss">
// Make the col invisibale if the child component throw a error.
.rpl-col {
&.rpl-child-component-error {
display: none;
}
}
// Show col has error child in Ripple dev mode
.ripple-dev-mode {
.rpl-col {
&.rpl-child-component-error {
display: block;
}
}
}
</style>
51 changes: 51 additions & 0 deletions packages/components/Atoms/Grid/__tests__/col.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { createLocalVue, mount } from '@vue/test-utils'
import RplCol from './../Col.vue'
import RplGlobal from '@dpc-sdp/ripple-global'

const localVue = createLocalVue()

localVue.use(RplGlobal, { isDev: true })

const colNotCatchError = mount(RplCol)

const colCatchErrorDev = mount(RplCol, {
propsData: {
catchChildError: true
},
localVue
})

const colCatchErrorNotDev = mount(RplCol, {
propsData: {
catchChildError: true
}
})

// Give an error for testing.
// Ideally will be mount an error child component but Vue test utils didn't support mount in slot.
const error = new Error('I have an error.')
colNotCatchError.vm.interceptError(error)
colCatchErrorDev.vm.interceptError(error)
colCatchErrorNotDev.vm.interceptError(error)

describe('RplCol', () => {
it('not render the child error class when catch child error is not enabled', () => {
expect(colNotCatchError.classes()).not.toContain('rpl-child-component-error')
})

it('render the child error class when caught an error in dev mode', () => {
expect(colCatchErrorDev.classes()).toContain('rpl-child-component-error')
})

it('render the child error messages when caught an error in dev mode', () => {
expect(colCatchErrorDev.contains('.rpl-dev-error')).toBe(true)
})

it('render the child error class when caught an error but is not in dev mode', () => {
expect(colCatchErrorNotDev.classes()).toContain('rpl-child-component-error')
})

it('not render the child error messages when caught an error but is not in dev mode', () => {
expect(colCatchErrorNotDev.contains('.rpl-dev-error')).toBe(false)
})
})
19 changes: 14 additions & 5 deletions packages/components/Molecules/Card/CardBox.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<template>
<div class="rpl-card-box">
<div class="rpl-card-box" :class="childErrorClass">
<rpl-dev-error v-if="gotChildError" :errors="childErrors" />
<div class="rpl-card-box__items">
<div class="rpl-card-box__item" v-for="(item, index) in cards" :key="index">
<component :is="item.name" v-bind="item.data"></component>
Expand All @@ -9,16 +10,24 @@
</template>

<script>
import catchChildError from '@dpc-sdp/ripple-global/mixins/catch-child-error'
import { RplDevError } from '@dpc-sdp/ripple-global'
import RplCardEmergencyContact from './CardEmergencyContact.vue'
export default {
name: 'RplCardBox',
components: {
RplCardEmergencyContact,
RplDevError
},
props: {
cards: Array
cards: Array,
catchChildError: {
type: Boolean,
default: true
}
},
components: {
RplCardEmergencyContact
}
mixins: [catchChildError]
}
</script>

Expand Down
Loading

0 comments on commit 039b446

Please sign in to comment.