SIA Chrome Extension Push Notifications (#78)
* SIA Chrome Extension Push Notifications
1
.babelrc
|
@ -12,6 +12,7 @@
|
|||
"transform-object-rest-spread",
|
||||
"syntax-class-properties",
|
||||
"transform-class-properties",
|
||||
"transform-async-to-generator",
|
||||
"react-hot-loader/babel",
|
||||
["module-resolver", {
|
||||
"root": ["./src"],
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
logs
|
||||
*.log
|
||||
|
||||
dist/*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
|
|
2
app.js
|
@ -18,6 +18,8 @@ if (process.env.NODE_ENV !== 'dist') {
|
|||
historyApiFallback: true
|
||||
}))
|
||||
|
||||
app.use('/favicon.ico', express.static(path.join(__dirname, 'src/static/favicon.ico')))
|
||||
|
||||
app.use(webpackHotMiddleware(compiler, {
|
||||
log: console.log,
|
||||
path: '/__webpack_hmr',
|
||||
|
|
37
cfg/base.js
|
@ -1,27 +1,32 @@
|
|||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||
|
||||
const env = process.env.REACT_WEBPACK_ENV
|
||||
|
||||
let constants
|
||||
try {
|
||||
constants = require(`./${env}.const`)
|
||||
} catch (ex) { // TODO: Catch only file not found.
|
||||
console.log(`${env}.const not found.`, ex)
|
||||
constants = require('./defaultConstants')
|
||||
} catch (ex) {
|
||||
if (ex.code && ex.code === 'MODULE_NOT_FOUND') {
|
||||
console.log(`${env}.const not found. Falling back to defaultConstants.`)
|
||||
constants = require('./defaultConstants')
|
||||
} else {
|
||||
throw new Error(`Unknown error while loading ${env}.const. ${ex}`)
|
||||
}
|
||||
}
|
||||
|
||||
const srcPath = path.join(__dirname, '/../src')
|
||||
const siaRoot = path.join(__dirname, '..')
|
||||
const publicPath = '/assets/'
|
||||
|
||||
const config = {
|
||||
entry: {
|
||||
app: ['babel-polyfill'],
|
||||
appInsights: path.join(srcPath, 'appInsights')
|
||||
appInsights: path.join(siaRoot, 'src/appInsights')
|
||||
},
|
||||
devtool: 'eval',
|
||||
output: {
|
||||
path: path.join(__dirname, '/../dist/assets'),
|
||||
path: path.join(siaRoot, 'dist/assets'),
|
||||
filename: '[name].js',
|
||||
publicPath: publicPath
|
||||
},
|
||||
|
@ -33,15 +38,7 @@ const config = {
|
|||
noInfo: false
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js'],
|
||||
alias: {
|
||||
actions: `${srcPath}/actions/`,
|
||||
sources: `${srcPath}/sources/`,
|
||||
stores: `${srcPath}/stores/`,
|
||||
styles: `${srcPath}/styles/`,
|
||||
config: `${srcPath}/config/`,
|
||||
'react/lib/ReactMount': 'react-dom/lib/ReactMount'
|
||||
}
|
||||
extensions: ['.js']
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
|
@ -85,7 +82,15 @@ const config = {
|
|||
'process.env.NODE_ENV': `"${env}"`,
|
||||
'constants': JSON.stringify(constants)
|
||||
}),
|
||||
new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /de/)
|
||||
new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /de/),
|
||||
new CopyWebpackPlugin([
|
||||
{ from: path.join(siaRoot, 'src/extensionHooks/manifest.json'), to: path.join(siaRoot, 'dist') },
|
||||
{ from: path.join(siaRoot, 'src/static'), to: path.join(siaRoot, 'dist/static') },
|
||||
{ from: path.join(siaRoot, 'src/static/favicon.ico'), to: path.join(siaRoot, 'dist') },
|
||||
{ from: path.join(siaRoot, 'src/extensionHooks/extension.html'), to: path.join(siaRoot, 'dist') },
|
||||
{ from: path.join(siaRoot, 'src/index.html'), to: path.join(siaRoot, 'dist') }
|
||||
],
|
||||
{ copyUnmodified: true })
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ module.exports = {
|
|||
|
||||
baseUrl: 'http://localhost:50000/',
|
||||
|
||||
eventUiUrl: 'http://localhost:3000/',
|
||||
|
||||
authRedirectUri: 'http://localhost:3000/',
|
||||
|
||||
retries: 2,
|
||||
|
@ -42,6 +44,6 @@ module.exports = {
|
|||
},
|
||||
|
||||
instrumentationKey: 'APP INSIGHT GOES HERE',
|
||||
|
||||
|
||||
useAppInsights: false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
# About the dist folder
|
||||
After building the dist version of your project, the generated files are stored in this folder. You should keep it under version control.
|
|
@ -1,16 +0,0 @@
|
|||
{
|
||||
"name": "SIA",
|
||||
"description": "SIA",
|
||||
"version": "0.0.0.2",
|
||||
"manifest_version": 2,
|
||||
"browser_action": {
|
||||
"default_popup": "extension.html"
|
||||
},
|
||||
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
|
||||
"author": "microsoft",
|
||||
"permissions": [
|
||||
"identity",
|
||||
"tabs",
|
||||
"https://*/"
|
||||
]
|
||||
}
|
До Ширина: | Высота: | Размер: 100 KiB |
|
@ -1,24 +0,0 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<!--
|
||||
To collect end-user usage analytics about your application,
|
||||
insert the following script into each page you want to track.
|
||||
Place this code immediately before the closing </head> tag,
|
||||
and before any other scripts. Your first data will appear
|
||||
automatically in just a few seconds.
|
||||
-->
|
||||
<script type="text/javascript" src="/assets/appInsights.js"></script>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>SRE Incident Assistant</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
</head>
|
||||
<body>
|
||||
<div id="siaApp">APPLICATION CONTENT</div>
|
||||
|
||||
<script>__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__</script>
|
||||
<script type="text/javascript" src="/assets/app.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,6 +0,0 @@
|
|||
# static
|
||||
|
||||
Files and directories that you put in `static` will be copied to the
|
||||
`dist/static` directory during the build step. Use it to provide
|
||||
arbitrary static assets that can be referenced by path in your
|
||||
application.
|
До Ширина: | Высота: | Размер: 202 KiB |
|
@ -335,7 +335,7 @@
|
|||
"anymatch": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
|
||||
"integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
|
||||
"integrity": "sha1-VT3Lj5HjyImEXf26NMd3IbkLnXo=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"micromatch": "2.3.11",
|
||||
|
@ -345,7 +345,7 @@
|
|||
"aproba": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
|
||||
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
|
||||
"integrity": "sha1-aALmJk79GMeQobDVF/DyYnvyyUo=",
|
||||
"dev": true
|
||||
},
|
||||
"are-we-there-yet": {
|
||||
|
@ -380,7 +380,7 @@
|
|||
"arr-flatten": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
|
||||
"integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
|
||||
"integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=",
|
||||
"dev": true
|
||||
},
|
||||
"array-filter": {
|
||||
|
@ -822,7 +822,7 @@
|
|||
"babel-loader": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-7.1.2.tgz",
|
||||
"integrity": "sha512-jRwlFbINAeyDStqK6Dd5YuY0k5YuzQUvlz2ZamuXrXmxav3pNqe9vfJ402+2G+OmlJSXxCOpB6Uz0INM7RQe2A==",
|
||||
"integrity": "sha1-9svhInEPGqKvTYgcbVtUNYyiQSY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"find-cache-dir": "1.0.0",
|
||||
|
@ -1336,7 +1336,7 @@
|
|||
"babel-preset-env": {
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.6.1.tgz",
|
||||
"integrity": "sha512-W6VIyA6Ch9ePMI7VptNn2wBM6dbG0eSz25HEiL40nQXCsXGTGZSTZu1Iap+cj3Q0S5a7T9+529l/5Bkvd+afNA==",
|
||||
"integrity": "sha1-oYtWTMm5r99KrleuPBsNmRiOb0g=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-plugin-check-es2015-constants": "6.22.0",
|
||||
|
@ -1490,7 +1490,7 @@
|
|||
"babylon": {
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
|
||||
"integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
|
||||
"integrity": "sha1-ry87iPpvXB5MY00aD46sT1WzleM=",
|
||||
"dev": true
|
||||
},
|
||||
"backo2": {
|
||||
|
@ -1514,7 +1514,7 @@
|
|||
"base64-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",
|
||||
"integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==",
|
||||
"integrity": "sha1-qRlH2h9KUW6jjltOwOw3c2deCIY=",
|
||||
"dev": true
|
||||
},
|
||||
"base64id": {
|
||||
|
@ -1586,7 +1586,7 @@
|
|||
"bn.js": {
|
||||
"version": "4.11.8",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
|
||||
"integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==",
|
||||
"integrity": "sha1-LN4J617jQfSEdGuwMJsyU7GxRC8=",
|
||||
"dev": true
|
||||
},
|
||||
"body-parser": {
|
||||
|
@ -1710,7 +1710,7 @@
|
|||
"browserify": {
|
||||
"version": "14.5.0",
|
||||
"resolved": "https://registry.npmjs.org/browserify/-/browserify-14.5.0.tgz",
|
||||
"integrity": "sha512-gKfOsNQv/toWz+60nSPfYzuwSEdzvV2WdxrVPUbPD/qui44rAkB3t3muNtmmGYHqrG56FGwX9SUEQmzNLAeS7g==",
|
||||
"integrity": "sha1-C7vOUhrNbk0dVNjpNlAI77hanMU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"JSONStream": "1.3.1",
|
||||
|
@ -2131,7 +2131,7 @@
|
|||
"cipher-base": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
|
||||
"integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
|
||||
"integrity": "sha1-h2Dk7MJy9MNjUy+SbYdKriwTl94=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"inherits": "2.0.3",
|
||||
|
@ -2141,7 +2141,7 @@
|
|||
"circular-json": {
|
||||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
|
||||
"integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==",
|
||||
"integrity": "sha1-gVyZ6oT2gJUp0vRXkb34JxE1LWY=",
|
||||
"dev": true
|
||||
},
|
||||
"clap": {
|
||||
|
@ -2436,7 +2436,7 @@
|
|||
"copy-concurrently": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
|
||||
"integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==",
|
||||
"integrity": "sha1-kilzmMrjSTf8r9bsgTnBgFHwteA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"aproba": "1.2.0",
|
||||
|
@ -2447,6 +2447,59 @@
|
|||
"run-queue": "1.0.3"
|
||||
}
|
||||
},
|
||||
"copy-webpack-plugin": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.4.1.tgz",
|
||||
"integrity": "sha512-ojaz8MpS3zoLJT/JbYMusYM+dCEArhW24hGAUPYPydTCS+87NFh2TWr85sywG3So4Q4E68QoerqQ+Ns1g0fhDg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cacache": "10.0.2",
|
||||
"find-cache-dir": "1.0.0",
|
||||
"globby": "7.1.1",
|
||||
"is-glob": "4.0.0",
|
||||
"loader-utils": "0.2.17",
|
||||
"minimatch": "3.0.4",
|
||||
"p-limit": "1.1.0",
|
||||
"serialize-javascript": "1.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"globby": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz",
|
||||
"integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"array-union": "1.0.2",
|
||||
"dir-glob": "2.0.0",
|
||||
"glob": "7.1.2",
|
||||
"ignore": "3.3.5",
|
||||
"pify": "3.0.0",
|
||||
"slash": "1.0.0"
|
||||
}
|
||||
},
|
||||
"is-extglob": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
|
||||
"dev": true
|
||||
},
|
||||
"is-glob": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz",
|
||||
"integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extglob": "2.1.1"
|
||||
}
|
||||
},
|
||||
"pify": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
||||
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"copyfiles": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-1.2.0.tgz",
|
||||
|
@ -2510,7 +2563,7 @@
|
|||
"cross-env": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.1.3.tgz",
|
||||
"integrity": "sha512-UOokgwvDzCT0mqRSLEkJzUhYXB1vK3E5UgDrD41QiXsm9UetcW2rCGHYz/O3p873lMJ1VZbFCF9Izkwh7nYR5A==",
|
||||
"integrity": "sha1-+K4Y+qyHaSsKi00vcADU7DqF39c=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cross-spawn": "5.1.0",
|
||||
|
@ -2975,6 +3028,33 @@
|
|||
"randombytes": "2.0.5"
|
||||
}
|
||||
},
|
||||
"dir-glob": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz",
|
||||
"integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"arrify": "1.0.1",
|
||||
"path-type": "3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"path-type": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
|
||||
"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pify": "3.0.0"
|
||||
}
|
||||
},
|
||||
"pify": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
||||
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"discontinuous-range": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz",
|
||||
|
@ -3108,7 +3188,7 @@
|
|||
"electron-releases": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/electron-releases/-/electron-releases-2.1.0.tgz",
|
||||
"integrity": "sha512-cyKFD1bTE/UgULXfaueIN1k5EPFzs+FRc/rvCY5tIynefAPqopQEgjr0EzY+U3Dqrk/G4m9tXSPuZ77v6dL/Rw==",
|
||||
"integrity": "sha1-xWFL+BHxds48g242igYleCNB/U4=",
|
||||
"dev": true
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
|
@ -3515,7 +3595,7 @@
|
|||
"espree": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/espree/-/espree-3.5.2.tgz",
|
||||
"integrity": "sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==",
|
||||
"integrity": "sha1-dWrai5eenc/NswqtjRqTBKkF4co=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"acorn": "5.3.0",
|
||||
|
@ -3525,7 +3605,7 @@
|
|||
"acorn": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.3.0.tgz",
|
||||
"integrity": "sha512-Yej+zOJ1Dm/IMZzzj78OntP/r3zHEaKcyNoU2lAaxPtrseM6rF0xwqoz5Q5ysAiED9hTjI2hgtvLXitlCN1/Ug==",
|
||||
"integrity": "sha1-dEbTlFnFT7SagObuZHgUm5QOyCI=",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
|
@ -3592,7 +3672,7 @@
|
|||
"evp_bytestokey": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
|
||||
"integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
|
||||
"integrity": "sha1-f8vbGY3HGVlDLv4ThCaE4FJaywI=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"md5.js": "1.3.4",
|
||||
|
@ -4029,7 +4109,7 @@
|
|||
"file-loader": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.6.tgz",
|
||||
"integrity": "sha512-873ztuL+/hfvXbLDJ262PGO6XjERnybJu2gW1/5j8HUfxSiFJI9Hj/DhZ50ZGRUxBvuNiazb/cM2rh9pqrxP6Q==",
|
||||
"integrity": "sha1-e5qPLFjwCnf930npQPesl4o+oOg=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loader-utils": "1.1.0",
|
||||
|
@ -4108,6 +4188,37 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"find-cache-dir": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz",
|
||||
"integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commondir": "1.0.1",
|
||||
"make-dir": "1.0.0",
|
||||
"pkg-dir": "2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"find-up": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
|
||||
"integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"locate-path": "2.0.0"
|
||||
}
|
||||
},
|
||||
"pkg-dir": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz",
|
||||
"integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"find-up": "2.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"find-root": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
|
||||
|
@ -4447,15 +4558,12 @@
|
|||
"full-icu": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/full-icu/-/full-icu-1.2.0.tgz",
|
||||
"integrity": "sha512-0B/oH/5WnTM0grN0/F91WN1zdLx+IKH0uOlAqj6DWhRQTGFCj645elI46fKykRSWeafPrIOIRzAL7co1Vku5pQ==",
|
||||
"requires": {
|
||||
"icu4c-data": "0.59.2"
|
||||
}
|
||||
"integrity": "sha512-0B/oH/5WnTM0grN0/F91WN1zdLx+IKH0uOlAqj6DWhRQTGFCj645elI46fKykRSWeafPrIOIRzAL7co1Vku5pQ=="
|
||||
},
|
||||
"function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=",
|
||||
"dev": true
|
||||
},
|
||||
"function.prototype.name": {
|
||||
|
@ -4560,7 +4668,7 @@
|
|||
"glob": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
|
||||
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
|
||||
"integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "1.0.0",
|
||||
|
@ -4609,7 +4717,7 @@
|
|||
"globals": {
|
||||
"version": "9.18.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
|
||||
"integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
|
||||
"integrity": "sha1-qjiWs+abSH8X4x7SFD1pqOMMLYo=",
|
||||
"dev": true
|
||||
},
|
||||
"globby": {
|
||||
|
@ -4743,7 +4851,7 @@
|
|||
"hash.js": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz",
|
||||
"integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==",
|
||||
"integrity": "sha1-NA3tvmKQGHFRweodd3o0SJNd+EY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"inherits": "2.0.3",
|
||||
|
@ -4792,7 +4900,7 @@
|
|||
"history": {
|
||||
"version": "4.7.2",
|
||||
"resolved": "https://registry.npmjs.org/history/-/history-4.7.2.tgz",
|
||||
"integrity": "sha512-1zkBRWW6XweO0NBcjiphtVJVsIQ+SXF29z9DVkceeaSLVMFXHool+fdCZD4spDCfZJCILPILc3bm7Bc+HRi0nA==",
|
||||
"integrity": "sha1-IrXH8xYzxbgCHH9KipVKwTnujVs=",
|
||||
"requires": {
|
||||
"invariant": "2.2.2",
|
||||
"loose-envify": "1.3.1",
|
||||
|
@ -4830,7 +4938,7 @@
|
|||
"hosted-git-info": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz",
|
||||
"integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==",
|
||||
"integrity": "sha1-bWDjSzq7yDEwYsO3mO+NkBoHrzw=",
|
||||
"dev": true
|
||||
},
|
||||
"html-comment-regex": {
|
||||
|
@ -4969,7 +5077,7 @@
|
|||
"ansi-styles": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
|
||||
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
|
||||
"integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "1.9.0"
|
||||
|
@ -4978,7 +5086,7 @@
|
|||
"chalk": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz",
|
||||
"integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==",
|
||||
"integrity": "sha1-tepI78nBeT3MybR2fJORTT8tUro=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "3.2.0",
|
||||
|
@ -5023,7 +5131,7 @@
|
|||
"supports-color": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.1.0.tgz",
|
||||
"integrity": "sha512-Ry0AwkoKjDpVKK4sV4h6o3UJmNRbjYm2uXhwfj3J56lMVdvnUNqzQVRztOOMGQ++w1K/TjNDFvpJk0F/LoeBCQ==",
|
||||
"integrity": "sha1-BYoCHRthn33fOYDXEuo1kM5949U=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "2.0.0"
|
||||
|
@ -5031,11 +5139,6 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"icu4c-data": {
|
||||
"version": "0.59.2",
|
||||
"resolved": "https://registry.npmjs.org/icu4c-data/-/icu4c-data-0.59.2.tgz",
|
||||
"integrity": "sha1-Xf97e+4H/fp6ybtgHMe4gEaha+Y="
|
||||
},
|
||||
"ieee754": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz",
|
||||
|
@ -5529,13 +5632,13 @@
|
|||
"istanbul-lib-coverage": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz",
|
||||
"integrity": "sha512-0+1vDkmzxqJIn5rcoEqapSB4DmPxE31EtI2dF2aCkV5esN9EWHxZ0dwgDClivMXJqE7zaYQxq30hj5L0nlTN5Q==",
|
||||
"integrity": "sha1-c7+5mIhSmUFck9OKPprfeEp3qdo=",
|
||||
"dev": true
|
||||
},
|
||||
"istanbul-lib-instrument": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.9.1.tgz",
|
||||
"integrity": "sha512-RQmXeQ7sphar7k7O1wTNzVczF9igKpaeGQAG9qR2L+BS4DCJNTI9nytRmIVYevwO0bbq+2CXvJmYDuz0gMrywA==",
|
||||
"integrity": "sha1-JQsws1MeXTJRKZ/dZLCyydtrVY4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-generator": "6.26.0",
|
||||
|
@ -5989,7 +6092,7 @@
|
|||
"karma-babel-preprocessor": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/karma-babel-preprocessor/-/karma-babel-preprocessor-7.0.0.tgz",
|
||||
"integrity": "sha512-k8YUot8ZAAYhAeUxOsOGUEXW7AlB6SkoIVGfavEBCAdGHzWuraOBoR2wCxxdePUCvcItIxSUyQnOj6DuZdEJYA==",
|
||||
"integrity": "sha1-GHVtgY+XpeiPkZAmdM2RMBd6jc4=",
|
||||
"dev": true
|
||||
},
|
||||
"karma-chai": {
|
||||
|
@ -6048,7 +6151,7 @@
|
|||
"ansi-styles": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
|
||||
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
|
||||
"integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "1.9.0"
|
||||
|
@ -6057,7 +6160,7 @@
|
|||
"chalk": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz",
|
||||
"integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==",
|
||||
"integrity": "sha1-tepI78nBeT3MybR2fJORTT8tUro=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "3.2.0",
|
||||
|
@ -6122,7 +6225,7 @@
|
|||
"karma-webpack": {
|
||||
"version": "2.0.9",
|
||||
"resolved": "https://registry.npmjs.org/karma-webpack/-/karma-webpack-2.0.9.tgz",
|
||||
"integrity": "sha512-F1j3IG/XhiMzcunAXbWXH95uizjzr3WdTzmVWlta8xqxcCtAu9FByCb4sccIMxaVFAefpgnUW9KlCo0oLvIX6A==",
|
||||
"integrity": "sha1-YciAkffdkQY1E0wDKyZqRlr/tX8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"async": "0.9.2",
|
||||
|
@ -6147,13 +6250,13 @@
|
|||
"mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||
"integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=",
|
||||
"dev": true
|
||||
},
|
||||
"webpack-dev-middleware": {
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz",
|
||||
"integrity": "sha512-FCrqPy1yy/sN6U/SaEZcHKRXGlqU0DUaEBL45jkUYoB8foVb6wCnbIJ1HKIx+qUFTW+3JpVcCJCxZ8VATL4e+A==",
|
||||
"integrity": "sha1-+PwRIM47T8VoDO7LQ9d3lmshEF4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"memory-fs": "0.4.1",
|
||||
|
@ -6564,7 +6667,7 @@
|
|||
"lru-cache": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz",
|
||||
"integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==",
|
||||
"integrity": "sha1-Yi4y6CSItJJ5EUpPns9F581rulU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pseudomap": "1.0.2",
|
||||
|
@ -6674,7 +6777,7 @@
|
|||
"material-ui": {
|
||||
"version": "0.20.0",
|
||||
"resolved": "https://registry.npmjs.org/material-ui/-/material-ui-0.20.0.tgz",
|
||||
"integrity": "sha512-wkHkeU1SaGfCrtwIzBOl5vynNNNzVGW27ql0Ue5HZLB4WyRQ3YohJBdKa5lBrH5JD/Cgae7IzrP7cVWDyKpeLQ==",
|
||||
"integrity": "sha1-hUEbtZyRbJx3A/Kdz/xE46Z9URE=",
|
||||
"requires": {
|
||||
"babel-runtime": "6.26.0",
|
||||
"inline-style-prefixer": "3.0.8",
|
||||
|
@ -6925,7 +7028,7 @@
|
|||
"minimatch": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "1.1.8"
|
||||
|
@ -6975,7 +7078,7 @@
|
|||
"mocha": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mocha/-/mocha-4.1.0.tgz",
|
||||
"integrity": "sha512-0RVnjg1HJsXY2YFDoTNzcc1NKhYuXKRrBAG2gDygmJJA136Cs2QlRliZG1mA0ap7cuaT30mw16luAeln+4RiNA==",
|
||||
"integrity": "sha1-fYbPvPNcuCnidUwy4XNV7AUzh5Q=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"browser-stdout": "1.3.0",
|
||||
|
@ -6993,7 +7096,7 @@
|
|||
"commander": {
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
|
||||
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
|
||||
"integrity": "sha1-FXFS/R56bI2YpbcVzzdt+SgARWM=",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
|
@ -7026,7 +7129,7 @@
|
|||
"supports-color": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
|
||||
"integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
|
||||
"integrity": "sha1-iD992rwWUUKyphQn8zUt7RldGj4=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "2.0.0"
|
||||
|
@ -7342,7 +7445,7 @@
|
|||
"normalize-package-data": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
|
||||
"integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
|
||||
"integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"hosted-git-info": "2.5.0",
|
||||
|
@ -7436,7 +7539,7 @@
|
|||
"nyc": {
|
||||
"version": "11.4.1",
|
||||
"resolved": "https://registry.npmjs.org/nyc/-/nyc-11.4.1.tgz",
|
||||
"integrity": "sha512-5eCZpvaksFVjP2rt1r60cfXmt3MUtsQDw8bAzNqNEr4WLvUMLgiVENMf/B9bE9YAX0mGVvaGA3v9IS9ekNqB1Q==",
|
||||
"integrity": "sha1-E/335+8i0CfGHRdHWPaXimj09eU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"archy": "1.0.0",
|
||||
|
@ -9842,7 +9945,7 @@
|
|||
"ansi-styles": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
|
||||
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
|
||||
"integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "1.9.0"
|
||||
|
@ -9900,7 +10003,7 @@
|
|||
"ansi-styles": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
|
||||
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
|
||||
"integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "1.9.0"
|
||||
|
@ -9980,7 +10083,7 @@
|
|||
"ansi-styles": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
|
||||
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
|
||||
"integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "1.9.0"
|
||||
|
@ -10060,7 +10163,7 @@
|
|||
"ansi-styles": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
|
||||
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
|
||||
"integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "1.9.0"
|
||||
|
@ -10261,7 +10364,7 @@
|
|||
"promise": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
|
||||
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
|
||||
"integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=",
|
||||
"requires": {
|
||||
"asap": "2.0.6"
|
||||
}
|
||||
|
@ -10467,7 +10570,7 @@
|
|||
"randomatic": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
|
||||
"integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==",
|
||||
"integrity": "sha1-x6vpzIuHwLqodrGf3oP9RkeX44w=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-number": "3.0.0",
|
||||
|
@ -10508,7 +10611,7 @@
|
|||
"randombytes": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz",
|
||||
"integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==",
|
||||
"integrity": "sha1-3ACaJGuNCaF3tLegrne8Vw9LG3k=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
|
@ -10546,7 +10649,7 @@
|
|||
"react": {
|
||||
"version": "16.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-16.2.0.tgz",
|
||||
"integrity": "sha512-ZmIomM7EE1DvPEnSFAHZn9Vs9zJl5A9H7el0EGTE6ZbW9FKe/14IYAlPbC8iH25YarEQxZL+E8VW7Mi7kfQrDQ==",
|
||||
"integrity": "sha1-oxvS2rib/2XUITT6GH8k0FTCc7o=",
|
||||
"requires": {
|
||||
"fbjs": "0.8.16",
|
||||
"loose-envify": "1.3.1",
|
||||
|
@ -10583,7 +10686,7 @@
|
|||
"react-dom": {
|
||||
"version": "16.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.2.0.tgz",
|
||||
"integrity": "sha512-zpGAdwHVn9K0091d+hr+R0qrjoJ84cIBFL2uU60KvWBPfZ7LPSrfqviTxGHWN0sjPZb2hxWzMexwrvJdKePvjg==",
|
||||
"integrity": "sha1-aQAxeGAcDKGbcJszqDNp/mEkwEQ=",
|
||||
"requires": {
|
||||
"fbjs": "0.8.16",
|
||||
"loose-envify": "1.3.1",
|
||||
|
@ -10615,7 +10718,7 @@
|
|||
"react-hot-loader": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-3.1.3.tgz",
|
||||
"integrity": "sha512-d7nZf78irxoGN5PY4zd6CSgZiroOhvIWzRast3qwTn4sSnBwlt08kV8WMQ9mitmxEdlCTwZt+5ClrRSjxWguMQ==",
|
||||
"integrity": "sha1-b5KHcyaVjHywE0tRJHRReGkSYII=",
|
||||
"requires": {
|
||||
"global": "4.3.2",
|
||||
"react-deep-force-update": "2.1.1",
|
||||
|
@ -10677,7 +10780,7 @@
|
|||
"react-redux": {
|
||||
"version": "5.0.6",
|
||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.0.6.tgz",
|
||||
"integrity": "sha512-8taaaGu+J7PMJQDJrk/xiWEYQmdo3mkXw6wPr3K3LxvXis3Fymiq7c13S+Tpls/AyNUAsoONkU81AP0RA6y6Vw==",
|
||||
"integrity": "sha1-I+06T5hjWdaLUhLqqmgeYNZXSUY=",
|
||||
"requires": {
|
||||
"hoist-non-react-statics": "2.3.1",
|
||||
"invariant": "2.2.2",
|
||||
|
@ -10697,7 +10800,7 @@
|
|||
"react-router": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-4.2.0.tgz",
|
||||
"integrity": "sha512-DY6pjwRhdARE4TDw7XjxjZsbx9lKmIcyZoZ+SDO7SBJ1KUeWNxT22Kara2AC7u6/c2SYEHlEDLnzBCcNhLE8Vg==",
|
||||
"integrity": "sha1-Yfez43cNrrJAYtrj7t7xsFQVWYY=",
|
||||
"requires": {
|
||||
"history": "4.7.2",
|
||||
"hoist-non-react-statics": "2.3.1",
|
||||
|
@ -10731,7 +10834,7 @@
|
|||
"react-router-dom": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-4.2.2.tgz",
|
||||
"integrity": "sha512-cHMFC1ZoLDfEaMFoKTjN7fry/oczMgRt5BKfMAkTu5zEuJvUiPp1J8d0eXSVTnBh6pxlbdqDhozunOOLtmKfPA==",
|
||||
"integrity": "sha1-yKgd863Fi7qKdngulGy9Tq5km40=",
|
||||
"requires": {
|
||||
"history": "4.7.2",
|
||||
"invariant": "2.2.2",
|
||||
|
@ -10752,7 +10855,7 @@
|
|||
"react-test-renderer": {
|
||||
"version": "16.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-16.2.0.tgz",
|
||||
"integrity": "sha512-Kd4gJFtpNziR9ElOE/C23LeflKLZPRpNQYWP3nQBY43SJ5a+xyEGSeMrm2zxNKXcnCbBS/q1UpD9gqd5Dv+rew==",
|
||||
"integrity": "sha1-vd8lmmuPzYVV8BKvyOrMI4hyohE=",
|
||||
"requires": {
|
||||
"fbjs": "0.8.16",
|
||||
"object-assign": "4.1.1",
|
||||
|
@ -10813,7 +10916,7 @@
|
|||
"readable-stream": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
|
||||
"integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
|
||||
"integrity": "sha1-No8lEtefnUb9/HE0mueHi7weuVw=",
|
||||
"requires": {
|
||||
"core-util-is": "1.0.2",
|
||||
"inherits": "2.0.3",
|
||||
|
@ -10859,7 +10962,7 @@
|
|||
"redbox-react": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/redbox-react/-/redbox-react-1.5.0.tgz",
|
||||
"integrity": "sha512-mdxArOI3sF8K5Nay5NG+lv/VW516TbXjjd4h1wcV1Iy4IMDQPnCayjoQXBAycAFSME4nyXRUXCjHxsw2rYpVRw==",
|
||||
"integrity": "sha1-BNqxFVfSZlG/NWKmfCKs5WxdOWc=",
|
||||
"requires": {
|
||||
"error-stack-parser": "1.3.6",
|
||||
"object-assign": "4.1.1",
|
||||
|
@ -10942,7 +11045,7 @@
|
|||
"redux": {
|
||||
"version": "3.7.2",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-3.7.2.tgz",
|
||||
"integrity": "sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==",
|
||||
"integrity": "sha1-BrcxIyFZAdJdBlvjQusCa8HIU3s=",
|
||||
"requires": {
|
||||
"lodash": "4.17.4",
|
||||
"lodash-es": "4.17.4",
|
||||
|
@ -10953,7 +11056,7 @@
|
|||
"redux-mock-store": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/redux-mock-store/-/redux-mock-store-1.4.0.tgz",
|
||||
"integrity": "sha512-y+SGh/SONWwqs4DiyHjd0H6NMgz368wXDiUjSHuOnMEr4dN9PmjV6N3bNvxoILaIQ7zeVKclLyxsCQ2TwGZfEw==",
|
||||
"integrity": "sha1-zch2UPV1nyk1iP7MnKwrBX2VGQ0=",
|
||||
"requires": {
|
||||
"lodash.isplainobject": "4.0.6"
|
||||
}
|
||||
|
@ -10961,12 +11064,12 @@
|
|||
"redux-persist": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/redux-persist/-/redux-persist-5.4.0.tgz",
|
||||
"integrity": "sha512-Ohp7g5WRx2rDyDk/bKKCgbD3ES6ahGPWxFEp3QPx2opwst0jJEbZKigZtQewUeJZnomN/7Zo3QglPDOZ6EdYEw=="
|
||||
"integrity": "sha1-oQYjE1RqnUym+ScUZNGPc26Mo5Q="
|
||||
},
|
||||
"redux-persist-transform-filter": {
|
||||
"version": "0.0.16",
|
||||
"resolved": "https://registry.npmjs.org/redux-persist-transform-filter/-/redux-persist-transform-filter-0.0.16.tgz",
|
||||
"integrity": "sha512-P7vBmrhOlGWO6Qtw1VoJ2cPzlb4PdPtJjppcJK0uSmcg5TCYxBVla27mxBZzday4CCy0wsYqDq+UI/1E84Yk9Q==",
|
||||
"integrity": "sha1-DCHcFmd0wS+z8JD3ovXqkPe6DOo=",
|
||||
"requires": {
|
||||
"lodash.forin": "4.4.0",
|
||||
"lodash.get": "4.4.2",
|
||||
|
@ -10995,7 +11098,7 @@
|
|||
"regenerator-transform": {
|
||||
"version": "0.10.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz",
|
||||
"integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==",
|
||||
"integrity": "sha1-HkmWg3Ix2ot/PPQRTXG1aRoGgN0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"babel-runtime": "6.26.0",
|
||||
|
@ -11006,7 +11109,7 @@
|
|||
"regex-cache": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
|
||||
"integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
|
||||
"integrity": "sha1-db3FiioUls7EihKDW8VMjVYjNt0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-equal-shallow": "0.1.3"
|
||||
|
@ -11185,7 +11288,7 @@
|
|||
"resolve-pathname": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz",
|
||||
"integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg=="
|
||||
"integrity": "sha1-fpriHtgV/WOrGJre7mTcgx7vqHk="
|
||||
},
|
||||
"restore-cursor": {
|
||||
"version": "1.0.1",
|
||||
|
@ -11220,7 +11323,7 @@
|
|||
"rimraf": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
|
||||
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
|
||||
"integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "7.1.2"
|
||||
|
@ -11279,12 +11382,12 @@
|
|||
"safe-buffer": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
|
||||
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
|
||||
"integrity": "sha1-iTMSr2myEj3vcfV4iQAWce6yyFM="
|
||||
},
|
||||
"sax": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
|
||||
"integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=",
|
||||
"dev": true
|
||||
},
|
||||
"schema-utils": {
|
||||
|
@ -11492,7 +11595,7 @@
|
|||
"source-list-map": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz",
|
||||
"integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==",
|
||||
"integrity": "sha1-qqR0A/eyRakvvJfqCPJQ1gh+0IU=",
|
||||
"dev": true
|
||||
},
|
||||
"source-map": {
|
||||
|
@ -11513,7 +11616,7 @@
|
|||
"sourcemapped-stacktrace": {
|
||||
"version": "1.1.8",
|
||||
"resolved": "https://registry.npmjs.org/sourcemapped-stacktrace/-/sourcemapped-stacktrace-1.1.8.tgz",
|
||||
"integrity": "sha512-OkVoI7GQOLl/laR1qsSo1c87tS8kF2VXhQq2SrQCDdXufBAcm8FgXogWso96ciMYoDtTw1Dn70CVdwYzoYs6Pg==",
|
||||
"integrity": "sha1-a3o/Gm+xX21A5wHiPOQEVTSA1og=",
|
||||
"requires": {
|
||||
"source-map": "0.5.6"
|
||||
},
|
||||
|
@ -11579,7 +11682,7 @@
|
|||
"ssri": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ssri/-/ssri-5.0.0.tgz",
|
||||
"integrity": "sha512-728D4yoQcQm1ooZvSbywLkV1RjfITZXh0oWrhM/lnsx3nAHx7LsRGJWB/YyvoceAYRq98xqbstiN4JBv1/wNHg==",
|
||||
"integrity": "sha1-E8GTkLYGyCHyoQ0Cs1HBcpuU2M8=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
|
@ -11753,7 +11856,7 @@
|
|||
"stream-http": {
|
||||
"version": "2.7.2",
|
||||
"resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz",
|
||||
"integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==",
|
||||
"integrity": "sha1-QKBQ7I3DtTsz2ZCUFcAsC/Gr+60=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"builtin-status-codes": "3.0.0",
|
||||
|
@ -11821,7 +11924,7 @@
|
|||
"string_decoder": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
|
||||
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
|
||||
"integrity": "sha1-D8Z9fBQYJd6UKC3VNr7GubzoYKs=",
|
||||
"requires": {
|
||||
"safe-buffer": "5.1.1"
|
||||
}
|
||||
|
@ -11871,7 +11974,7 @@
|
|||
"style-loader": {
|
||||
"version": "0.19.1",
|
||||
"resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.19.1.tgz",
|
||||
"integrity": "sha512-IRE+ijgojrygQi3rsqT0U4dd+UcPCqcVvauZpCnQrGAlEe+FUIyrK93bUDScamesjP08JlQNsFJU+KmPedP5Og==",
|
||||
"integrity": "sha1-WR/8gLzv4mi3fF2evAUF13Jhn4U=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loader-utils": "1.1.0",
|
||||
|
@ -12013,7 +12116,7 @@
|
|||
"test-exclude": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.1.1.tgz",
|
||||
"integrity": "sha512-35+Asrsk3XHJDBgf/VRFexPgh3UyETv8IAn/LRTiZjVy6rjPVqdEk8dJcJYBzl1w0XCJM48lvTy8SfEsCWS4nA==",
|
||||
"integrity": "sha1-TYSWSwlmsAh+zDNKLOAC09k0HiY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"arrify": "1.0.1",
|
||||
|
@ -12428,7 +12531,7 @@
|
|||
"url-loader": {
|
||||
"version": "0.6.2",
|
||||
"resolved": "https://registry.npmjs.org/url-loader/-/url-loader-0.6.2.tgz",
|
||||
"integrity": "sha512-h3qf9TNn53BpuXTTcpC+UehiRrl0Cv45Yr/xWayApjw6G8Bg2dGke7rIwDQ39piciWCWrC+WiqLjOh3SUp9n0Q==",
|
||||
"integrity": "sha1-oAenEJYg6dmI0UvOZ3od7Lmpk/c=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loader-utils": "1.1.0",
|
||||
|
@ -12510,7 +12613,7 @@
|
|||
"uuid": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
|
||||
"integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==",
|
||||
"integrity": "sha1-PdPT55Crwk17DToDT/q6vijrvAQ=",
|
||||
"dev": true
|
||||
},
|
||||
"uws": {
|
||||
|
@ -12542,7 +12645,7 @@
|
|||
"value-equal": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz",
|
||||
"integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw=="
|
||||
"integrity": "sha1-xb3S9U7gk8BIOdcc4uR1imiQq8c="
|
||||
},
|
||||
"vendors": {
|
||||
"version": "1.0.1",
|
||||
|
@ -12595,7 +12698,7 @@
|
|||
"webpack": {
|
||||
"version": "3.10.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-3.10.0.tgz",
|
||||
"integrity": "sha512-fxxKXoicjdXNUMY7LIdY89tkJJJ0m1Oo8PQutZ5rLgWbV5QVKI15Cn7+/IHnRTd3vfKfiwBx6SBqlorAuNA8LA==",
|
||||
"integrity": "sha1-UpG4dQeM8qv0K90jr+P4+WwX1yU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"acorn": "5.3.0",
|
||||
|
@ -12625,7 +12728,7 @@
|
|||
"acorn": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.3.0.tgz",
|
||||
"integrity": "sha512-Yej+zOJ1Dm/IMZzzj78OntP/r3zHEaKcyNoU2lAaxPtrseM6rF0xwqoz5Q5ysAiED9hTjI2hgtvLXitlCN1/Ug==",
|
||||
"integrity": "sha1-dEbTlFnFT7SagObuZHgUm5QOyCI=",
|
||||
"dev": true
|
||||
},
|
||||
"ajv": {
|
||||
|
@ -12964,7 +13067,7 @@
|
|||
"webpack-hot-middleware": {
|
||||
"version": "2.21.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack-hot-middleware/-/webpack-hot-middleware-2.21.0.tgz",
|
||||
"integrity": "sha512-P6xiOLy10QlSVSO7GanU9PLxN6zLLQ7RG16MPTvmFwf2KUG7jMp6m+fmdgsR7xoaVVLA7OlX3YO6JjoZEKjCuA==",
|
||||
"integrity": "sha1-ezwROnpLMByR4HSVc8eqsotBS1I=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-html": "0.0.7",
|
||||
|
@ -12988,7 +13091,7 @@
|
|||
"ansi-styles": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
|
||||
"integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
|
||||
"integrity": "sha1-wVm41b4PnlpvNG2rlPFs4CIWG4g=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "1.9.0"
|
||||
|
@ -12997,7 +13100,7 @@
|
|||
"chalk": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz",
|
||||
"integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==",
|
||||
"integrity": "sha1-tepI78nBeT3MybR2fJORTT8tUro=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "3.2.0",
|
||||
|
@ -13082,7 +13185,7 @@
|
|||
"which": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
|
||||
"integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==",
|
||||
"integrity": "sha1-/wS9/AEO5UfXgL7DjhrBwnd9JTo=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"isexe": "2.0.0"
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
"main": "",
|
||||
"scripts": {
|
||||
"clean": "rimraf dist/*",
|
||||
"copy": "copyfiles -f ./src/index.html ./src/favicon.ico ./dist",
|
||||
"dist": "npm run copy & webpack --env=dist",
|
||||
"dist": "npm run clean && cross-env NODE_ENV=dist webpack --env=dist --progress --profile --colors --display-error-details --display-reasons --debug",
|
||||
"lint": "standard \"src/**/*.js\"",
|
||||
"lint:fix": "standard --fix \"src/**/*.js\"",
|
||||
"posttest": "npm run lint",
|
||||
|
@ -82,6 +81,7 @@
|
|||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"chai": "^4.1.2",
|
||||
"copy-webpack-plugin": "^4.3.1",
|
||||
"copyfiles": "^1.2.0",
|
||||
"cross-env": "^5.1.3",
|
||||
"css-loader": "^0.28.7",
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { DateTime } from 'luxon'
|
||||
|
||||
import { paginationActions, updatePagination, reduxBackedPromise } from 'actions/actionHelpers'
|
||||
import * as filterActions from 'actions/filterActions'
|
||||
import * as notificationActions from 'actions/notificationActions'
|
||||
|
||||
export const EVENTS = 'EVENTS'
|
||||
export const REQUEST_EVENT = 'REQUEST_EVENT'
|
||||
|
@ -62,6 +64,11 @@ export const getEventActionSet = (incidentId, eventId) => ({
|
|||
}),
|
||||
|
||||
succeed: (event) => (dispatch) => {
|
||||
dispatch(notificationActions.emitNotification({
|
||||
event,
|
||||
incidentId: event.incidentId
|
||||
}))
|
||||
|
||||
dispatch({
|
||||
type: RECEIVE_EVENT,
|
||||
event,
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
export const NOTIFICATIONS_READ = 'NOTIFICATIONS_READ'
|
||||
export const EMIT_NOTIFICATION = 'EMIT_NOTIFICATION'
|
||||
export const NOTIFICATION_EMITTED = 'NOTIFICATION_EMITTED'
|
||||
export const TOGGLE_RECEIVE_PUSH_NOTIFICATIONS = 'TOGGLE_RECEIVE_PUSH_NOTIFICATIONS'
|
||||
export const NOTIFICATION_CLICKED = 'NOTIFICATION_CLICKED'
|
||||
export const NOTIFICATION_REMOVED = 'NOTIFICATION_REMOVED'
|
||||
|
||||
export const notificationClicked = (notificationId, buttonIndex) => ({
|
||||
type: NOTIFICATION_CLICKED,
|
||||
notificationId,
|
||||
buttonIndex
|
||||
})
|
||||
|
||||
export const notificationRemoved = (notificationId) => ({
|
||||
type: NOTIFICATION_REMOVED,
|
||||
notificationId
|
||||
})
|
||||
|
||||
export const notificationEmitted = (eventId, notificationId, buttonActions) => ({
|
||||
type: NOTIFICATION_EMITTED,
|
||||
eventId,
|
||||
notificationId,
|
||||
buttonActions
|
||||
})
|
||||
|
||||
export const emitNotification = (notification) => ({
|
||||
type: EMIT_NOTIFICATION,
|
||||
notification
|
||||
})
|
||||
|
||||
export const toggleReceivePushNotifications = (enable) => ({
|
||||
type: TOGGLE_RECEIVE_PUSH_NOTIFICATIONS,
|
||||
enable
|
||||
})
|
||||
|
||||
export const notificationsRead = { type: NOTIFICATIONS_READ }
|
|
@ -0,0 +1,10 @@
|
|||
import { Component } from 'react'
|
||||
|
||||
class ExtensionBadge extends Component {
|
||||
render () {
|
||||
chrome.browserAction.setBadgeText({ text: this.props.text })
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export default ExtensionBadge
|
|
@ -0,0 +1,84 @@
|
|||
import { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import config from 'config'
|
||||
import { fillTemplate, LoadTextFromEvent } from 'services/playbookService'
|
||||
import { notificationEmitted } from 'actions/notificationActions'
|
||||
|
||||
export class Notification extends Component {
|
||||
componentDidMount () {
|
||||
if (!this.props.isEmitted) {
|
||||
this.createNotification()
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
if (this.props.isClicked) {
|
||||
this.handleClicks()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
handleClicks () {
|
||||
const { buttonActions, buttonIndex } = this.props
|
||||
const buttonAction = buttonIndex != null
|
||||
? buttonActions[buttonIndex]
|
||||
: buttonActions.find(buttonAction => buttonAction.default)
|
||||
if (buttonAction) {
|
||||
chrome.tabs.create({ url: buttonAction.url })
|
||||
}
|
||||
}
|
||||
|
||||
createNotification () {
|
||||
const { notificationEmitted, event } = this.props
|
||||
const buttonActions = this.createButtonActions()
|
||||
const notificationBody = this.createNotificationBody(buttonActions)
|
||||
chrome.notifications.create(notificationBody, (notificationId) => {
|
||||
notificationEmitted(event.id, notificationId, buttonActions)
|
||||
})
|
||||
}
|
||||
|
||||
createNotificationBody (buttonActions) {
|
||||
const { event, ticket, eventType, engagement } = this.props
|
||||
const severity = ticket.data ? ticket.data.severity : null
|
||||
const title = ticket.data ? ticket.data.title : null
|
||||
return {
|
||||
type: 'basic',
|
||||
iconUrl: `/static/sia-blue-icon-128.png`,
|
||||
title: `${ticket.originId} | ${ticket.status} ${severity ? '| Sev ' + severity : ''}`,
|
||||
message: LoadTextFromEvent(event, eventType, ticket, engagement),
|
||||
contextMessage: title || `SRE Incident Assistant | Event ID: ${event.id}`,
|
||||
// Only two buttons allowed in chrome notifications
|
||||
buttons: buttonActions.slice(0, 2).map(buttonAction => ({
|
||||
title: buttonAction.title,
|
||||
iconUrl: '/static/sia-green-icon-128.png'
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
createButtonActions () {
|
||||
const { actions, event, ticket, eventType, engagement } = this.props
|
||||
const ticketSystem = config.ticketSystems[ticket.ticketSystemId || 1]
|
||||
const defaultActions = [{
|
||||
title: 'Open in SIA',
|
||||
url: `${config.eventUiUrl}tickets/${ticket.originId}`,
|
||||
default: true
|
||||
}, {
|
||||
title: `Open in ${ticketSystem.name}`,
|
||||
url: `${ticketSystem.ticketUriPrefix}${ticket.originId}${ticketSystem.ticketUriSuffix}`
|
||||
}]
|
||||
const playbookActions = actions
|
||||
? actions.filter(action => action.actionTemplate.isUrl)
|
||||
.map(action => ({
|
||||
title: `${action.name}: ${action.actionTemplate.name}`,
|
||||
url: fillTemplate(action.actionTemplate, event, ticket, eventType, engagement)
|
||||
})) : []
|
||||
return playbookActions.concat(defaultActions)
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
notificationEmitted
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(Notification)
|
|
@ -0,0 +1,85 @@
|
|||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import * as incidentActions from 'actions/incidentActions'
|
||||
|
||||
import ExtensionBadge from 'components/Extension/ExtensionBadge'
|
||||
import Notification from 'components/Extension/Notification'
|
||||
|
||||
class Notifications extends Component {
|
||||
componentDidUpdate () {
|
||||
if (!this.props.enabled) {
|
||||
return
|
||||
}
|
||||
|
||||
this.fetchIncidentsIfNeeded()
|
||||
}
|
||||
|
||||
fetchIncidentsIfNeeded () {
|
||||
const { notifications, incidents, incidentsFetching, fetchIncident } = this.props
|
||||
const incidentIds = [...new Set(notifications.map(n => n.incidentId))]
|
||||
incidentIds.forEach(incidentId => {
|
||||
const incidentIsLoaded = incidents[incidentId]
|
||||
const incidentIsFetching = incidentsFetching.includes(incidentId)
|
||||
if (incidentIsLoaded || incidentIsFetching) {
|
||||
return
|
||||
}
|
||||
fetchIncident(incidentId)
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
const { enabled, notifications, unreadCount, eventTypes, incidents } = this.props
|
||||
|
||||
if (!enabled || unreadCount === 0) {
|
||||
return <ExtensionBadge text='' />
|
||||
}
|
||||
|
||||
const notificationsToRender = notifications.filter(n => incidents[n.incidentId])
|
||||
.map(notification => {
|
||||
const eventType = eventTypes[notification.event.eventTypeId]
|
||||
const actions = eventType ? eventType.actions : null
|
||||
const ticket = incidents[notification.incidentId].primaryTicket
|
||||
const engagement = null // TODO
|
||||
|
||||
return <Notification
|
||||
key={notification.event.id}
|
||||
{...notification}
|
||||
actions={actions}
|
||||
engagement={engagement}
|
||||
eventType={eventType}
|
||||
ticket={ticket}
|
||||
/>
|
||||
})
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ExtensionBadge text={unreadCount > 99 ? '99+' : unreadCount.toString()} />
|
||||
{ notificationsToRender }
|
||||
</div>)
|
||||
}
|
||||
}
|
||||
|
||||
export const mapStateToProps = (state) => {
|
||||
const enabled = state.notifications.options.receivePushNotificationsEnabled
|
||||
|
||||
if (!enabled) {
|
||||
return { enabled }
|
||||
}
|
||||
|
||||
return {
|
||||
enabled,
|
||||
notifications: state.notifications.list,
|
||||
unreadCount: state.notifications.unreadCount,
|
||||
eventTypes: state.eventTypes.records,
|
||||
incidents: state.incidents.map,
|
||||
engagements: state.engagements.list,
|
||||
incidentsFetching: state.incidents.fetchingByIncidentId
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
fetchIncident: incidentActions.fetchIncident
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Notifications)
|
|
@ -14,6 +14,8 @@ import incidentRedirect from 'components/Incident/incidentRedirect'
|
|||
import Home from 'components/Home'
|
||||
import TopNav from 'components/TopNav/TopNav'
|
||||
import Debug from 'components/Debug'
|
||||
import { isChromeExtensionBackground } from 'services/notificationService'
|
||||
import Notifications from 'components/Extension/Notifications'
|
||||
|
||||
const history = createBrowserHistory()
|
||||
|
||||
|
@ -27,6 +29,7 @@ export default class MainComponent extends React.Component {
|
|||
<EnsureLoggedInContainer>
|
||||
<Router history={history} >
|
||||
<div>
|
||||
{ isChromeExtensionBackground() ? <Notifications /> : null }
|
||||
<TopNav />
|
||||
<Route exact path='/' component={Home} />
|
||||
<Route exact path='/extension.html' component={Home} />
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
let config
|
||||
try {
|
||||
|
||||
if (typeof constants !== 'undefined') {
|
||||
// The global 'constants' is being defined by Webpack in /cfg/[dev|dist|test|localhost].js
|
||||
// eslint-disable-next-line no-undef
|
||||
config = constants
|
||||
} catch (ex) { // required for Travis and Code Coverage
|
||||
try {
|
||||
const testConstants = require('../../cfg/test.const.js')
|
||||
config = testConstants.default || testConstants
|
||||
} catch (ex) {
|
||||
const defaultConstants = require('../../cfg/defaultConstants')
|
||||
config = defaultConstants.default || defaultConstants
|
||||
}
|
||||
} else {
|
||||
const defaultConstants = require('../../cfg/defaultConstants')
|
||||
config = defaultConstants.default || defaultConstants
|
||||
}
|
||||
|
||||
export default config
|
||||
|
|
|
@ -5,6 +5,7 @@ import { ListenForScreenSize } from 'actions/styleActions'
|
|||
import incidentApp from 'reducers'
|
||||
import { persistStore } from 'redux-persist'
|
||||
import { getFilterFromUrl } from 'actions/filterActions'
|
||||
import { configureNotificationService } from 'services/notificationService'
|
||||
|
||||
const urlFilter = getFilterFromUrl(window.location.search)
|
||||
const reducer = incidentApp(urlFilter)
|
||||
|
@ -15,4 +16,6 @@ export const persistor = persistStore(store)
|
|||
|
||||
establishSignalRConnection(store.dispatch)
|
||||
|
||||
configureNotificationService(store.dispatch)
|
||||
|
||||
ListenForScreenSize(window, store)
|
||||
|
|
|
@ -6,9 +6,10 @@
|
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<div id="siaApp" style="height:1000px" >APPLICATION CONTENT</div>
|
||||
<script type="text/javascript" src="app.js"></script>
|
||||
<script type="text/javascript" src="/assets/app.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "SIA",
|
||||
"description": "SRE Incident Assistant",
|
||||
"version": "0.0.0.3",
|
||||
"icons": {
|
||||
"128": "/static/sia-blue-icon-128.png",
|
||||
"24": "/static/sia-blue-icon-24.png",
|
||||
"19": "/static/sia-blue-icon-19.png",
|
||||
"16": "/static/sia-blue-icon-16.png"
|
||||
},
|
||||
"manifest_version": 2,
|
||||
"browser_action": {
|
||||
"default_icon": {
|
||||
"128": "/static/sia-blue-icon-128.png",
|
||||
"24": "/static/sia-blue-icon-24.png",
|
||||
"19": "/static/sia-blue-icon-19.png",
|
||||
"16": "/static/sia-blue-icon-16.png"
|
||||
},
|
||||
"default_popup": "/extension.html"
|
||||
},
|
||||
"background": {
|
||||
"page": "/extension.html"
|
||||
},
|
||||
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
|
||||
"author": "microsoft",
|
||||
"permissions": [
|
||||
"contextMenus",
|
||||
"notifications",
|
||||
"identity",
|
||||
"tabs",
|
||||
"https://*/"
|
||||
]
|
||||
}
|
Двоичные данные
src/favicon.ico
До Ширина: | Высота: | Размер: 100 KiB |
|
@ -7,10 +7,10 @@
|
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<div id="siaApp">APPLICATION CONTENT</div>
|
||||
|
||||
<script>__REACT_DEVTOOLS_GLOBAL_HOOK__ = parent.__REACT_DEVTOOLS_GLOBAL_HOOK__</script>
|
||||
<script type="text/javascript" src="/assets/app.js"></script>
|
||||
</body>
|
||||
|
|
|
@ -9,6 +9,7 @@ import signalR from 'reducers/signalRReducer'
|
|||
import forms from 'reducers/formReducer'
|
||||
import eventTypes from 'reducers/eventTypeReducer'
|
||||
import globalActions from 'reducers/globalActionReducer'
|
||||
import notifications from 'reducers/notificationReducer'
|
||||
|
||||
const rootReducer = (filters) => combineReducers({
|
||||
incidents,
|
||||
|
@ -20,7 +21,8 @@ const rootReducer = (filters) => combineReducers({
|
|||
expandSection,
|
||||
signalR,
|
||||
eventTypes,
|
||||
globalActions
|
||||
globalActions,
|
||||
notifications
|
||||
})
|
||||
|
||||
export default rootReducer
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
import { combineReducers } from 'redux'
|
||||
import * as notificationActions from 'actions/notificationActions'
|
||||
|
||||
const notificationOptionsInitialState = {
|
||||
receivePushNotificationsEnabled: true
|
||||
}
|
||||
|
||||
export function notificationOptionsReducer (state = notificationOptionsInitialState, action) {
|
||||
switch (action.type) {
|
||||
case notificationActions.TOGGLE_RECEIVE_PUSH_NOTIFICATIONS:
|
||||
return {
|
||||
...state,
|
||||
receivePushNotificationsEnabled: action.enable
|
||||
}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
const unreadNotificationCountInitialState = 0
|
||||
|
||||
export function unreadNotificationCountReducer (state = unreadNotificationCountInitialState, action) {
|
||||
switch (action.type) {
|
||||
case notificationActions.EMIT_NOTIFICATION:
|
||||
return state + 1
|
||||
case notificationActions.NOTIFICATIONS_READ:
|
||||
return 0
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
const notificationListInitialState = []
|
||||
|
||||
export function notificationListReducer (state = notificationListInitialState, action) {
|
||||
switch (action.type) {
|
||||
case notificationActions.EMIT_NOTIFICATION:
|
||||
return state.concat(action.notification)
|
||||
case notificationActions.NOTIFICATION_EMITTED:
|
||||
return state.map(notification =>
|
||||
notification.event.id === action.eventId
|
||||
? {
|
||||
...notification,
|
||||
notificationId: action.notificationId,
|
||||
isEmitted: true,
|
||||
buttonActions: action.buttonActions
|
||||
}
|
||||
: notification)
|
||||
case notificationActions.NOTIFICATION_CLICKED:
|
||||
return state.map(notification =>
|
||||
notification.notificationId === action.notificationId
|
||||
? { ...notification, isClicked: true, buttonIndex: action.buttonIndex }
|
||||
: notification)
|
||||
case notificationActions.NOTIFICATION_REMOVED:
|
||||
return state.filter(notification => notification.notificationId !== action.notificationId)
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
export default combineReducers({
|
||||
options: notificationOptionsReducer,
|
||||
unreadCount: unreadNotificationCountReducer,
|
||||
list: notificationListReducer
|
||||
})
|
|
@ -0,0 +1,73 @@
|
|||
import * as actions from 'actions/notificationActions'
|
||||
|
||||
export const extensionMessages = {
|
||||
popupOnLoad: 'SIA_EXTENSION_POPUP_ON_LOAD'
|
||||
}
|
||||
|
||||
export const isChromeExtension = () => typeof chrome !== 'undefined' &&
|
||||
typeof window !== 'undefined' &&
|
||||
chrome.extension != null &&
|
||||
chrome.extension.getBackgroundPage != null
|
||||
|
||||
export const isChromeExtensionBackground = () => isChromeExtension() &&
|
||||
chrome.extension.getBackgroundPage() === window
|
||||
|
||||
export const isChromeExtensionPopup = () => isChromeExtension() &&
|
||||
chrome.extension.getBackgroundPage() !== window
|
||||
|
||||
export const configureNotificationService = (dispatch) => {
|
||||
if (isChromeExtensionPopup()) {
|
||||
sendPopupLoadEvent()
|
||||
}
|
||||
|
||||
if (isChromeExtensionBackground()) {
|
||||
chrome.browserAction.setBadgeBackgroundColor({ color: '#FFB900' })
|
||||
registerExtensionListeners(dispatch)
|
||||
createContextMenus()
|
||||
}
|
||||
}
|
||||
|
||||
export const createContextMenus = () => {
|
||||
chrome.contextMenus.removeAll()
|
||||
chrome.contextMenus.create({
|
||||
id: actions.TOGGLE_RECEIVE_PUSH_NOTIFICATIONS,
|
||||
type: 'checkbox',
|
||||
checked: true,
|
||||
title: 'Receive Push Notifications',
|
||||
contexts: ['all']
|
||||
})
|
||||
}
|
||||
|
||||
export const sendPopupLoadEvent = () => {
|
||||
chrome.runtime.sendMessage({ messageId: extensionMessages.popupOnLoad })
|
||||
}
|
||||
|
||||
export const registerExtensionListeners = (dispatch) => {
|
||||
chrome.runtime.onMessage.addListener((request, sender) => {
|
||||
if (request.messageId === extensionMessages.popupOnLoad) {
|
||||
dispatch(actions.notificationsRead)
|
||||
}
|
||||
})
|
||||
|
||||
chrome.contextMenus.onClicked.addListener((info, tab) => {
|
||||
switch (info.menuItemId) {
|
||||
case actions.TOGGLE_RECEIVE_PUSH_NOTIFICATIONS:
|
||||
dispatch(actions.toggleReceivePushNotifications(info.checked))
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
chrome.notifications.onClicked.addListener((notificationId) => {
|
||||
dispatch(actions.notificationClicked(notificationId))
|
||||
})
|
||||
|
||||
chrome.notifications.onButtonClicked.addListener((notificationId, buttonIndex) => {
|
||||
dispatch(actions.notificationClicked(notificationId, buttonIndex))
|
||||
})
|
||||
|
||||
chrome.notifications.onClosed.addListener(notificationId => {
|
||||
dispatch(actions.notificationRemoved(notificationId))
|
||||
})
|
||||
}
|
После Ширина: | Высота: | Размер: 3.6 KiB |
После Ширина: | Высота: | Размер: 4.2 KiB |
После Ширина: | Высота: | Размер: 734 B |
После Ширина: | Высота: | Размер: 888 B |
После Ширина: | Высота: | Размер: 1.1 KiB |
После Ширина: | Высота: | Размер: 4.5 KiB |
После Ширина: | Высота: | Размер: 4.5 KiB |
После Ширина: | Высота: | Размер: 4.4 KiB |
|
@ -0,0 +1,170 @@
|
|||
import { expect } from 'chai'
|
||||
import React from 'react'
|
||||
import { shallow } from 'enzyme'
|
||||
import 'test/helpers/configureEnzyme'
|
||||
import { Notification } from 'components/Extension/Notification'
|
||||
|
||||
/* eslint-disable no-unused-expressions */
|
||||
describe('Notification component', function () {
|
||||
const originalWindow = global.window
|
||||
const originalChrome = global.chrome
|
||||
|
||||
after(function () {
|
||||
// Since we are messing with global objects we need to reset them back to the original
|
||||
// objects to avoid impacting other test suites.
|
||||
global.window = originalWindow
|
||||
global.chrome = originalChrome
|
||||
})
|
||||
|
||||
beforeEach(function () {
|
||||
global.window = {}
|
||||
global.chrome = {}
|
||||
})
|
||||
|
||||
const baseProps = {
|
||||
event: { id: 'eventId0' },
|
||||
actions: [],
|
||||
engagement: {},
|
||||
eventType: {},
|
||||
ticket: {}
|
||||
}
|
||||
|
||||
context('when not emitted yet', function () {
|
||||
it('should create a notification', function () {
|
||||
let notificationBodyResult
|
||||
global.chrome = {
|
||||
notifications: {
|
||||
create: notificationBody => { notificationBodyResult = notificationBody }
|
||||
}
|
||||
}
|
||||
shallow(<Notification {...baseProps} />)
|
||||
expect(notificationBodyResult).to.not.be.undefined
|
||||
})
|
||||
|
||||
it('should dispatch notificationEmitted', function () {
|
||||
global.chrome = {
|
||||
notifications: {
|
||||
create: (body, afterCreate) => { afterCreate('notificationId0') }
|
||||
}
|
||||
}
|
||||
let eventIdResult
|
||||
let notificationIdResult
|
||||
let buttonActionsResult
|
||||
|
||||
const props = {
|
||||
...baseProps,
|
||||
notificationEmitted: (eventId, notificationId, buttonActions) => {
|
||||
eventIdResult = eventId
|
||||
notificationIdResult = notificationId
|
||||
buttonActionsResult = buttonActions
|
||||
}
|
||||
}
|
||||
|
||||
shallow(<Notification {...props} />)
|
||||
expect(eventIdResult).to.equal('eventId0')
|
||||
expect(notificationIdResult).to.equal('notificationId0')
|
||||
expect(buttonActionsResult).to.not.be.undefined
|
||||
})
|
||||
|
||||
describe('createButtonActions', function () {
|
||||
it('should create two base actions if no playbook actions provided', function () {
|
||||
let notificationBodyResult
|
||||
global.chrome = {
|
||||
notifications: {
|
||||
create: (notificationBody, afterCreate) => {
|
||||
notificationBodyResult = notificationBody
|
||||
afterCreate('notificationId0')
|
||||
}
|
||||
}
|
||||
}
|
||||
let buttonActionsResult
|
||||
const props = {
|
||||
...baseProps,
|
||||
notificationEmitted: (eventId, notificationId, buttonActions) => {
|
||||
buttonActionsResult = buttonActions
|
||||
}
|
||||
}
|
||||
shallow(<Notification {...props} />)
|
||||
const notificationButtonTitles = notificationBodyResult.buttons.map(b => b.title)
|
||||
const buttonActionTitles = buttonActionsResult.map(b => b.title)
|
||||
expect(buttonActionsResult).to.have.lengthOf(2)
|
||||
expect(notificationBodyResult.buttons).to.have.lengthOf(2)
|
||||
expect(notificationButtonTitles).to.deep.equal(buttonActionTitles)
|
||||
})
|
||||
|
||||
it('should create at most two buttons based on the playbook actions provided', function () {
|
||||
let notificationBodyResult
|
||||
global.chrome = {
|
||||
notifications: {
|
||||
create: (notificationBody, afterCreate) => {
|
||||
notificationBodyResult = notificationBody
|
||||
afterCreate('notificationId0')
|
||||
}
|
||||
}
|
||||
}
|
||||
let buttonActionsResult
|
||||
const props = {
|
||||
...baseProps,
|
||||
notificationEmitted: (eventId, notificationId, buttonActions) => {
|
||||
buttonActionsResult = buttonActions
|
||||
},
|
||||
actions: [{
|
||||
actionTemplate: { name: 'actionTemplate0', isUrl: true },
|
||||
name: 'playbookAction0'
|
||||
}, {
|
||||
actionTemplate: { name: 'actionTemplate1', isUrl: true },
|
||||
name: 'playbookAction1'
|
||||
}]
|
||||
}
|
||||
shallow(<Notification {...props} />)
|
||||
const notificationButtonTitles = notificationBodyResult.buttons.map(b => b.title)
|
||||
const buttonActionTitles = buttonActionsResult.slice(0, 2).map(b => b.title)
|
||||
expect(buttonActionsResult).to.have.lengthOf(4)
|
||||
expect(notificationBodyResult.buttons).to.have.lengthOf(2)
|
||||
expect(notificationButtonTitles).to.deep.equal(buttonActionTitles)
|
||||
expect(notificationButtonTitles[0]).to.contain(props.actions[0].name)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('when emitted already', function () {
|
||||
it('should not create a notification', function () {
|
||||
let notificationBodyResult
|
||||
global.chrome = {
|
||||
notifications: {
|
||||
create: notificationBody => { notificationBodyResult = notificationBody }
|
||||
}
|
||||
}
|
||||
const props = {...baseProps, isEmitted: true}
|
||||
const shallowNotification = shallow(<Notification {...props} />)
|
||||
expect(shallowNotification.length).to.equal(1)
|
||||
expect(notificationBodyResult).to.be.undefined
|
||||
})
|
||||
})
|
||||
|
||||
context('when notification clicked', function () {
|
||||
const clickedProps = {
|
||||
...baseProps,
|
||||
isEmitted: true,
|
||||
isClicked: true,
|
||||
buttonActions: [{url: 'url0'}, {url: 'url1', default: true}, {url: 'url2'}]
|
||||
}
|
||||
|
||||
it('should open a new tab pointing to the button action url', function () {
|
||||
let urlResult
|
||||
global.chrome.tabs = { create: tab => { urlResult = tab.url } }
|
||||
shallow(<Notification {...{...clickedProps, buttonIndex: 0}} />)
|
||||
expect(urlResult).to.equal(clickedProps.buttonActions[0].url)
|
||||
shallow(<Notification {...{...clickedProps, buttonIndex: 2}} />)
|
||||
expect(urlResult).to.equal(clickedProps.buttonActions[2].url)
|
||||
})
|
||||
|
||||
it('should fallback to the default action url when clicked in body instead of button', function () {
|
||||
let urlResult
|
||||
global.chrome.tabs = { create: tab => { urlResult = tab.url } }
|
||||
shallow(<Notification {...clickedProps} />)
|
||||
const defaultActionUrl = clickedProps.buttonActions.find(buttonAction => buttonAction.default).url
|
||||
expect(urlResult).to.equal(defaultActionUrl)
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,167 @@
|
|||
import { expect } from 'chai'
|
||||
import * as reducer from 'reducers/notificationReducer'
|
||||
import * as actions from 'actions/notificationActions'
|
||||
|
||||
/* eslint-disable no-unused-expressions */
|
||||
describe('Chrome Extension Push Notifications Reducer', function () {
|
||||
describe('Notification Options Reducer', function () {
|
||||
it('should enable and disable the receivePushNotificationsEnabled flag', function () {
|
||||
const result = reducer.notificationOptionsReducer(undefined, {
|
||||
type: actions.TOGGLE_RECEIVE_PUSH_NOTIFICATIONS,
|
||||
enable: true
|
||||
})
|
||||
const result2 = reducer.notificationOptionsReducer(undefined, {
|
||||
type: actions.TOGGLE_RECEIVE_PUSH_NOTIFICATIONS,
|
||||
enable: false
|
||||
})
|
||||
|
||||
const result3 = reducer.notificationOptionsReducer({ receivePushNotificationsEnabled: true }, {
|
||||
type: actions.TOGGLE_RECEIVE_PUSH_NOTIFICATIONS,
|
||||
enable: false
|
||||
})
|
||||
|
||||
expect(result.receivePushNotificationsEnabled).to.be.true
|
||||
expect(result2.receivePushNotificationsEnabled).to.be.false
|
||||
expect(result3.receivePushNotificationsEnabled).to.be.false
|
||||
})
|
||||
})
|
||||
|
||||
describe('Unread Notification Count Reducer', function () {
|
||||
it('should increment unreadNotificationCount by one with every notification emitted', function () {
|
||||
const action = { type: actions.EMIT_NOTIFICATION }
|
||||
const result1 = reducer.unreadNotificationCountReducer(undefined, action)
|
||||
const result2 = reducer.unreadNotificationCountReducer(7, action)
|
||||
expect(result1).to.equal(1)
|
||||
expect(result2).to.equal(8)
|
||||
})
|
||||
|
||||
it('should reset to zero when notifications are read', function () {
|
||||
const action = { type: actions.NOTIFICATIONS_READ }
|
||||
const result1 = reducer.unreadNotificationCountReducer(undefined, action)
|
||||
const result2 = reducer.unreadNotificationCountReducer(7, action)
|
||||
expect(result1).to.equal(0)
|
||||
expect(result2).to.equal(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Notification List Reducer', function () {
|
||||
context('when emit is invoked', function () {
|
||||
it('should add the notification to the list', function () {
|
||||
const notification = {}
|
||||
const action = { type: actions.EMIT_NOTIFICATION, notification }
|
||||
const resultList1 = reducer.notificationListReducer(undefined, action)
|
||||
const resultList2 = reducer.notificationListReducer([{}, {}, {}], action)
|
||||
expect(resultList1).to.contain(notification)
|
||||
expect(resultList1).to.have.lengthOf(1)
|
||||
expect(resultList2).to.contain(notification)
|
||||
expect(resultList2).to.have.lengthOf(4)
|
||||
})
|
||||
})
|
||||
|
||||
context('when notification emitted', function () {
|
||||
it('should add the notification id', function () {
|
||||
const notification1 = { event: {id: 'Event1'} }
|
||||
const notification2 = { event: {id: 'Event2'} }
|
||||
const action = {
|
||||
type: actions.NOTIFICATION_EMITTED,
|
||||
eventId: notification1.event.id,
|
||||
notificationId: 'Notification1'
|
||||
}
|
||||
const resultList = reducer.notificationListReducer([notification1, notification2], action)
|
||||
const resultNotification1 = resultList.find(n => n.event.id === notification1.event.id)
|
||||
const resultNotification2 = resultList.find(n => n.event.id === notification2.event.id)
|
||||
expect(resultNotification1.notificationId).to.equal(action.notificationId)
|
||||
expect(resultNotification2.notificationId).to.be.undefined
|
||||
})
|
||||
|
||||
it('should set isEmitted to true', function () {
|
||||
const notification1 = { event: {id: 'Event1'} }
|
||||
const notification2 = { event: {id: 'Event2'} }
|
||||
const action = {
|
||||
type: actions.NOTIFICATION_EMITTED,
|
||||
eventId: notification1.event.id
|
||||
}
|
||||
const resultList = reducer.notificationListReducer([notification1, notification2], action)
|
||||
const resultNotification1 = resultList.find(n => n.event.id === notification1.event.id)
|
||||
const resultNotification2 = resultList.find(n => n.event.id === notification2.event.id)
|
||||
expect(resultNotification1.isEmitted).to.be.true
|
||||
expect(resultNotification2.isEmitted).to.not.be.true
|
||||
})
|
||||
|
||||
it('should add the action buttons', function () {
|
||||
const buttonActions = {}
|
||||
const notification1 = { event: {id: 'Event1'} }
|
||||
const notification2 = { event: {id: 'Event2'} }
|
||||
const action = {
|
||||
type: actions.NOTIFICATION_EMITTED,
|
||||
eventId: notification1.event.id,
|
||||
buttonActions
|
||||
}
|
||||
const resultList = reducer.notificationListReducer([notification1, notification2], action)
|
||||
const resultNotification1 = resultList.find(n => n.event.id === notification1.event.id)
|
||||
const resultNotification2 = resultList.find(n => n.event.id === notification2.event.id)
|
||||
expect(resultNotification1.buttonActions).to.equal(buttonActions)
|
||||
expect(resultNotification2.buttonActions).to.not.equal(buttonActions)
|
||||
})
|
||||
})
|
||||
|
||||
context('when notification clicked', function () {
|
||||
it('should set isClicked to true', function () {
|
||||
const notification1 = { notificationId: 'Notification1' }
|
||||
const notification2 = { notificationId: 'Notification2' }
|
||||
const action = {
|
||||
type: actions.NOTIFICATION_CLICKED,
|
||||
notificationId: notification1.notificationId,
|
||||
buttonIndex: 0
|
||||
}
|
||||
const resultList = reducer.notificationListReducer([notification1, notification2], action)
|
||||
const resultNotification1 = resultList.find(n => n.notificationId === notification1.notificationId)
|
||||
const resultNotification2 = resultList.find(n => n.notificationId === notification2.notificationId)
|
||||
expect(resultNotification1.isClicked).to.be.true
|
||||
expect(resultNotification2.isClicked).to.not.be.true
|
||||
})
|
||||
|
||||
it('should set the proper button index', function () {
|
||||
const notification1 = { notificationId: 'Notification1' }
|
||||
const notification2 = { notificationId: 'Notification2' }
|
||||
const action1 = {
|
||||
type: actions.NOTIFICATION_CLICKED,
|
||||
notificationId: notification1.notificationId,
|
||||
buttonIndex: 0
|
||||
}
|
||||
const action2 = {
|
||||
type: actions.NOTIFICATION_CLICKED,
|
||||
notificationId: notification2.notificationId,
|
||||
buttonIndex: 1
|
||||
}
|
||||
|
||||
const resultList1 = reducer.notificationListReducer([notification1, notification2], action1)
|
||||
const resultList2 = reducer.notificationListReducer(resultList1, action2)
|
||||
|
||||
const result1Notification1 = resultList1.find(n => n.notificationId === notification1.notificationId)
|
||||
const result1Notification2 = resultList1.find(n => n.notificationId === notification2.notificationId)
|
||||
const result2Notification1 = resultList2.find(n => n.notificationId === notification1.notificationId)
|
||||
const result2Notification2 = resultList2.find(n => n.notificationId === notification2.notificationId)
|
||||
expect(result1Notification1.buttonIndex).to.equal(action1.buttonIndex)
|
||||
expect(result1Notification2.buttonIndex).to.be.undefined
|
||||
expect(result2Notification1.buttonIndex).to.equal(action1.buttonIndex)
|
||||
expect(result2Notification2.buttonIndex).to.equal(action2.buttonIndex)
|
||||
})
|
||||
})
|
||||
|
||||
context('when notification removed', function () {
|
||||
it('should be eliminated from the list', function () {
|
||||
const notification1 = { notificationId: 'Notification1' }
|
||||
const notification2 = { notificationId: 'Notification2' }
|
||||
const action = {
|
||||
type: actions.NOTIFICATION_REMOVED,
|
||||
notificationId: notification1.notificationId
|
||||
}
|
||||
const resultList = reducer.notificationListReducer([notification1, notification2], action)
|
||||
expect(resultList).to.not.contain(notification1)
|
||||
expect(resultList).to.contain(notification2)
|
||||
expect(resultList).to.have.lengthOf(1)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -0,0 +1,122 @@
|
|||
import { expect } from 'chai'
|
||||
import * as service from 'services/notificationService'
|
||||
import * as actions from 'actions/notificationActions'
|
||||
|
||||
/* eslint-disable no-unused-expressions */
|
||||
describe('Chrome Extension Push Notifications Service', function () {
|
||||
const originalWindow = global.window
|
||||
const originalChrome = global.chrome
|
||||
|
||||
after(function () {
|
||||
// Since we are messing with global objects we need to reset them back to the original
|
||||
// objects to avoid impacting other test suites.
|
||||
global.window = originalWindow
|
||||
global.chrome = originalChrome
|
||||
})
|
||||
|
||||
beforeEach(function () {
|
||||
global.window = {}
|
||||
global.chrome = {}
|
||||
})
|
||||
|
||||
context('when there is no chrome.extension object', function () {
|
||||
it('should not be considered a chrome extension', () => {
|
||||
const isChromeExtensionResult = service.isChromeExtension()
|
||||
expect(isChromeExtensionResult).to.be.false
|
||||
})
|
||||
})
|
||||
|
||||
context('when running as a chrome extension', function () {
|
||||
beforeEach(function () {
|
||||
global.chrome = { extension: { getBackgroundPage: () => null } }
|
||||
})
|
||||
|
||||
it('should be considered a chrome extension', () => {
|
||||
const isChromeExtensionResult = service.isChromeExtension()
|
||||
expect(isChromeExtensionResult).to.be.true
|
||||
})
|
||||
|
||||
context('when running as a chrome extension background', function () {
|
||||
beforeEach(function () {
|
||||
global.chrome = {
|
||||
extension: { getBackgroundPage: () => global.window },
|
||||
browserAction: { setBadgeBackgroundColor: () => null },
|
||||
runtime: { onMessage: { addListener: () => null } },
|
||||
contextMenus: {
|
||||
onClicked: { addListener: () => null },
|
||||
create: () => null,
|
||||
removeAll: () => null
|
||||
},
|
||||
notifications: {
|
||||
onClicked: { addListener: () => null },
|
||||
onButtonClicked: { addListener: () => null },
|
||||
onClosed: { addListener: () => null }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('should be considered a chrome extension background', () => {
|
||||
const isChromeExtensionBackgroundResult = service.isChromeExtensionBackground()
|
||||
expect(isChromeExtensionBackgroundResult).to.be.true
|
||||
})
|
||||
|
||||
it('should not be considered a chrome extension popup', () => {
|
||||
const isChromeExtensionPopupResult = service.isChromeExtensionPopup()
|
||||
expect(isChromeExtensionPopupResult).to.be.false
|
||||
})
|
||||
|
||||
it('should register chrome event listeners', () => {
|
||||
let runtimeOnMessageListenerAdded = false
|
||||
let contextMenusOnClickedListenerAdded = false
|
||||
let notificationsOnClickedListenerAdded = false
|
||||
let notificationsOnButtonClickedListenerAdded = false
|
||||
let notificationsOnClosedListenerAdded = false
|
||||
global.chrome.runtime.onMessage.addListener = () => { runtimeOnMessageListenerAdded = true }
|
||||
global.chrome.contextMenus.onClicked.addListener = () => { contextMenusOnClickedListenerAdded = true }
|
||||
global.chrome.notifications = {
|
||||
onClicked: { addListener: () => { notificationsOnClickedListenerAdded = true } },
|
||||
onButtonClicked: { addListener: () => { notificationsOnButtonClickedListenerAdded = true } },
|
||||
onClosed: { addListener: () => { notificationsOnClosedListenerAdded = true } }
|
||||
}
|
||||
|
||||
service.configureNotificationService()
|
||||
|
||||
expect(runtimeOnMessageListenerAdded).to.be.true
|
||||
expect(contextMenusOnClickedListenerAdded).to.be.true
|
||||
expect(notificationsOnClickedListenerAdded).to.be.true
|
||||
expect(notificationsOnButtonClickedListenerAdded).to.be.true
|
||||
expect(notificationsOnClosedListenerAdded).to.be.true
|
||||
})
|
||||
|
||||
it('should create a context menu option to toggle receive push notifications', function () {
|
||||
const menuIdsResult = []
|
||||
global.chrome.contextMenus.create = (options) => { menuIdsResult.push(options.id) }
|
||||
service.configureNotificationService()
|
||||
expect(menuIdsResult).to.include(actions.TOGGLE_RECEIVE_PUSH_NOTIFICATIONS)
|
||||
})
|
||||
})
|
||||
|
||||
context('when running as a chrome extension popup', function () {
|
||||
beforeEach(function () {
|
||||
global.chrome = { extension: { getBackgroundPage: () => {} } }
|
||||
})
|
||||
|
||||
it('should be considered a chrome extension popup', () => {
|
||||
const isChromeExtensionPopupResult = service.isChromeExtensionPopup()
|
||||
expect(isChromeExtensionPopupResult).to.be.true
|
||||
})
|
||||
|
||||
it('should not be considered a chrome extension background', () => {
|
||||
const isChromeExtensionBackgroundResult = service.isChromeExtensionBackground()
|
||||
expect(isChromeExtensionBackgroundResult).to.be.false
|
||||
})
|
||||
|
||||
it('should send a popupOnLoad message', () => {
|
||||
let msgIdResults = []
|
||||
global.chrome.runtime = { sendMessage: msg => { msgIdResults.push(msg.messageId) } }
|
||||
service.configureNotificationService()
|
||||
expect(msgIdResults).to.include(service.extensionMessages.popupOnLoad)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|