diff --git a/frontend/package.json b/frontend/package.json
index d6aee66ff8..53ba67e157 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -63,7 +63,7 @@
     "eslint-config-finn-prettier": "^3.0.2",
     "eslint-config-finn-react": "^2.0.2",
     "eslint-plugin-react": "^7.11.1",
-    "fetch-mock": "^9.4.0",
+    "fetch-mock": "^9.11.0",
     "identity-obj-proxy": "^3.0.0",
     "immutable": "^3.8.1",
     "jest": "^24.9.0",
@@ -112,6 +112,7 @@
     ],
     "snapshotSerializers": [
       "enzyme-to-json/serializer"
-    ]
+    ],
+    "testPathIgnorePatterns": ["/src/store/addons/__tests__/data.js"]
   }
 }
diff --git a/frontend/public/jira.svg b/frontend/public/jira.svg
new file mode 100644
index 0000000000..4ace5cc84a
--- /dev/null
+++ b/frontend/public/jira.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/public/slack.svg b/frontend/public/slack.svg
new file mode 100644
index 0000000000..69a4eb6a21
--- /dev/null
+++ b/frontend/public/slack.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/public/webhooks.svg b/frontend/public/webhooks.svg
new file mode 100644
index 0000000000..ec5cddf369
--- /dev/null
+++ b/frontend/public/webhooks.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/component/addons/form-addon-component.jsx b/frontend/src/component/addons/form-addon-component.jsx
new file mode 100644
index 0000000000..4570160cdb
--- /dev/null
+++ b/frontend/src/component/addons/form-addon-component.jsx
@@ -0,0 +1,177 @@
+import React, { useState, useEffect } from 'react';
+import PropTypes from 'prop-types';
+import { Textfield, Card, CardTitle, CardText, CardActions, Switch, Grid, Cell } from 'react-mdl';
+
+import { FormButtons, styles as commonStyles } from '../common';
+import { trim } from '../common/util';
+import AddonParameters from './form-addon-parameters';
+import AddonEvents from './form-addon-events';
+import { cloneDeep } from 'lodash';
+
+const AddonFormComponent = ({ editMode, provider, addon, fetch, cancel, submit }) => {
+    const [config, setConfig] = useState(addon);
+    const [errors, setErrors] = useState({
+        parameters: {},
+    });
+    const submitText = editMode ? 'Update' : 'Create';
+
+    useEffect(() => {
+        if (!provider) {
+            fetch();
+        }
+    }, []); // empty array => fetch only first time
+
+    useEffect(() => {
+        setConfig({ ...addon });
+    }, [addon.id]);
+
+    useEffect(() => {
+        if (provider && !config.provider) {
+            setConfig({ ...addon, provider: provider.name });
+        }
+    }, [provider]);
+
+    const setFieldValue = field => evt => {
+        evt.preventDefault();
+        const newConfig = { ...config };
+        newConfig[field] = evt.target.value;
+        setConfig(newConfig);
+    };
+
+    const onEnabled = evt => {
+        evt.preventDefault();
+        const enabled = !config.enabled;
+        setConfig({ ...config, enabled });
+    };
+
+    const setParameterValue = param => evt => {
+        evt.preventDefault();
+        const newConfig = { ...config };
+        newConfig.parameters[param] = evt.target.value;
+        setConfig(newConfig);
+    };
+
+    const setEventValue = name => evt => {
+        const newConfig = { ...config };
+        if (evt.target.checked) {
+            newConfig.events.push(name);
+        } else {
+            newConfig.events = newConfig.events.filter(e => e !== name);
+        }
+        setConfig(newConfig);
+        setErrors({ ...errors, events: undefined });
+    };
+
+    const onSubmit = async evt => {
+        evt.preventDefault();
+        if (!provider) return;
+
+        const updatedErrors = cloneDeep(errors);
+        updatedErrors.containsErrors = false;
+
+        // Validations
+        if (config.events.length === 0) {
+            updatedErrors.events = 'You must listen to at least one event';
+            updatedErrors.containsErrors = true;
+        }
+
+        provider.parameters.forEach(p => {
+            const value = trim(config.parameters[p.name]);
+            if (p.required && !value) {
+                updatedErrors.parameters[p.name] = 'This field is required';
+                updatedErrors.containsErrors = true;
+            }
+        });
+
+        if (updatedErrors.containsErrors) {
+            setErrors(updatedErrors);
+            return;
+        }
+
+        try {
+            await submit(config);
+        } catch (e) {
+            setErrors({ parameters: {}, general: e.message });
+        }
+    };
+
+    const { name, description, documentationUrl = 'https://unleash.github.io/docs/addons' } = provider ? provider : {};
+
+    return (
+        
+            
+                Configure {name}
+            
+            
+                {description} 
+                
+                    Read more
+                
+                {errors.general}
+            
+            
+        
+    );
+};
+
+AddonFormComponent.propTypes = {
+    provider: PropTypes.object,
+    addon: PropTypes.object.isRequired,
+    fetch: PropTypes.func.isRequired,
+    submit: PropTypes.func.isRequired,
+    cancel: PropTypes.func.isRequired,
+    editMode: PropTypes.bool.isRequired,
+};
+
+export default AddonFormComponent;
diff --git a/frontend/src/component/addons/form-addon-container.js b/frontend/src/component/addons/form-addon-container.js
new file mode 100644
index 0000000000..01f2e456d5
--- /dev/null
+++ b/frontend/src/component/addons/form-addon-container.js
@@ -0,0 +1,55 @@
+import { connect } from 'react-redux';
+import FormComponent from './form-addon-component';
+import { updateAddon, createAddon, fetchAddons } from '../../store/addons/actions';
+import { cloneDeep } from 'lodash';
+
+// Required for to fill the inital form.
+const DEFAULT_DATA = {
+    provider: '',
+    description: '',
+    enabled: true,
+    parameters: {},
+    events: [],
+};
+
+const mapStateToProps = (state, params) => {
+    const defaultAddon = cloneDeep(DEFAULT_DATA);
+    const editMode = !!params.addonId;
+    const addons = state.addons.get('addons').toJS();
+    const providers = state.addons.get('providers').toJS();
+
+    let addon;
+    let provider;
+
+    if (editMode) {
+        addon = addons.find(addon => addon.id === +params.addonId) || defaultAddon;
+        provider = addon ? providers.find(provider => provider.name === addon.provider) : undefined;
+    } else {
+        provider = providers.find(provider => provider.name === params.provider);
+        addon = { ...defaultAddon, provider: provider ? provider.name : '' };
+    }
+
+    return {
+        provider,
+        addon,
+        editMode,
+    };
+};
+
+const mapDispatchToProps = (dispatch, ownProps) => {
+    const { addonId, history } = ownProps;
+    const submit = addonId ? updateAddon : createAddon;
+
+    return {
+        submit: async addonConfig => {
+            await submit(addonConfig)(dispatch);
+            history.push('/addons');
+        },
+        fetch: () => fetchAddons()(dispatch),
+        cancel: () => history.push('/addons'),
+    };
+};
+
+const FormAddContainer = connect(mapStateToProps, mapDispatchToProps)(FormComponent);
+
+export default FormAddContainer;
diff --git a/frontend/src/component/addons/form-addon-events.jsx b/frontend/src/component/addons/form-addon-events.jsx
new file mode 100644
index 0000000000..f4790432d1
--- /dev/null
+++ b/frontend/src/component/addons/form-addon-events.jsx
@@ -0,0 +1,32 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Checkbox, Grid, Cell } from 'react-mdl';
+
+import { styles as commonStyles } from '../common';
+
+const AddonEvents = ({ provider, checkedEvents, setEventValue, error }) => {
+    if (!provider) return null;
+
+    return (
+        
+            Events
+            {error}
+            
+                {provider.events.map(e => (
+                    +                        
++                ))}
+            
+        
+    );
+};
+
+AddonEvents.propTypes = {
+    provider: PropTypes.object,
+    checkedEvents: PropTypes.array.isRequired,
+    setEventValue: PropTypes.func.isRequired,
+    error: PropTypes.string,
+};
+
+export default AddonEvents;
diff --git a/frontend/src/component/addons/form-addon-parameters.jsx b/frontend/src/component/addons/form-addon-parameters.jsx
new file mode 100644
index 0000000000..8f6065126c
--- /dev/null
+++ b/frontend/src/component/addons/form-addon-parameters.jsx
@@ -0,0 +1,82 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Textfield } from 'react-mdl';
+
+const MASKED_VALUE = '*****';
+
+const resolveType = ({ type = 'text', sensitive = false }, value) => {
+    if (sensitive && value === MASKED_VALUE) {
+        return 'text';
+    }
+    if (type === 'textfield') {
+        return 'text';
+    }
+    return type;
+};
+
+const AddonParameter = ({ definition, config, errors, setParameterValue }) => {
+    const value = config.parameters[definition.name] || '';
+    const type = resolveType(definition, value);
+    const error = errors.parameters[definition.name];
+    const descStyle = { fontSize: '0.8em', color: 'gray', marginTop: error ? '2px' : '-15px' };
+
+    return (
+ | 
+            
+            
{definition.description}
+        
Parameters
+            {editMode ? (
+                
+                    Sensitive parameters will be masked with value "*****". If you don't change the value they
+                    will not be updated when saving.
+                
+            ) : null}
+            {provider.parameters.map(p => (
+                
+            ))}
+        
+    );
+};
+
+AddonParameters.propTypes = {
+    provider: PropTypes.object,
+    config: PropTypes.object.isRequired,
+    errors: PropTypes.object.isRequired,
+    setParameterValue: PropTypes.func.isRequired,
+    editMode: PropTypes.bool.optional,
+};
+
+export default AddonParameters;
diff --git a/frontend/src/component/addons/list-component.jsx b/frontend/src/component/addons/list-component.jsx
new file mode 100644
index 0000000000..eb7c23c79c
--- /dev/null
+++ b/frontend/src/component/addons/list-component.jsx
@@ -0,0 +1,117 @@
+import React, { useEffect } from 'react';
+import PropTypes from 'prop-types';
+import { Link } from 'react-router-dom';
+
+import { List, ListItem, ListItemAction, IconButton, Card, Button } from 'react-mdl';
+import { HeaderTitle, styles as commonStyles } from '../common';
+import { CREATE_ADDON, DELETE_ADDON, UPDATE_ADDON } from '../../permissions';
+
+const style = { width: '40px', height: '40px', marginRight: '16px', float: 'left' };
+
+const getIcon = name => {
+    switch (name) {
+        case 'slack':
+            return  ;
+        case 'jira-comment':
+            return
;
+        case 'jira-comment':
+            return  ;
+        case 'webhook':
+            return
;
+        case 'webhook':
+            return  ;
+        default:
+            return device_hub;
+    }
+};
+
+const AddonListComponent = ({ addons, providers, fetchAddons, removeAddon, toggleAddon, history, hasPermission }) => {
+    useEffect(() => {
+        if (addons.length === 0) {
+            fetchAddons();
+        }
+    }, []);
+
+    const onRemoveAddon = addon => () => removeAddon(addon);
+
+    return (
+
;
+        default:
+            return device_hub;
+    }
+};
+
+const AddonListComponent = ({ addons, providers, fetchAddons, removeAddon, toggleAddon, history, hasPermission }) => {
+    useEffect(() => {
+        if (addons.length === 0) {
+            fetchAddons();
+        }
+    }, []);
+
+    const onRemoveAddon = addon => () => removeAddon(addon);
+
+    return (
+        
+            {addons.length > 0 ? (
+                
+                    
+                    
+                        {addons.map(addon => (
+                            
+                                
+                                    {getIcon(addon.provider)}
+                                    
+                                        {hasPermission(UPDATE_ADDON) ? (
+                                            
+                                                {addon.provider}
+                                            
+                                        ) : (
+                                            {addon.provider}
+                                        )}
+                                        {addon.enabled ? null :  (Disabled)}
+                                    
+                                    {addon.description}
+                                
+                                
+                                    {hasPermission(UPDATE_ADDON) ? (
+                                         toggleAddon(addon)}
+                                        />
+                                    ) : null}
+                                    {hasPermission(DELETE_ADDON) ? (
+                                        
+                                    ) : null}
+                                
+                            
+                        ))}
+                    
+                
+            ) : null}
+
+            
+                
+                
+                    {providers.map((provider, i) => (
+                        
+                            
+                                {getIcon(provider.name)}
+                                
+                                    {provider.displayName} 
+                                
+                                {provider.description}
+                            
+                            
+                                {hasPermission(CREATE_ADDON) ? (
+                                    
+                                ) : (
+                                    ''
+                                )}
+                            
+                        
+                    ))}
+                
+            
+
+    );
+};
+AddonListComponent.propTypes = {
+    addons: PropTypes.array.isRequired,
+    providers: PropTypes.array.isRequired,
+    fetchAddons: PropTypes.func.isRequired,
+    removeAddon: PropTypes.func.isRequired,
+    toggleAddon: PropTypes.func.isRequired,
+    history: PropTypes.object.isRequired,
+    hasPermission: PropTypes.func.isRequired,
+};
+
+export default AddonListComponent;
diff --git a/frontend/src/component/addons/list-container.jsx b/frontend/src/component/addons/list-container.jsx
new file mode 100644
index 0000000000..ed83e458e6
--- /dev/null
+++ b/frontend/src/component/addons/list-container.jsx
@@ -0,0 +1,32 @@
+import { connect } from 'react-redux';
+import AddonsListComponent from './list-component.jsx';
+import { fetchAddons, removeAddon, updateAddon } from '../../store/addons/actions';
+import { hasPermission } from '../../permissions';
+
+const mapStateToProps = state => {
+    const list = state.addons.toJS();
+
+    return {
+        addons: list.addons,
+        providers: list.providers,
+        hasPermission: hasPermission.bind(null, state.user.get('profile')),
+    };
+};
+
+const mapDispatchToProps = dispatch => ({
+    removeAddon: addon => {
+        // eslint-disable-next-line no-alert
+        if (window.confirm('Are you sure you want to remove this addon?')) {
+            removeAddon(addon)(dispatch);
+        }
+    },
+    fetchAddons: () => fetchAddons()(dispatch),
+    toggleAddon: addon => {
+        const updatedAddon = { ...addon, enabled: !addon.enabled };
+        return updateAddon(updatedAddon)(dispatch);
+    },
+});
+
+const AddonsListContainer = connect(mapStateToProps, mapDispatchToProps)(AddonsListComponent);
+
+export default AddonsListContainer;
diff --git a/frontend/src/component/common/common.module.scss b/frontend/src/component/common/common.module.scss
index 6b55a7665d..36b0466ca5 100644
--- a/frontend/src/component/common/common.module.scss
+++ b/frontend/src/component/common/common.module.scss
@@ -98,4 +98,8 @@
     top: 56px;
     right: 24px;
     z-index: 2;
+}
+
+.error {
+    color: #d50000;
 }
\ No newline at end of file
diff --git a/frontend/src/component/feature/feature-tag-component.jsx b/frontend/src/component/feature/feature-tag-component.jsx
index 0def7c591d..c8308d597e 100644
--- a/frontend/src/component/feature/feature-tag-component.jsx
+++ b/frontend/src/component/feature/feature-tag-component.jsx
@@ -11,8 +11,19 @@ function FeatureTagComponent({ tags, tagTypes, featureToggleName, untagFeature }
 
     const tagIcon = typeName => {
         let tagType = tagTypes.find(type => type.name === typeName);
+        const style = { width: '20px', height: '20px', margin: '0' };
+
         if (tagType && tagType.icon) {
-            return ;
+            switch (tagType.name) {
+                case 'slack':
+                    return  ;
+                case 'jira':
+                    return
;
+                case 'jira':
+                    return  ;
+                case 'webhook':
+                    return
;
+                case 'webhook':
+                    return  ;
+                default:
+                    return ;
+            }
         } else {
             return {typeName[0].toUpperCase()};
         }
@@ -21,12 +32,12 @@ function FeatureTagComponent({ tags, tagTypes, featureToggleName, untagFeature }
     const renderTag = t => (
          onUntagFeature(t)}
-            title={t.value}
+            title={`Type: ${t.type} \nValue: ${t.value}`}
             key={`${t.type}:${t.value}`}
             style={{ marginRight: '3px', fontSize: '0.8em' }}
         >
-            {tagIcon(t.type)}
-            {t.value}
+            {tagIcon(t.type)}
+            {t.value}
         
     );
 
diff --git a/frontend/src/component/history/history-list-component.jsx b/frontend/src/component/history/history-list-component.jsx
index 6fa784b703..629e0dce68 100644
--- a/frontend/src/component/history/history-list-component.jsx
+++ b/frontend/src/component/history/history-list-component.jsx
@@ -8,6 +8,19 @@ import { formatFullDateTimeWithLocale } from '../common/util';
 
 import styles from './history.module.scss';
 
+const getName = name => {
+    if (name) {
+        return (
+            
+                Name: 
+                {name}
+            
+        );
+    } else {
+        return null;
+    }
+};
+
 const HistoryMeta = ({ entry, timeFormatted }) => (
;
+                default:
+                    return ;
+            }
         } else {
             return {typeName[0].toUpperCase()};
         }
@@ -21,12 +32,12 @@ function FeatureTagComponent({ tags, tagTypes, featureToggleName, untagFeature }
     const renderTag = t => (
          onUntagFeature(t)}
-            title={t.value}
+            title={`Type: ${t.type} \nValue: ${t.value}`}
             key={`${t.type}:${t.value}`}
             style={{ marginRight: '3px', fontSize: '0.8em' }}
         >
-            {tagIcon(t.type)}
-            {t.value}
+            {tagIcon(t.type)}
+            {t.value}
         
     );
 
diff --git a/frontend/src/component/history/history-list-component.jsx b/frontend/src/component/history/history-list-component.jsx
index 6fa784b703..629e0dce68 100644
--- a/frontend/src/component/history/history-list-component.jsx
+++ b/frontend/src/component/history/history-list-component.jsx
@@ -8,6 +8,19 @@ import { formatFullDateTimeWithLocale } from '../common/util';
 
 import styles from './history.module.scss';
 
+const getName = name => {
+    if (name) {
+        return (
+            
+                Name: 
+                {name}
+            
+        );
+    } else {
+        return null;
+    }
+};
+
 const HistoryMeta = ({ entry, timeFormatted }) => (
     
         
@@ -17,8 +30,7 @@ const HistoryMeta = ({ entry, timeFormatted }) => (
             - {entry.createdBy}
- Type: 
- {entry.type}-
- Name: -
- {entry.data.name}+            {getName(entry.data.name)}
Change
diff --git a/frontend/src/component/menu/__tests__/__snapshots__/drawer-test.jsx.snap b/frontend/src/component/menu/__tests__/__snapshots__/drawer-test.jsx.snap
index 04da1fdcd8..d226f9dee2 100644
--- a/frontend/src/component/menu/__tests__/__snapshots__/drawer-test.jsx.snap
+++ b/frontend/src/component/menu/__tests__/__snapshots__/drawer-test.jsx.snap
@@ -106,6 +106,19 @@ exports[`should render DrawerMenu 1`] = `
        
       Tag types
     
+    
+      
+       
+      Addons
+    
     
+    
+      
+       
+      Addons
+    
     
         Tag types
       
+      
+        Addons
+      
       
         Tag types
       
+      
+        Addons
+      
        {
-    expect(routes.length).toEqual(25);
+    expect(routes.length).toEqual(28);
     expect(routes).toMatchSnapshot();
 });
 
 test('returns all baseRoutes', () => {
-    expect(baseRoutes.length).toEqual(7);
+    expect(baseRoutes.length).toEqual(8);
     expect(baseRoutes).toMatchSnapshot();
 });
 
diff --git a/frontend/src/component/menu/routes.js b/frontend/src/component/menu/routes.js
index 35330f48d2..e494ecaa0e 100644
--- a/frontend/src/component/menu/routes.js
+++ b/frontend/src/component/menu/routes.js
@@ -23,7 +23,9 @@ import CreateTagType from '../../page/tag-types/create';
 import EditTagType from '../../page/tag-types/edit';
 import ListTags from '../../page/tags';
 import CreateTag from '../../page/tags/create';
-
+import Addons from '../../page/addons';
+import AddonsCreate from '../../page/addons/create';
+import AddonsEdit from '../../page/addons/edit';
 export const routes = [
     // Features
     { path: '/features/create', parent: '/features', title: 'Create', component: CreateFeatureToggle },
@@ -70,6 +72,11 @@ export const routes = [
     { path: '/tags/create', parent: '/tags', title: 'Create', component: CreateTag },
     { path: '/tags', title: 'Tags', icon: 'label', component: ListTags, hidden: true },
 
+    // Addons
+    { path: '/addons/create/:provider', parent: '/addons', title: 'Create', component: AddonsCreate },
+    { path: '/addons/edit/:id', parent: '/addons', title: 'Edit', component: AddonsEdit },
+    { path: '/addons', title: 'Addons', icon: 'device_hub', component: Addons, hidden: false },
+
     { path: '/logout', title: 'Sign out', icon: 'exit_to_app', component: LogoutFeatures },
 ];
 
diff --git a/frontend/src/page/addons/create.js b/frontend/src/page/addons/create.js
new file mode 100644
index 0000000000..c9894d3484
--- /dev/null
+++ b/frontend/src/page/addons/create.js
@@ -0,0 +1,14 @@
+import React from 'react';
+import AddonForm from '../../component/addons/form-addon-container';
+import PropTypes from 'prop-types';
+
+const render = ({ match: { params }, history }) => (
+    
+);
+
+render.propTypes = {
+    match: PropTypes.object.isRequired,
+    history: PropTypes.object.isRequired,
+};
+
+export default render;
diff --git a/frontend/src/page/addons/edit.js b/frontend/src/page/addons/edit.js
new file mode 100644
index 0000000000..ffe64e5387
--- /dev/null
+++ b/frontend/src/page/addons/edit.js
@@ -0,0 +1,14 @@
+import React from 'react';
+import AddonForm from '../../component/addons/form-addon-container';
+import PropTypes from 'prop-types';
+
+const render = ({ match: { params }, history }) => (
+    
+);
+
+render.propTypes = {
+    match: PropTypes.object.isRequired,
+    history: PropTypes.object.isRequired,
+};
+
+export default render;
diff --git a/frontend/src/page/addons/index.js b/frontend/src/page/addons/index.js
new file mode 100644
index 0000000000..1b154129d8
--- /dev/null
+++ b/frontend/src/page/addons/index.js
@@ -0,0 +1,11 @@
+import React from 'react';
+import Addons from '../../component/addons/list-container';
+import PropTypes from 'prop-types';
+
+const render = ({ history }) => ;
+
+render.propTypes = {
+    history: PropTypes.object.isRequired,
+};
+
+export default render;
diff --git a/frontend/src/permissions.js b/frontend/src/permissions.js
index 00b5e1f5e1..ac6edb8b0a 100644
--- a/frontend/src/permissions.js
+++ b/frontend/src/permissions.js
@@ -17,6 +17,9 @@ export const DELETE_TAG_TYPE = 'DELETE_TAG_TYPE';
 export const UPDATE_TAG_TYPE = 'UPDATE_TAG_TYPE';
 export const CREATE_TAG = 'CREATE_TAG';
 export const DELETE_TAG = 'DELETE_TAG';
+export const CREATE_ADDON = 'CREATE_ADDON';
+export const UPDATE_ADDON = 'UPDATE_ADDON';
+export const DELETE_ADDON = 'DELETE_ADDON';
 
 export function hasPermission(user, permission) {
     return (
diff --git a/frontend/src/store/addons/__tests__/__snapshots__/addons-store.test.js.snap b/frontend/src/store/addons/__tests__/__snapshots__/addons-store.test.js.snap
new file mode 100644
index 0000000000..a417521d15
--- /dev/null
+++ b/frontend/src/store/addons/__tests__/__snapshots__/addons-store.test.js.snap
@@ -0,0 +1,189 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should add addon-config 1`] = `
+Object {
+  "addons": Array [
+    Object {
+      "description": null,
+      "enabled": true,
+      "events": Array [
+        "feature-updated",
+        "feature-created",
+      ],
+      "id": 1,
+      "parameters": Object {
+        "bodyTemplate": "{'name': '{{event.data.name}}' }",
+        "url": "http://localhost:4242/webhook",
+      },
+      "provider": "webhook",
+    },
+  ],
+  "providers": Array [
+    Object {
+      "displayName": "Webhook",
+      "events": Array [
+        "feature-created",
+        "feature-updated",
+        "feature-archived",
+        "feature-revived",
+      ],
+      "name": "webhook",
+      "parameters": Array [
+        Object {
+          "displayName": "Webhook URL",
+          "name": "url",
+          "type": "string",
+        },
+        Object {
+          "displayName": "Unleash Admin UI url",
+          "name": "unleashUrl",
+          "type": "text",
+        },
+        Object {
+          "description": "You may format the body using a mustache template.",
+          "displayName": "Body template",
+          "name": "bodyTemplate",
+          "type": "text",
+        },
+      ],
+    },
+  ],
+}
+`;
+
+exports[`should be default state 1`] = `
+Object {
+  "addons": Array [],
+  "providers": Array [],
+}
+`;
+
+exports[`should be merged state all 1`] = `
+Object {
+  "addons": Array [],
+  "providers": Array [
+    Object {
+      "displayName": "Webhook",
+      "events": Array [
+        "feature-created",
+        "feature-updated",
+        "feature-archived",
+        "feature-revived",
+      ],
+      "name": "webhook",
+      "parameters": Array [
+        Object {
+          "displayName": "Webhook URL",
+          "name": "url",
+          "type": "string",
+        },
+        Object {
+          "displayName": "Unleash Admin UI url",
+          "name": "unleashUrl",
+          "type": "text",
+        },
+        Object {
+          "description": "You may format the body using a mustache template.",
+          "displayName": "Body template",
+          "name": "bodyTemplate",
+          "type": "text",
+        },
+      ],
+    },
+  ],
+}
+`;
+
+exports[`should clear addon-config on logout 1`] = `
+Object {
+  "addons": Array [],
+  "providers": Array [],
+}
+`;
+
+exports[`should remove addon-config 1`] = `
+Object {
+  "addons": Array [],
+  "providers": Array [
+    Object {
+      "displayName": "Webhook",
+      "events": Array [
+        "feature-created",
+        "feature-updated",
+        "feature-archived",
+        "feature-revived",
+      ],
+      "name": "webhook",
+      "parameters": Array [
+        Object {
+          "displayName": "Webhook URL",
+          "name": "url",
+          "type": "string",
+        },
+        Object {
+          "displayName": "Unleash Admin UI url",
+          "name": "unleashUrl",
+          "type": "text",
+        },
+        Object {
+          "description": "You may format the body using a mustache template.",
+          "displayName": "Body template",
+          "name": "bodyTemplate",
+          "type": "text",
+        },
+      ],
+    },
+  ],
+}
+`;
+
+exports[`should update addon-config 1`] = `
+Object {
+  "addons": Array [
+    Object {
+      "description": "new desc",
+      "enabled": false,
+      "events": Array [
+        "feature-updated",
+        "feature-created",
+      ],
+      "id": 1,
+      "parameters": Object {
+        "bodyTemplate": "{'name': '{{event.data.name}}' }",
+        "url": "http://localhost:4242/webhook",
+      },
+      "provider": "webhook",
+    },
+  ],
+  "providers": Array [
+    Object {
+      "displayName": "Webhook",
+      "events": Array [
+        "feature-created",
+        "feature-updated",
+        "feature-archived",
+        "feature-revived",
+      ],
+      "name": "webhook",
+      "parameters": Array [
+        Object {
+          "displayName": "Webhook URL",
+          "name": "url",
+          "type": "string",
+        },
+        Object {
+          "displayName": "Unleash Admin UI url",
+          "name": "unleashUrl",
+          "type": "text",
+        },
+        Object {
+          "description": "You may format the body using a mustache template.",
+          "displayName": "Body template",
+          "name": "bodyTemplate",
+          "type": "text",
+        },
+      ],
+    },
+  ],
+}
+`;
diff --git a/frontend/src/store/addons/__tests__/addons-actions.test.js b/frontend/src/store/addons/__tests__/addons-actions.test.js
new file mode 100644
index 0000000000..024e241f7c
--- /dev/null
+++ b/frontend/src/store/addons/__tests__/addons-actions.test.js
@@ -0,0 +1,113 @@
+import configureMockStore from 'redux-mock-store';
+import thunk from 'redux-thunk';
+import fetchMock from 'fetch-mock';
+
+import {
+    RECEIVE_ADDON_CONFIG,
+    ERRPR_RECEIVE_ADDON_CONFIG,
+    REMOVE_ADDON_CONFIG,
+    UPDATE_ADDON_CONFIG,
+    ADD_ADDON_CONFIG,
+    fetchAddons,
+    removeAddon,
+    updateAddon,
+    createAddon,
+} from '../actions';
+
+const middlewares = [thunk];
+const mockStore = configureMockStore(middlewares);
+
+afterEach(() => {
+    fetchMock.restore();
+});
+
+test('creates RECEIVE_ADDON_CONFIG when fetching addons has been done', () => {
+    fetchMock.getOnce('api/admin/addons', {
+        body: { addons: { providers: [{ name: 'webhook' }] } },
+        headers: { 'content-type': 'application/json' },
+    });
+
+    const expectedActions = [{ type: RECEIVE_ADDON_CONFIG, value: { addons: { providers: [{ name: 'webhook' }] } } }];
+    const store = mockStore({ addons: [] });
+
+    return store.dispatch(fetchAddons()).then(() => {
+        // return of async actions
+        expect(store.getActions()).toEqual(expectedActions);
+    });
+});
+
+test('creates RECEIVE_ADDON_CONFIG_ when fetching addons has been done', () => {
+    fetchMock.getOnce('api/admin/addons', {
+        body: { message: 'Server error' },
+        headers: { 'content-type': 'application/json' },
+        status: 500,
+    });
+
+    const store = mockStore({ addons: [] });
+
+    return store.dispatch(fetchAddons()).catch(e => {
+        // return of async actions
+        expect(store.getActions()[0].error.type).toEqual(ERRPR_RECEIVE_ADDON_CONFIG);
+        expect(e.message).toEqual('Unexpected exception when talking to unleash-api');
+    });
+});
+
+test('creates REMOVE_ADDON_CONFIG when delete addon has been done', () => {
+    const addon = {
+        id: 1,
+        provider: 'webhook',
+    };
+
+    fetchMock.deleteOnce('api/admin/addons/1', {
+        status: 200,
+    });
+
+    const expectedActions = [{ type: REMOVE_ADDON_CONFIG, value: addon }];
+    const store = mockStore({ addons: [] });
+
+    return store.dispatch(removeAddon(addon)).then(() => {
+        // return of async actions
+        expect(store.getActions()).toEqual(expectedActions);
+    });
+});
+
+test('creates UPDATE_ADDON_CONFIG when delete addon has been done', () => {
+    const addon = {
+        id: 1,
+        provider: 'webhook',
+    };
+
+    fetchMock.putOnce('api/admin/addons/1', {
+        headers: { 'content-type': 'application/json' },
+        status: 200,
+        body: addon,
+    });
+
+    const expectedActions = [{ type: UPDATE_ADDON_CONFIG, value: addon }];
+    const store = mockStore({ addons: [] });
+
+    return store.dispatch(updateAddon(addon)).then(() => {
+        // return of async actions
+        expect(store.getActions()).toEqual(expectedActions);
+    });
+});
+
+test('creates ADD_ADDON_CONFIG when delete addon has been done', () => {
+    const addon = {
+        provider: 'webhook',
+    };
+
+    fetchMock.postOnce('api/admin/addons', {
+        headers: { 'content-type': 'application/json' },
+        status: 200,
+        body: addon,
+    });
+
+    const expectedActions = [{ type: ADD_ADDON_CONFIG, value: addon }];
+    const store = mockStore({ addons: [] });
+
+    return store.dispatch(createAddon(addon)).then(() => {
+        // return of async actions
+        expect(store.getActions()).toEqual(expectedActions);
+    });
+});
diff --git a/frontend/src/store/addons/__tests__/addons-store.test.js b/frontend/src/store/addons/__tests__/addons-store.test.js
new file mode 100644
index 0000000000..d98cb34dcb
--- /dev/null
+++ b/frontend/src/store/addons/__tests__/addons-store.test.js
@@ -0,0 +1,54 @@
+import reducer from '../index';
+import { RECEIVE_ADDON_CONFIG, ADD_ADDON_CONFIG, REMOVE_ADDON_CONFIG, UPDATE_ADDON_CONFIG } from '../actions';
+import { addonSimple, addonsWithConfig, addonConfig } from './data';
+import { USER_LOGOUT } from '../../user/actions';
+
+test('should be default state', () => {
+    const state = reducer(undefined, {});
+    expect(state.toJS()).toMatchSnapshot();
+});
+
+test('should be merged state all', () => {
+    const state = reducer(undefined, { type: RECEIVE_ADDON_CONFIG, value: addonSimple });
+    expect(state.toJS()).toMatchSnapshot();
+});
+
+test('should add addon-config', () => {
+    let state = reducer(undefined, { type: RECEIVE_ADDON_CONFIG, value: addonSimple });
+    state = reducer(state, { type: ADD_ADDON_CONFIG, value: addonConfig });
+
+    const data = state.toJS();
+    expect(data).toMatchSnapshot();
+    expect(data.addons.length).toBe(1);
+});
+
+test('should remove addon-config', () => {
+    let state = reducer(undefined, { type: RECEIVE_ADDON_CONFIG, value: addonsWithConfig });
+    state = reducer(state, { type: REMOVE_ADDON_CONFIG, value: addonConfig });
+
+    const data = state.toJS();
+    expect(data).toMatchSnapshot();
+    expect(data.addons.length).toBe(0);
+});
+
+test('should update addon-config', () => {
+    const updateAdddonConfig = { ...addonConfig, description: 'new desc', enabled: false };
+
+    let state = reducer(undefined, { type: RECEIVE_ADDON_CONFIG, value: addonsWithConfig });
+    state = reducer(state, { type: UPDATE_ADDON_CONFIG, value: updateAdddonConfig });
+
+    const data = state.toJS();
+    expect(data).toMatchSnapshot();
+    expect(data.addons.length).toBe(1);
+    expect(data.addons[0].description).toBe('new desc');
+});
+
+test('should clear addon-config on logout', () => {
+    let state = reducer(undefined, { type: RECEIVE_ADDON_CONFIG, value: addonsWithConfig });
+    state = reducer(state, { type: USER_LOGOUT });
+
+    const data = state.toJS();
+    expect(data).toMatchSnapshot();
+    expect(data.addons.length).toBe(0);
+    expect(data.providers.length).toBe(0);
+});
diff --git a/frontend/src/store/addons/__tests__/data.js b/frontend/src/store/addons/__tests__/data.js
new file mode 100644
index 0000000000..5e18859d85
--- /dev/null
+++ b/frontend/src/store/addons/__tests__/data.js
@@ -0,0 +1,69 @@
+export const addonSimple = {
+    addons: [],
+    providers: [
+        {
+            name: 'webhook',
+            displayName: 'Webhook',
+            parameters: [
+                {
+                    name: 'url',
+                    displayName: 'Webhook URL',
+                    type: 'string',
+                },
+                {
+                    name: 'unleashUrl',
+                    displayName: 'Unleash Admin UI url',
+                    type: 'text',
+                },
+                {
+                    name: 'bodyTemplate',
+                    displayName: 'Body template',
+                    description: 'You may format the body using a mustache template.',
+                    type: 'text',
+                },
+            ],
+            events: ['feature-created', 'feature-updated', 'feature-archived', 'feature-revived'],
+        },
+    ],
+};
+
+export const addonConfig = {
+    id: 1,
+    provider: 'webhook',
+    enabled: true,
+    description: null,
+    parameters: {
+        url: 'http://localhost:4242/webhook',
+        bodyTemplate: "{'name': '{{event.data.name}}' }",
+    },
+    events: ['feature-updated', 'feature-created'],
+};
+
+export const addonsWithConfig = {
+    addons: [addonConfig],
+    providers: [
+        {
+            name: 'webhook',
+            displayName: 'Webhook',
+            parameters: [
+                {
+                    name: 'url',
+                    displayName: 'Webhook URL',
+                    type: 'string',
+                },
+                {
+                    name: 'unleashUrl',
+                    displayName: 'Unleash Admin UI url',
+                    type: 'text',
+                },
+                {
+                    name: 'bodyTemplate',
+                    displayName: 'Body template',
+                    description: 'You may format the body using a mustache template.',
+                    type: 'text',
+                },
+            ],
+            events: ['feature-created', 'feature-updated', 'feature-archived', 'feature-revived'],
+        },
+    ],
+};
diff --git a/frontend/src/store/addons/actions.js b/frontend/src/store/addons/actions.js
new file mode 100644
index 0000000000..83805e5a4e
--- /dev/null
+++ b/frontend/src/store/addons/actions.js
@@ -0,0 +1,51 @@
+import api from './api';
+import { dispatchAndThrow } from '../util';
+
+export const RECEIVE_ADDON_CONFIG = 'RECEIVE_ADDON_CONFIG';
+export const ERROR_RECEIVE_ADDON_CONFIG = 'ERROR_RECEIVE_ADDON_CONFIG';
+export const REMOVE_ADDON_CONFIG = 'REMOVE_ADDON_CONFIG';
+export const ERROR_REMOVING_ADDON_CONFIG = 'ERROR_REMOVING_ADDON_CONFIG';
+export const ADD_ADDON_CONFIG = 'ADD_ADDON_CONFIG';
+export const ERROR_ADD_ADDON_CONFIG = 'ERROR_ADD_ADDON_CONFIG';
+export const UPDATE_ADDON_CONFIG = 'UPDATE_ADDON_CONFIG';
+export const ERROR_UPDATE_ADDON_CONFIG = 'ERROR_UPDATE_ADDON_CONFIG';
+
+// const receiveAddonConfig = value => ({ type: RECEIVE_ADDON_CONFIG, value });
+const addAddonConfig = value => ({ type: ADD_ADDON_CONFIG, value });
+const updateAdddonConfig = value => ({ type: UPDATE_ADDON_CONFIG, value });
+const removeAddonconfig = value => ({ type: REMOVE_ADDON_CONFIG, value });
+
+const success = (dispatch, type) => value => dispatch({ type, value });
+
+export function fetchAddons() {
+    return dispatch =>
+        api
+            .fetchAll()
+            .then(success(dispatch, RECEIVE_ADDON_CONFIG))
+            .catch(dispatchAndThrow(dispatch, ERROR_RECEIVE_ADDON_CONFIG));
+}
+
+export function removeAddon(addon) {
+    return dispatch =>
+        api
+            .remove(addon)
+            .then(() => dispatch(removeAddonconfig(addon)))
+            .catch(dispatchAndThrow(dispatch, ERROR_REMOVING_ADDON_CONFIG));
+}
+
+export function createAddon(addon) {
+    return dispatch =>
+        api
+            .create(addon)
+            .then(res => res.json())
+            .then(value => dispatch(addAddonConfig(value)))
+            .catch(dispatchAndThrow(dispatch, ERROR_ADD_ADDON_CONFIG));
+}
+
+export function updateAddon(addon) {
+    return dispatch =>
+        api
+            .update(addon)
+            .then(() => dispatch(updateAdddonConfig(addon)))
+            .catch(dispatchAndThrow(dispatch, ERROR_UPDATE_ADDON_CONFIG));
+}
diff --git a/frontend/src/store/addons/api.js b/frontend/src/store/addons/api.js
new file mode 100644
index 0000000000..455654b78f
--- /dev/null
+++ b/frontend/src/store/addons/api.js
@@ -0,0 +1,42 @@
+import { throwIfNotSuccess, headers } from '../api-helper';
+
+const URI = 'api/admin/addons';
+
+function fetchAll() {
+    return fetch(URI, { credentials: 'include' })
+        .then(throwIfNotSuccess)
+        .then(response => response.json());
+}
+
+function create(addonConfig) {
+    return fetch(URI, {
+        method: 'POST',
+        headers,
+        body: JSON.stringify(addonConfig),
+        credentials: 'include',
+    }).then(throwIfNotSuccess);
+}
+
+function update(addonConfig) {
+    return fetch(`${URI}/${addonConfig.id}`, {
+        method: 'PUT',
+        headers,
+        body: JSON.stringify(addonConfig),
+        credentials: 'include',
+    }).then(throwIfNotSuccess);
+}
+
+function remove(addonConfig) {
+    return fetch(`${URI}/${addonConfig.id}`, {
+        method: 'DELETE',
+        headers,
+        credentials: 'include',
+    }).then(throwIfNotSuccess);
+}
+
+export default {
+    fetchAll,
+    create,
+    update,
+    remove,
+};
diff --git a/frontend/src/store/addons/index.js b/frontend/src/store/addons/index.js
new file mode 100644
index 0000000000..ab31635f7e
--- /dev/null
+++ b/frontend/src/store/addons/index.js
@@ -0,0 +1,33 @@
+import { Map as $Map, List, fromJS } from 'immutable';
+import { RECEIVE_ADDON_CONFIG, ADD_ADDON_CONFIG, REMOVE_ADDON_CONFIG, UPDATE_ADDON_CONFIG } from './actions';
+import { USER_LOGOUT, USER_LOGIN } from '../user/actions';
+
+function getInitState() {
+    return new $Map({
+        providers: new List(),
+        addons: new List(),
+    });
+}
+
+const strategies = (state = getInitState(), action) => {
+    switch (action.type) {
+        case RECEIVE_ADDON_CONFIG:
+            return fromJS(action.value);
+        case ADD_ADDON_CONFIG: {
+            return state.update('addons', arr => arr.push(fromJS(action.value)));
+        }
+        case REMOVE_ADDON_CONFIG:
+            return state.update('addons', arr => arr.filter(a => a.get('id') !== action.value.id));
+        case UPDATE_ADDON_CONFIG: {
+            const index = state.get('addons').findIndex(item => item.get('id') === action.value.id);
+            return state.setIn(['addons', index], fromJS(action.value));
+        }
+        case USER_LOGOUT:
+        case USER_LOGIN:
+            return getInitState();
+        default:
+            return state;
+    }
+};
+
+export default strategies;
diff --git a/frontend/src/store/index.js b/frontend/src/store/index.js
index 9aa0b77693..492190c2b5 100644
--- a/frontend/src/store/index.js
+++ b/frontend/src/store/index.js
@@ -15,6 +15,7 @@ import applications from './application';
 import uiConfig from './ui-config';
 import context from './context';
 import projects from './project';
+import addons from './addons';
 
 const unleashStore = combineReducers({
     features,
@@ -33,6 +34,7 @@ const unleashStore = combineReducers({
     uiConfig,
     context,
     projects,
+    addons,
 });
 
 export default unleashStore;
diff --git a/frontend/src/store/util.js b/frontend/src/store/util.js
index 6d727484b6..713a47ee22 100644
--- a/frontend/src/store/util.js
+++ b/frontend/src/store/util.js
@@ -17,3 +17,5 @@ export function dispatchAndThrow(dispatch, type) {
         throw error;
     };
 }
+
+export const success = (dispatch, type, val) => value => dispatch({ type, value: val ? val : value });
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index 526c43d1bb..9c6e8989ff 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -9,6 +9,13 @@
   dependencies:
     "@babel/highlight" "^7.8.3"
 
+"@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.11":
+  version "7.12.11"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f"
+  integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==
+  dependencies:
+    "@babel/highlight" "^7.10.4"
+
 "@babel/compat-data@^7.8.6", "@babel/compat-data@^7.9.0":
   version "7.9.0"
   resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.9.0.tgz#04815556fc90b0c174abd2c0c1bb966faa036a6c"
@@ -18,6 +25,27 @@
     invariant "^2.2.4"
     semver "^5.5.0"
 
+"@babel/core@^7.0.0":
+  version "7.12.10"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.10.tgz#b79a2e1b9f70ed3d84bbfb6d8c4ef825f606bccd"
+  integrity sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w==
+  dependencies:
+    "@babel/code-frame" "^7.10.4"
+    "@babel/generator" "^7.12.10"
+    "@babel/helper-module-transforms" "^7.12.1"
+    "@babel/helpers" "^7.12.5"
+    "@babel/parser" "^7.12.10"
+    "@babel/template" "^7.12.7"
+    "@babel/traverse" "^7.12.10"
+    "@babel/types" "^7.12.10"
+    convert-source-map "^1.7.0"
+    debug "^4.1.0"
+    gensync "^1.0.0-beta.1"
+    json5 "^2.1.2"
+    lodash "^4.17.19"
+    semver "^5.4.1"
+    source-map "^0.5.0"
+
 "@babel/core@^7.1.0", "@babel/core@^7.7.5", "@babel/core@^7.9.0":
   version "7.9.0"
   resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.0.tgz#ac977b538b77e132ff706f3b8a4dbad09c03c56e"
@@ -40,6 +68,15 @@
     semver "^5.4.1"
     source-map "^0.5.0"
 
+"@babel/generator@^7.12.10", "@babel/generator@^7.12.11":
+  version "7.12.11"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.11.tgz#98a7df7b8c358c9a37ab07a24056853016aba3af"
+  integrity sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==
+  dependencies:
+    "@babel/types" "^7.12.11"
+    jsesc "^2.5.1"
+    source-map "^0.5.0"
+
 "@babel/generator@^7.4.0", "@babel/generator@^7.9.0", "@babel/generator@^7.9.5":
   version "7.9.5"
   resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.5.tgz#27f0917741acc41e6eaaced6d68f96c3fa9afaf9"
@@ -131,6 +168,15 @@
     "@babel/traverse" "^7.8.3"
     "@babel/types" "^7.8.3"
 
+"@babel/helper-function-name@^7.12.11":
+  version "7.12.11"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.12.11.tgz#1fd7738aee5dcf53c3ecff24f1da9c511ec47b42"
+  integrity sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==
+  dependencies:
+    "@babel/helper-get-function-arity" "^7.12.10"
+    "@babel/template" "^7.12.7"
+    "@babel/types" "^7.12.11"
+
 "@babel/helper-function-name@^7.8.3", "@babel/helper-function-name@^7.9.5":
   version "7.9.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c"
@@ -140,6 +186,13 @@
     "@babel/template" "^7.8.3"
     "@babel/types" "^7.9.5"
 
+"@babel/helper-get-function-arity@^7.12.10":
+  version "7.12.10"
+  resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz#b158817a3165b5faa2047825dfa61970ddcc16cf"
+  integrity sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==
+  dependencies:
+    "@babel/types" "^7.12.10"
+
 "@babel/helper-get-function-arity@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5"
@@ -154,6 +207,13 @@
   dependencies:
     "@babel/types" "^7.8.3"
 
+"@babel/helper-member-expression-to-functions@^7.12.7":
+  version "7.12.7"
+  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz#aa77bd0396ec8114e5e30787efa78599d874a855"
+  integrity sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==
+  dependencies:
+    "@babel/types" "^7.12.7"
+
 "@babel/helper-member-expression-to-functions@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c"
@@ -168,6 +228,28 @@
   dependencies:
     "@babel/types" "^7.8.3"
 
+"@babel/helper-module-imports@^7.12.1":
+  version "7.12.5"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz#1bfc0229f794988f76ed0a4d4e90860850b54dfb"
+  integrity sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==
+  dependencies:
+    "@babel/types" "^7.12.5"
+
+"@babel/helper-module-transforms@^7.12.1":
+  version "7.12.1"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz#7954fec71f5b32c48e4b303b437c34453fd7247c"
+  integrity sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==
+  dependencies:
+    "@babel/helper-module-imports" "^7.12.1"
+    "@babel/helper-replace-supers" "^7.12.1"
+    "@babel/helper-simple-access" "^7.12.1"
+    "@babel/helper-split-export-declaration" "^7.11.0"
+    "@babel/helper-validator-identifier" "^7.10.4"
+    "@babel/template" "^7.10.4"
+    "@babel/traverse" "^7.12.1"
+    "@babel/types" "^7.12.1"
+    lodash "^4.17.19"
+
 "@babel/helper-module-transforms@^7.9.0":
   version "7.9.0"
   resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5"
@@ -181,6 +263,13 @@
     "@babel/types" "^7.9.0"
     lodash "^4.17.13"
 
+"@babel/helper-optimise-call-expression@^7.12.10":
+  version "7.12.10"
+  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz#94ca4e306ee11a7dd6e9f42823e2ac6b49881e2d"
+  integrity sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ==
+  dependencies:
+    "@babel/types" "^7.12.10"
+
 "@babel/helper-optimise-call-expression@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9"
@@ -211,6 +300,16 @@
     "@babel/traverse" "^7.8.3"
     "@babel/types" "^7.8.3"
 
+"@babel/helper-replace-supers@^7.12.1":
+  version "7.12.11"
+  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.12.11.tgz#ea511658fc66c7908f923106dd88e08d1997d60d"
+  integrity sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==
+  dependencies:
+    "@babel/helper-member-expression-to-functions" "^7.12.7"
+    "@babel/helper-optimise-call-expression" "^7.12.10"
+    "@babel/traverse" "^7.12.10"
+    "@babel/types" "^7.12.11"
+
 "@babel/helper-replace-supers@^7.8.3", "@babel/helper-replace-supers@^7.8.6":
   version "7.8.6"
   resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz#5ada744fd5ad73203bf1d67459a27dcba67effc8"
@@ -221,6 +320,13 @@
     "@babel/traverse" "^7.8.6"
     "@babel/types" "^7.8.6"
 
+"@babel/helper-simple-access@^7.12.1":
+  version "7.12.1"
+  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz#32427e5aa61547d38eb1e6eaf5fd1426fdad9136"
+  integrity sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==
+  dependencies:
+    "@babel/types" "^7.12.1"
+
 "@babel/helper-simple-access@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae"
@@ -229,6 +335,13 @@
     "@babel/template" "^7.8.3"
     "@babel/types" "^7.8.3"
 
+"@babel/helper-split-export-declaration@^7.11.0", "@babel/helper-split-export-declaration@^7.12.11":
+  version "7.12.11"
+  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz#1b4cc424458643c47d37022223da33d76ea4603a"
+  integrity sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==
+  dependencies:
+    "@babel/types" "^7.12.11"
+
 "@babel/helper-split-export-declaration@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9"
@@ -236,6 +349,11 @@
   dependencies:
     "@babel/types" "^7.8.3"
 
+"@babel/helper-validator-identifier@^7.10.4", "@babel/helper-validator-identifier@^7.12.11":
+  version "7.12.11"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed"
+  integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==
+
 "@babel/helper-validator-identifier@^7.9.0", "@babel/helper-validator-identifier@^7.9.5":
   version "7.9.5"
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80"
@@ -251,6 +369,15 @@
     "@babel/traverse" "^7.8.3"
     "@babel/types" "^7.8.3"
 
+"@babel/helpers@^7.12.5":
+  version "7.12.5"
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.12.5.tgz#1a1ba4a768d9b58310eda516c449913fe647116e"
+  integrity sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==
+  dependencies:
+    "@babel/template" "^7.10.4"
+    "@babel/traverse" "^7.12.5"
+    "@babel/types" "^7.12.5"
+
 "@babel/helpers@^7.9.0":
   version "7.9.2"
   resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.2.tgz#b42a81a811f1e7313b88cba8adc66b3d9ae6c09f"
@@ -260,6 +387,15 @@
     "@babel/traverse" "^7.9.0"
     "@babel/types" "^7.9.0"
 
+"@babel/highlight@^7.10.4":
+  version "7.10.4"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143"
+  integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.10.4"
+    chalk "^2.0.0"
+    js-tokens "^4.0.0"
+
 "@babel/highlight@^7.8.3":
   version "7.9.0"
   resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079"
@@ -274,6 +410,11 @@
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.4.tgz#68a35e6b0319bbc014465be43828300113f2f2e8"
   integrity sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==
 
+"@babel/parser@^7.12.10", "@babel/parser@^7.12.11", "@babel/parser@^7.12.7":
+  version "7.12.11"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.11.tgz#9ce3595bcd74bc5c466905e86c535b8b25011e79"
+  integrity sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==
+
 "@babel/plugin-proposal-async-generator-functions@^7.8.3":
   version "7.8.3"
   resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f"
@@ -856,6 +997,13 @@
     core-js-pure "^3.0.0"
     regenerator-runtime "^0.13.4"
 
+"@babel/runtime@^7.0.0":
+  version "7.12.5"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e"
+  integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==
+  dependencies:
+    regenerator-runtime "^0.13.4"
+
 "@babel/runtime@^7.1.2", "@babel/runtime@^7.4.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4":
   version "7.9.2"
   resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06"
@@ -870,6 +1018,15 @@
   dependencies:
     regenerator-runtime "^0.13.4"
 
+"@babel/template@^7.10.4", "@babel/template@^7.12.7":
+  version "7.12.7"
+  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.7.tgz#c817233696018e39fbb6c491d2fb684e05ed43bc"
+  integrity sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==
+  dependencies:
+    "@babel/code-frame" "^7.10.4"
+    "@babel/parser" "^7.12.7"
+    "@babel/types" "^7.12.7"
+
 "@babel/template@^7.4.0", "@babel/template@^7.7.4", "@babel/template@^7.8.3", "@babel/template@^7.8.6":
   version "7.8.6"
   resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b"
@@ -894,6 +1051,21 @@
     globals "^11.1.0"
     lodash "^4.17.13"
 
+"@babel/traverse@^7.12.1", "@babel/traverse@^7.12.10", "@babel/traverse@^7.12.5":
+  version "7.12.12"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.12.tgz#d0cd87892704edd8da002d674bc811ce64743376"
+  integrity sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==
+  dependencies:
+    "@babel/code-frame" "^7.12.11"
+    "@babel/generator" "^7.12.11"
+    "@babel/helper-function-name" "^7.12.11"
+    "@babel/helper-split-export-declaration" "^7.12.11"
+    "@babel/parser" "^7.12.11"
+    "@babel/types" "^7.12.12"
+    debug "^4.1.0"
+    globals "^11.1.0"
+    lodash "^4.17.19"
+
 "@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0", "@babel/types@^7.9.5":
   version "7.9.5"
   resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.5.tgz#89231f82915a8a566a703b3b20133f73da6b9444"
@@ -903,6 +1075,15 @@
     lodash "^4.17.13"
     to-fast-properties "^2.0.0"
 
+"@babel/types@^7.12.1", "@babel/types@^7.12.10", "@babel/types@^7.12.11", "@babel/types@^7.12.12", "@babel/types@^7.12.5", "@babel/types@^7.12.7":
+  version "7.12.12"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.12.tgz#4608a6ec313abbd87afa55004d373ad04a96c299"
+  integrity sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.12.11"
+    lodash "^4.17.19"
+    to-fast-properties "^2.0.0"
+
 "@cnakazawa/watch@^1.0.3":
   version "1.0.4"
   resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a"
@@ -2050,14 +2231,6 @@ babel-preset-jest@^25.3.0:
     babel-plugin-jest-hoist "^25.2.6"
     babel-preset-current-node-syntax "^0.1.2"
 
-babel-runtime@^6.26.0:
-  version "6.26.0"
-  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
-  integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
-  dependencies:
-    core-js "^2.4.0"
-    regenerator-runtime "^0.11.0"
-
 balanced-match@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
@@ -2816,11 +2989,6 @@ core-js-pure@^3.0.0:
   resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813"
   integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==
 
-core-js@^2.4.0:
-  version "2.6.11"
-  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c"
-  integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==
-
 core-js@^3.0.0:
   version "3.6.5"
   resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a"
@@ -4042,12 +4210,13 @@ fb-watchman@^2.0.0:
   dependencies:
     bser "2.1.1"
 
-fetch-mock@^9.4.0:
-  version "9.4.0"
-  resolved "https://registry.yarnpkg.com/fetch-mock/-/fetch-mock-9.4.0.tgz#9be073577bcfa57af714ca91f7536aff8450ec88"
-  integrity sha512-tqnFmcjYheW5Z9zOPRVY+ZXjB/QWCYtPiOrYGEsPgKfpGHco97eaaj7Rv9MjK7PVWG4rWfv6t2IgQAzDQizBZA==
+fetch-mock@^9.11.0:
+  version "9.11.0"
+  resolved "https://registry.yarnpkg.com/fetch-mock/-/fetch-mock-9.11.0.tgz#371c6fb7d45584d2ae4a18ee6824e7ad4b637a3f"
+  integrity sha512-PG1XUv+x7iag5p/iNHD4/jdpxL9FtVSqRMUQhPab4hVDt80T1MH5ehzVrL2IdXO9Q2iBggArFvPqjUbHFuI58Q==
   dependencies:
-    babel-runtime "^6.26.0"
+    "@babel/core" "^7.0.0"
+    "@babel/runtime" "^7.0.0"
     core-js "^3.0.0"
     debug "^4.1.1"
     glob-to-regexp "^0.4.0"
@@ -8133,11 +8302,6 @@ regenerate@^1.4.0:
   resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
   integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
 
-regenerator-runtime@^0.11.0:
-  version "0.11.1"
-  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
-  integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
-
 regenerator-runtime@^0.13.4:
   version "0.13.5"
   resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697"