зеркало из https://github.com/Azure/Sia-EventUI.git
Merge branch 'master' into yizha/removeAlias
This commit is contained in:
Коммит
e912bd4e1b
18
.babelrc
18
.babelrc
|
@ -1,12 +1,26 @@
|
|||
{
|
||||
"presets": [
|
||||
["env", { "modules": false }],
|
||||
["env"],
|
||||
"react"
|
||||
],
|
||||
"env": {
|
||||
"test": {
|
||||
"plugins": [
|
||||
"istanbul"
|
||||
]
|
||||
}
|
||||
},
|
||||
"plugins": [
|
||||
"transform-object-rest-spread",
|
||||
"syntax-class-properties",
|
||||
"transform-class-properties",
|
||||
"react-hot-loader/babel"
|
||||
"react-hot-loader/babel",
|
||||
["module-resolver", {
|
||||
"root": ["./src"],
|
||||
"alias": {
|
||||
"cfg": "./cfg",
|
||||
"test": "./test"
|
||||
}
|
||||
}]
|
||||
]
|
||||
}
|
||||
|
|
36
.eslintrc
36
.eslintrc
|
@ -1,36 +0,0 @@
|
|||
{
|
||||
"parser": "babel-eslint",
|
||||
"plugins": [
|
||||
"react"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"amd": true,
|
||||
"es6": true,
|
||||
"node": true,
|
||||
"mocha": true
|
||||
},
|
||||
"rules": {
|
||||
"comma-dangle": 1,
|
||||
"quotes": [ 1, "single" ],
|
||||
"no-undef": 1,
|
||||
"global-strict": 0,
|
||||
"no-extra-semi": 1,
|
||||
"no-underscore-dangle": 0,
|
||||
"no-console": 1,
|
||||
"no-unused-vars": 1,
|
||||
"no-trailing-spaces": [1, { "skipBlankLines": true }],
|
||||
"no-unreachable": 1,
|
||||
"no-alert": 0,
|
||||
"react/jsx-uses-react": 1,
|
||||
"react/jsx-uses-vars": 1,
|
||||
"semi": ["error", "never"]
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ lib-cov
|
|||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
.nyc_output/
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
@ -39,4 +40,4 @@ bower_components/
|
|||
temp
|
||||
|
||||
# Configuration constants files
|
||||
/cfg/*.const.js
|
||||
/cfg/*.const.js
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- "lts/*"
|
||||
- "lts/*"
|
||||
after_success:
|
||||
- npm install -g codecov codacy-coverage coveralls
|
||||
- codecov
|
||||
- cat ./coverage/lcov.info | codacy-coverage
|
||||
- cat ./coverage/lcov.info | coveralls
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"generator-react-webpack": {}
|
||||
}
|
|
@ -1,4 +1,9 @@
|
|||
[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Azure/Sia-EventUI/blob/master/LICENSE)
|
||||
[![Build Status](https://travis-ci.org/Azure/Sia-EventUI.svg?branch=master)](https://travis-ci.org/Azure/Sia-EventUI)
|
||||
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/10fae239209f4123b8277ef78fbcd195)](https://www.codacy.com/app/SIA/Azure-Sia-EventUI?utm_source=github.com&utm_medium=referral&utm_content=Azure/Sia-EventUI&utm_campaign=Badge_Grade)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/Azure/Sia-EventUI/badge.svg?branch=master)](https://coveralls.io/github/Azure/Sia-EventUI?branch=master)
|
||||
[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
|
||||
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/Azure/Sia-Root/blob/master/HOWTOCONTRIBUTE.md)
|
||||
|
||||
# This is the user interface for SRE Incident Assistant (SIA)
|
||||
See the [Root repository](https://github.com/azure/Sia-Root) for full project information.
|
||||
|
|
67
app.js
67
app.js
|
@ -1,40 +1,39 @@
|
|||
const express = require('express');
|
||||
const path = require('path');
|
||||
const app = express();
|
||||
const express = require('express')
|
||||
const path = require('path')
|
||||
const app = express()
|
||||
|
||||
if (process.env.NODE_ENV !== 'dist') {
|
||||
const webpackDevMiddleware = require('webpack-dev-middleware')
|
||||
const webpackHotMiddleware = require('webpack-hot-middleware')
|
||||
const webpack = require('webpack')
|
||||
const webpackConfig = require('./webpack.config')
|
||||
const compiler = webpack(webpackConfig)
|
||||
app.use(webpackDevMiddleware(compiler, {
|
||||
hot: true,
|
||||
filename: 'app.js',
|
||||
publicPath: '/assets/',
|
||||
stats: {
|
||||
colors: true
|
||||
},
|
||||
historyApiFallback: true
|
||||
}))
|
||||
|
||||
if (process.env.NODE_ENV != 'dist') {
|
||||
const webpackDevMiddleware = require('webpack-dev-middleware');
|
||||
const webpackHotMiddleware = require('webpack-hot-middleware');
|
||||
const webpack = require('webpack');
|
||||
const webpackConfig = require('./webpack.config');
|
||||
const compiler = webpack(webpackConfig);
|
||||
app.use(webpackDevMiddleware(compiler, {
|
||||
hot: true,
|
||||
filename: 'app.js',
|
||||
publicPath: '/assets/',
|
||||
stats: {
|
||||
colors: true,
|
||||
},
|
||||
historyApiFallback: true,
|
||||
}));
|
||||
|
||||
app.use(webpackHotMiddleware(compiler, {
|
||||
log: console.log,
|
||||
path: '/__webpack_hmr',
|
||||
heartbeat: 10 * 1000,
|
||||
}));
|
||||
app.get('*', function (req, res) {
|
||||
res.sendFile(path.join(__dirname + '/src/index.html'));
|
||||
});
|
||||
app.use(webpackHotMiddleware(compiler, {
|
||||
log: console.log,
|
||||
path: '/__webpack_hmr',
|
||||
heartbeat: 10 * 1000
|
||||
}))
|
||||
app.get('*', function (req, res) {
|
||||
res.sendFile(path.join(__dirname, '/src/index.html'))
|
||||
})
|
||||
} else {
|
||||
const DIST_DIR = path.join(__dirname, 'dist'),
|
||||
HTML_FILE = path.join(DIST_DIR, 'index.html');
|
||||
const DIST_DIR = path.join(__dirname, 'dist')
|
||||
const HTML_FILE = path.join(DIST_DIR, 'index.html')
|
||||
|
||||
app.use(express.static(DIST_DIR));
|
||||
app.get('*', function (req, res) {
|
||||
res.sendFile(HTML_FILE);
|
||||
});
|
||||
app.use(express.static(DIST_DIR))
|
||||
app.get('*', function (req, res) {
|
||||
res.sendFile(HTML_FILE)
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = app;
|
||||
module.exports = app
|
||||
|
|
|
@ -39,18 +39,12 @@ const config = {
|
|||
sources: `${srcPath}/sources/`,
|
||||
stores: `${srcPath}/stores/`,
|
||||
styles: `${srcPath}/styles/`,
|
||||
config: `${srcPath}/config/${env}`,
|
||||
config: `${srcPath}/config/`,
|
||||
'react/lib/ReactMount': 'react-dom/lib/ReactMount'
|
||||
}
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
enforce: 'pre',
|
||||
test: /\.(js|jsx)$/,
|
||||
include: srcPath,
|
||||
loader: 'eslint-loader'
|
||||
},
|
||||
{
|
||||
test: /\.(js|jsx)$/,
|
||||
loader: 'babel-loader',
|
||||
|
|
|
@ -8,12 +8,10 @@ let defaultConstants = require('./defaultConstants')
|
|||
You'll probably want this if you commit your code to a public repo.
|
||||
*/
|
||||
module.exports = Object.assign({}, defaultConstants, {
|
||||
baseUrl: JSON.stringify("http://localhost:60000/"), //Host on a different port
|
||||
retries: 4 //retry failed requests more times before giving up
|
||||
baseUrl: JSON.stringify('http://localhost:60000/'), // Host on a different port
|
||||
retries: 4 // retry failed requests more times before giving up
|
||||
})
|
||||
|
||||
|
||||
|
||||
/* Defaults Only: Copy this to a new file to create const file that just uses default constants.
|
||||
let defaultConstants = require('./defaultConstants')
|
||||
|
||||
|
|
|
@ -3,11 +3,13 @@
|
|||
$s = "let baseConstants = require('./defaultConstants')
|
||||
|
||||
module.exports = Object.assign({}, baseConstants, {
|
||||
appEnv: 'dist',
|
||||
aadInstance: '${env:aadInstance}',
|
||||
aadTenant: '$env:aadTenant',
|
||||
clientId: '$env:clientId',
|
||||
baseUrl: '$env:baseUrl',
|
||||
authRedirectUri: '$env:authRedirectUri',
|
||||
authVersion: 'ADAL', // TODO: Add env var
|
||||
ticketSystems: {
|
||||
1: {
|
||||
id: 1,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
module.exports = {
|
||||
|
||||
appEnv: 'test',
|
||||
|
||||
baseUrl: 'http://localhost:50000/',
|
||||
|
||||
authRedirectUri: 'http://localhost:3000/',
|
||||
|
@ -14,7 +16,7 @@ module.exports = {
|
|||
|
||||
ticketRefreshIntervalInSeconds: 300,
|
||||
|
||||
authVersion: 'ADAL',
|
||||
authVersion: 'TEST',
|
||||
|
||||
// Leave this as is if your code is in a public repo (or delete it if you want).
|
||||
// You can override the defaults with the real information in your cfg/$env.const.js file.
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -8,7 +8,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">APPLICATION CONTENT</div>
|
||||
<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>
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"*": ["src/*"],
|
||||
"test/*": ["test/*"],
|
||||
"cfg/*": ["cfg/*"]
|
||||
},
|
||||
"experimentalDecorators": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"target": "esnext"
|
||||
},
|
||||
"exclude": [
|
||||
"dist/*",
|
||||
"coverage/*",
|
||||
"temp/*"
|
||||
]
|
||||
}
|
|
@ -1,23 +1,23 @@
|
|||
var webpackCfg = require('./cfg/test');
|
||||
var webpackCfg = require('./cfg/test')
|
||||
|
||||
// Set node environment to testing
|
||||
process.env.NODE_ENV = 'test';
|
||||
process.env.NODE_ENV = 'test'
|
||||
|
||||
module.exports = function(config) {
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
browsers: [ 'PhantomJS' ],
|
||||
files: [
|
||||
'test/loadtests.js',
|
||||
{pattern: 'test/**/*Test.js', included: false},
|
||||
{pattern: 'test/**/*Helper.js', included: false},
|
||||
//{pattern: 'src/**/*.js', included: false},
|
||||
//'_karma_webpack_/loadtests.js',
|
||||
//'_karma_webpack_/**/*Test.js',
|
||||
//'_karma_webpack_/**/*Helper.js',
|
||||
//'test/loadtests.processed.js',
|
||||
//'test/**/*Test.processed.js',
|
||||
//'test/**/*Helper.processed.js'
|
||||
{pattern: 'test/**/*Helper.js', included: false}
|
||||
// {pattern: 'src/**/*.js', included: false},
|
||||
// '_karma_webpack_/loadtests.js',
|
||||
// '_karma_webpack_/**/*Test.js',
|
||||
// '_karma_webpack_/**/*Helper.js',
|
||||
// 'test/loadtests.processed.js',
|
||||
// 'test/**/*Test.processed.js',
|
||||
// 'test/**/*Helper.processed.js'
|
||||
],
|
||||
exclude: [
|
||||
'src/index.js'
|
||||
|
@ -46,5 +46,5 @@ module.exports = function(config) {
|
|||
{ type: 'text' }
|
||||
]
|
||||
}
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
84
package.json
84
package.json
|
@ -8,7 +8,8 @@
|
|||
"clean": "rimraf dist/*",
|
||||
"copy": "copyfiles -f ./src/index.html ./src/favicon.ico ./dist",
|
||||
"dist": "npm run copy & webpack --env=dist",
|
||||
"lint": "eslint ./src",
|
||||
"lint": "standard \"src/**/*.js\"",
|
||||
"lint:fix": "standard --fix \"src/**/*.js\"",
|
||||
"posttest": "npm run lint",
|
||||
"release:major": "npm version major && npm publish && git push --follow-tags",
|
||||
"release:minor": "npm version minor && npm publish && git push --follow-tags",
|
||||
|
@ -16,9 +17,39 @@
|
|||
"serve": "node server.js --env=dev",
|
||||
"serve:dist": "cross-env NODE_ENV=dist node server.js",
|
||||
"start": "node server.js --env=localhost",
|
||||
"test": "webpack --env=test",
|
||||
"test": "nyc cross-env NODE_ENV=test mocha",
|
||||
"test:watch": "karma start --autoWatch=true --singleRun=false"
|
||||
},
|
||||
"nyc": {
|
||||
"reporter": [
|
||||
"text",
|
||||
"text-summary",
|
||||
"lcov",
|
||||
"html"
|
||||
],
|
||||
"include": [
|
||||
"src/**/*.js"
|
||||
],
|
||||
"require": [
|
||||
"babel-register"
|
||||
],
|
||||
"sourceMap": false,
|
||||
"instrument": false,
|
||||
"all": true
|
||||
},
|
||||
"standard": {
|
||||
"parser": "babel-eslint",
|
||||
"env": [
|
||||
"mocha",
|
||||
"chai"
|
||||
],
|
||||
"globals": [
|
||||
"fetch",
|
||||
"Headers",
|
||||
"propTypes",
|
||||
"chrome"
|
||||
]
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Azure/Sia-EventUI.git"
|
||||
|
@ -33,28 +64,25 @@
|
|||
},
|
||||
"homepage": "https://github.com/Azure/Sia-EventUI#readme",
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.26.0",
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-eslint": "^8.0.3",
|
||||
"babel-loader": "^7.1.2",
|
||||
"babel-plugin-istanbul": "^4.1.5",
|
||||
"babel-plugin-module-resolver": "^3.0.0",
|
||||
"babel-plugin-transform-async-to-generator": "^6.24.1",
|
||||
"babel-plugin-transform-es2015-modules-umd": "^6.24.1",
|
||||
"babel-plugin-transform-object-rest-spread": "^6.26.0",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"browserify": "^14.5.0",
|
||||
"babel-register": "^6.26.0",
|
||||
"chai": "^4.1.2",
|
||||
"copyfiles": "^1.2.0",
|
||||
"core-js": "^2.5.3",
|
||||
"cross-env": "^5.1.3",
|
||||
"css-loader": "^0.28.7",
|
||||
"deep-equal": "^1.0.1",
|
||||
"eslint": "^4.13.1",
|
||||
"eslint-loader": "^1.9.0",
|
||||
"eslint-plugin-react": "^7.5.1",
|
||||
"file-loader": "^1.1.6",
|
||||
"karma": "^1.7.1",
|
||||
"karma": "^2.0.0",
|
||||
"karma-babel-preprocessor": "^7.0.0",
|
||||
"karma-browserify": "^5.1.2",
|
||||
"karma-chai": "^0.1.0",
|
||||
"karma-coverage": "^1.1.1",
|
||||
"karma-mocha": "^1.3.0",
|
||||
|
@ -62,27 +90,17 @@
|
|||
"karma-phantomjs-launcher": "^1.0.4",
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-webpack": "^2.0.9",
|
||||
"material-ui": "^0.20.0",
|
||||
"minimist": "^1.2.0",
|
||||
"mocha": "^4.0.1",
|
||||
"moment": "^2.20.1",
|
||||
"mocha": "^4.1.0",
|
||||
"nyc": "^11.4.1",
|
||||
"prop-types": "^15.6.0",
|
||||
"react": "^16.2.0",
|
||||
"react-addons-test-utils": "^15.6.2",
|
||||
"react-dom": "^16.2.0",
|
||||
"react-redux": "^5.0.6",
|
||||
"react-router": "^4.2.0",
|
||||
"react-router-dom": "^4.2.2",
|
||||
"react-tap-event-plugin": "^3.0.2",
|
||||
"react-test-renderer": "^16.2.0",
|
||||
"redux": "^3.7.2",
|
||||
"rimraf": "^2.6.2",
|
||||
"standard": "^10.0.3",
|
||||
"style-loader": "^0.19.1",
|
||||
"uglifyjs-webpack-plugin": "1.1.4",
|
||||
"uglifyjs-webpack-plugin": "1.1.6",
|
||||
"url-loader": "^0.6.2",
|
||||
"webpack": "^3.10.0",
|
||||
"webpack-dev-middleware": "^2.0.2",
|
||||
"webpack-dev-server": "^2.9.7",
|
||||
"webpack-hot-middleware": "^2.21.0",
|
||||
"webpack-node-externals": "^1.6.0",
|
||||
"webpack-shell-plugin": "^0.5.0"
|
||||
|
@ -90,15 +108,29 @@
|
|||
"dependencies": {
|
||||
"@aspnet/signalr-client": "^1.0.0-alpha2-final",
|
||||
"adal-angular": "^1.0.16",
|
||||
"babel-eslint": "^8.0.3",
|
||||
"babel-plugin-syntax-class-properties": "^6.13.0",
|
||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||
"cross-env": "^5.1.1",
|
||||
"codacy-coverage": "^2.0.3",
|
||||
"deep-equal": "^1.0.1",
|
||||
"express": "^4.16.2",
|
||||
"material-ui": "^0.20.0",
|
||||
"mocha-lcov-reporter": "^1.3.0",
|
||||
"moment": "^2.20.1",
|
||||
"msal": "^0.1.3",
|
||||
"object-path": "^0.11.4",
|
||||
"paginated-redux": "^0.2.2",
|
||||
"promise-retry": "^1.1.1",
|
||||
"query-string": "^5.0.1",
|
||||
"react": "^16.2.0",
|
||||
"react-dom": "^16.2.0",
|
||||
"react-hot-loader": "^3.1.3",
|
||||
"react-redux": "^5.0.6",
|
||||
"react-router": "^4.2.0",
|
||||
"react-router-dom": "^4.2.2",
|
||||
"react-tap-event-plugin": "^3.0.2",
|
||||
"react-test-renderer": "^16.2.0",
|
||||
"redux": "^3.7.2",
|
||||
"redux-mock-store": "^1.3.0",
|
||||
"redux-persist": "^5.4.0",
|
||||
"redux-persist-transform-filter": "0.0.16",
|
||||
|
|
56
server.js
56
server.js
|
@ -4,76 +4,76 @@
|
|||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var app = require('./app');
|
||||
var debug = require('debug')('nodejs-get-started:server');
|
||||
var http = require('http');
|
||||
var app = require('./app')
|
||||
var debug = require('debug')('nodejs-get-started:server')
|
||||
var http = require('http')
|
||||
|
||||
/**
|
||||
* Get port from environment and store in Express.
|
||||
*/
|
||||
|
||||
var port = normalizePort(process.env.PORT || '3000');
|
||||
app.set('port', port);
|
||||
var port = normalizePort(process.env.PORT || '3000')
|
||||
app.set('port', port)
|
||||
|
||||
/**
|
||||
* Create HTTP server.
|
||||
*/
|
||||
|
||||
var server = http.createServer(app);
|
||||
var server = http.createServer(app)
|
||||
|
||||
/**
|
||||
* Listen on provided port, on all network interfaces.
|
||||
*/
|
||||
|
||||
server.listen(port);
|
||||
server.on('error', onError);
|
||||
server.on('listening', onListening);
|
||||
server.listen(port)
|
||||
server.on('error', onError)
|
||||
server.on('listening', onListening)
|
||||
|
||||
/**
|
||||
* Normalize a port into a number, string, or false.
|
||||
*/
|
||||
|
||||
function normalizePort(val) {
|
||||
var port = parseInt(val, 10);
|
||||
function normalizePort (val) {
|
||||
var port = parseInt(val, 10)
|
||||
|
||||
if (isNaN(port)) {
|
||||
// named pipe
|
||||
return val;
|
||||
return val
|
||||
}
|
||||
|
||||
if (port >= 0) {
|
||||
// port number
|
||||
return port;
|
||||
return port
|
||||
}
|
||||
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Event listener for HTTP server "error" event.
|
||||
*/
|
||||
|
||||
function onError(error) {
|
||||
function onError (error) {
|
||||
if (error.syscall !== 'listen') {
|
||||
throw error;
|
||||
throw error
|
||||
}
|
||||
|
||||
var bind = typeof port === 'string'
|
||||
? 'Pipe ' + port
|
||||
: 'Port ' + port;
|
||||
: 'Port ' + port
|
||||
|
||||
// handle specific listen errors with friendly messages
|
||||
switch (error.code) {
|
||||
case 'EACCES':
|
||||
console.error(bind + ' requires elevated privileges');
|
||||
process.exit(1);
|
||||
break;
|
||||
console.error(bind + ' requires elevated privileges')
|
||||
process.exit(1)
|
||||
break
|
||||
case 'EADDRINUSE':
|
||||
console.error(bind + ' is already in use');
|
||||
process.exit(1);
|
||||
break;
|
||||
console.error(bind + ' is already in use')
|
||||
process.exit(1)
|
||||
break
|
||||
default:
|
||||
throw error;
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,10 +81,10 @@ function onError(error) {
|
|||
* Event listener for HTTP server "listening" event.
|
||||
*/
|
||||
|
||||
function onListening() {
|
||||
var addr = server.address();
|
||||
function onListening () {
|
||||
var addr = server.address()
|
||||
var bind = typeof addr === 'string'
|
||||
? 'pipe ' + addr
|
||||
: 'port ' + addr.port;
|
||||
debug('Listening on ' + bind);
|
||||
: 'port ' + addr.port
|
||||
debug('Listening on ' + bind)
|
||||
}
|
||||
|
|
|
@ -1,29 +1,31 @@
|
|||
import { authenticatedFetch, authenticatedPost, authenticatedPut } from '../services/authenticatedFetch'
|
||||
import { authenticatedFetch, authenticatedPost, authenticatedPut } from 'services/authenticatedFetch'
|
||||
|
||||
const needOnActionSet = (prop) => `Need "${prop}" function on actionSet!`
|
||||
|
||||
export const reduxBackedPromise = (promiseArgs, actionSet, operation = 'GET') => (dispatch) => {
|
||||
if(!actionSet.try) { throw needOnActionSet('try')}
|
||||
if(!actionSet.succeed) { throw needOnActionSet('succeed')}
|
||||
if(!actionSet.fail) { throw needOnActionSet('fail')}
|
||||
if (!actionSet.try) { throw needOnActionSet('try') }
|
||||
if (!actionSet.succeed) { throw needOnActionSet('succeed') }
|
||||
if (!actionSet.fail) { throw needOnActionSet('fail') }
|
||||
|
||||
let promiseGenerator
|
||||
switch (operation.toUpperCase()) {
|
||||
case 'PUT':
|
||||
promiseGenerator = authenticatedPut
|
||||
break
|
||||
case 'POST':
|
||||
promiseGenerator = authenticatedPost
|
||||
break
|
||||
default:
|
||||
promiseGenerator = authenticatedFetch
|
||||
break
|
||||
}
|
||||
if(!promiseGenerator) { throw 'promiseGenerator not initialized. This should not be possible. Consider rolling back.' }
|
||||
let promiseGenerator
|
||||
switch (operation.toUpperCase()) {
|
||||
case 'PUT':
|
||||
promiseGenerator = authenticatedPut
|
||||
break
|
||||
case 'POST':
|
||||
promiseGenerator = authenticatedPost
|
||||
break
|
||||
default:
|
||||
promiseGenerator = authenticatedFetch
|
||||
break
|
||||
}
|
||||
if (!promiseGenerator) {
|
||||
throw new Error('promiseGenerator not initialized. This should not be possible. Consider rolling back.')
|
||||
}
|
||||
|
||||
dispatch(actionSet.try())
|
||||
dispatch(actionSet.try())
|
||||
|
||||
return promiseGenerator(dispatch, ...promiseArgs)
|
||||
return promiseGenerator(dispatch, ...promiseArgs)
|
||||
.then(({json, response}) => dispatch(actionSet.succeed(json, response)),
|
||||
error => dispatch(actionSet.fail(error)))
|
||||
}
|
||||
|
@ -35,39 +37,39 @@ const sortActionType = (BASE_NAME) => 'SORT_' + BASE_NAME
|
|||
const filterActionType = (BASE_NAME) => 'FILTER_' + BASE_NAME
|
||||
|
||||
export const paginationActions = (BASE_NAME) => ({
|
||||
types: {
|
||||
GOTO_PAGE: goToPageActionType(BASE_NAME),
|
||||
NEXT_PAGE: nextPageActionType(BASE_NAME),
|
||||
PREV_PAGE: prevPageActionType(BASE_NAME),
|
||||
SORT: sortActionType(BASE_NAME),
|
||||
FILTER: filterActionType(BASE_NAME)
|
||||
},
|
||||
types: {
|
||||
GOTO_PAGE: goToPageActionType(BASE_NAME),
|
||||
NEXT_PAGE: nextPageActionType(BASE_NAME),
|
||||
PREV_PAGE: prevPageActionType(BASE_NAME),
|
||||
SORT: sortActionType(BASE_NAME),
|
||||
FILTER: filterActionType(BASE_NAME)
|
||||
},
|
||||
|
||||
goToPage: (page) => ({
|
||||
type: goToPageActionType(BASE_NAME),
|
||||
page
|
||||
}),
|
||||
goToPage: (page) => ({
|
||||
type: goToPageActionType(BASE_NAME),
|
||||
page
|
||||
}),
|
||||
|
||||
nextPage: () => ({
|
||||
type: nextPageActionType(BASE_NAME)
|
||||
}),
|
||||
nextPage: () => ({
|
||||
type: nextPageActionType(BASE_NAME)
|
||||
}),
|
||||
|
||||
sort: (by) => ({
|
||||
type: sortActionType(BASE_NAME),
|
||||
by
|
||||
}),
|
||||
sort: (by) => ({
|
||||
type: sortActionType(BASE_NAME),
|
||||
by
|
||||
}),
|
||||
|
||||
filter: (filter) => ({
|
||||
type: filterActionType(BASE_NAME),
|
||||
filter
|
||||
})
|
||||
filter: (filter) => ({
|
||||
type: filterActionType(BASE_NAME),
|
||||
filter
|
||||
})
|
||||
})
|
||||
|
||||
/*Update pagination does nothing on its own, but activates
|
||||
/* Update pagination does nothing on its own, but activates
|
||||
the default case of pagination reducers created by paginated-redux,
|
||||
which forces re-evaluation of the current page; simply adding
|
||||
items to the list array won't cause the contents of the current page
|
||||
to change.
|
||||
*/
|
||||
export const UPDATE_PAGINATION = 'UPDATE_PAGINATION'
|
||||
export const updatePagination = () => ({type:UPDATE_PAGINATION})
|
||||
export const updatePagination = () => ({type: UPDATE_PAGINATION})
|
||||
|
|
|
@ -4,20 +4,19 @@ export const USER_LOGGED_OUT = 'USER_LOGGED_OUT'
|
|||
export const USER_LOGIN_ERROR = 'USER_LOGIN_ERROR'
|
||||
|
||||
export const loginInProgress = () => ({
|
||||
type: LOGIN_IN_PROGRESS
|
||||
type: LOGIN_IN_PROGRESS
|
||||
})
|
||||
|
||||
export const userLoggedIn = (user) => ({
|
||||
type: USER_LOGGED_IN,
|
||||
user
|
||||
type: USER_LOGGED_IN,
|
||||
user
|
||||
})
|
||||
|
||||
export const userLoggedOut = () => ({
|
||||
type: USER_LOGGED_OUT
|
||||
type: USER_LOGGED_OUT
|
||||
})
|
||||
|
||||
export const userLoginError = error => ({
|
||||
type: USER_LOGIN_ERROR,
|
||||
error
|
||||
type: USER_LOGIN_ERROR,
|
||||
error
|
||||
})
|
||||
|
||||
|
|
|
@ -6,21 +6,21 @@ without changing state directly. They're intended to be used with Redux dev tool
|
|||
const RAW_HTTP_RESPONSE = 'DEBUG_RAW_HTTP_RESPONSE'
|
||||
const JSON_RESULT = 'DEBUG_JSON_RESULT'
|
||||
|
||||
//response is not serializable
|
||||
// response is not serializable
|
||||
export const rawHttpResponse = (response) => ({
|
||||
type: RAW_HTTP_RESPONSE,
|
||||
response: response ? {
|
||||
bodyUsed: response.bodyUsed,
|
||||
ok: response.ok,
|
||||
redirected: response.redirected,
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
type: response.type,
|
||||
url: response.url
|
||||
} : null
|
||||
type: RAW_HTTP_RESPONSE,
|
||||
response: response ? {
|
||||
bodyUsed: response.bodyUsed,
|
||||
ok: response.ok,
|
||||
redirected: response.redirected,
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
type: response.type,
|
||||
url: response.url
|
||||
} : null
|
||||
})
|
||||
|
||||
export const jsonResult = (json) => ({
|
||||
type:JSON_RESULT,
|
||||
json
|
||||
})
|
||||
type: JSON_RESULT,
|
||||
json
|
||||
})
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import moment from 'moment'
|
||||
import { reduxBackedPromise, paginationActions } from './actionHelpers'
|
||||
import { reduxBackedPromise, paginationActions } from 'actions/actionHelpers'
|
||||
|
||||
export const TRY_ENGAGE = 'TRY_ENGAGE'
|
||||
export const ENGAGE_SUCCESS = 'ENGAGE_SUCCESS'
|
||||
|
@ -9,72 +9,70 @@ export const DISENGAGE_SUCCESS = 'DISENGAGE_SUCCESS'
|
|||
export const DISENGAGE_FAILURE = 'DISENGAGE_FAILURE'
|
||||
export const ENGAGEMENTS = 'ENGAGEMENTS'
|
||||
|
||||
|
||||
export const engage = (incidentId, participant, timeEngaged = moment()) =>
|
||||
reduxBackedPromise(
|
||||
['incidents/' + incidentId + '/engagements/', {participant}],
|
||||
engageActionSet(incidentId, participant, timeEngaged),
|
||||
'POST'
|
||||
)
|
||||
|
||||
|
||||
export const disengage = (participant, engagement, timeDisengaged = moment()) =>
|
||||
reduxBackedPromise(
|
||||
[
|
||||
'incidents/' + engagement.incidentId + '/engagements/' + engagement.id,
|
||||
updatedEngagement(engagement, timeDisengaged),
|
||||
null,
|
||||
false
|
||||
],
|
||||
[
|
||||
'incidents/' + engagement.incidentId + '/engagements/' + engagement.id,
|
||||
updatedEngagement(engagement, timeDisengaged),
|
||||
null,
|
||||
false
|
||||
],
|
||||
disengageActionSet(engagement.incidentId, participant, engagement, timeDisengaged),
|
||||
'PUT'
|
||||
)
|
||||
|
||||
|
||||
const engageActionSet = (incidentId, participant, timeEngaged) => ({
|
||||
try: () => ({
|
||||
type: TRY_ENGAGE,
|
||||
incidentId,
|
||||
participant,
|
||||
timeEngaged
|
||||
}),
|
||||
try: () => ({
|
||||
type: TRY_ENGAGE,
|
||||
incidentId,
|
||||
participant,
|
||||
timeEngaged
|
||||
}),
|
||||
|
||||
succeed: (engagement) => ({
|
||||
type: ENGAGE_SUCCESS,
|
||||
engagement
|
||||
}),
|
||||
succeed: (engagement) => ({
|
||||
type: ENGAGE_SUCCESS,
|
||||
engagement
|
||||
}),
|
||||
|
||||
fail: (error) => ({
|
||||
type: ENGAGE_FAILURE,
|
||||
error,
|
||||
participant,
|
||||
timeEngaged
|
||||
})
|
||||
fail: (error) => ({
|
||||
type: ENGAGE_FAILURE,
|
||||
error,
|
||||
participant,
|
||||
timeEngaged
|
||||
})
|
||||
})
|
||||
|
||||
const updatedEngagement = (engagement, timeDisengaged) => ({
|
||||
...engagement,
|
||||
timeDisengaged
|
||||
...engagement,
|
||||
timeDisengaged
|
||||
})
|
||||
|
||||
const disengageActionSet = (incidentId, participant, engagement, timeDisengaged) => ({
|
||||
try: () => ({
|
||||
type: TRY_DISENGAGE,
|
||||
incidentId,
|
||||
participant,
|
||||
timeDisengaged
|
||||
}),
|
||||
try: () => ({
|
||||
type: TRY_DISENGAGE,
|
||||
incidentId,
|
||||
participant,
|
||||
timeDisengaged
|
||||
}),
|
||||
|
||||
succeed: () => ({
|
||||
type: DISENGAGE_SUCCESS,
|
||||
engagement: updatedEngagement(engagement, timeDisengaged)
|
||||
}),
|
||||
succeed: () => ({
|
||||
type: DISENGAGE_SUCCESS,
|
||||
engagement: updatedEngagement(engagement, timeDisengaged)
|
||||
}),
|
||||
|
||||
fail: (error) => ({
|
||||
type: DISENGAGE_FAILURE,
|
||||
error,
|
||||
participant,
|
||||
timeDisengaged
|
||||
})
|
||||
fail: (error) => ({
|
||||
type: DISENGAGE_FAILURE,
|
||||
error,
|
||||
participant,
|
||||
timeDisengaged
|
||||
})
|
||||
})
|
||||
|
||||
export const pagination = paginationActions(ENGAGEMENTS)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import moment from 'moment'
|
||||
import { paginationActions, updatePagination } from './actionHelpers'
|
||||
import { reduxBackedPromise } from './actionHelpers'
|
||||
import * as filterActions from './filterActions'
|
||||
import { paginationActions, updatePagination, reduxBackedPromise } from 'actions/actionHelpers'
|
||||
import * as filterActions from 'actions/filterActions'
|
||||
|
||||
export const EVENTS = 'EVENTS'
|
||||
export const REQUEST_EVENT = 'REQUEST_EVENT'
|
||||
|
@ -29,122 +28,120 @@ export const fetchEvents = (filter) => reduxBackedPromise(
|
|||
getEventsActionSet(filter.incidentId)
|
||||
)
|
||||
|
||||
export const postEvent = (incidentId, eventTypeId = 0, data= {}, occurrenceTime = moment()) => reduxBackedPromise(
|
||||
export const postEvent = (incidentId, eventTypeId = 0, data = {}, occurrenceTime = moment()) => reduxBackedPromise(
|
||||
postEventFetchArgs(incidentId, eventTypeId, data, occurrenceTime),
|
||||
postEventActionSet(incidentId),
|
||||
'POST'
|
||||
)
|
||||
|
||||
export const getEventsEndPoint = (incidentId) => (incidentId ? 'incidents/' + incidentId + '/': '') + 'events/'
|
||||
export const getEventsEndPoint = (incidentId) => (incidentId ? 'incidents/' + incidentId + '/' : '') + 'events/'
|
||||
|
||||
export const getEventsFetchArgs = (filter) => ([
|
||||
getEventsEndPoint(filter.incidentId) + filterActions.serializeFiltersForUrl(filter)
|
||||
getEventsEndPoint(filter.incidentId) + filterActions.serializeFiltersForUrl(filter)
|
||||
])
|
||||
|
||||
export const getEventFetchArgs = (incidentId, eventId) => {
|
||||
return [getEventsEndPoint(incidentId) + eventId]
|
||||
return [getEventsEndPoint(incidentId) + eventId]
|
||||
}
|
||||
|
||||
export const postEventFetchArgs = (incidentId, eventTypeId, data, occurrenceTime) => ([
|
||||
getEventsEndPoint(incidentId),
|
||||
{
|
||||
eventTypeId,
|
||||
occurred: occurrenceTime,
|
||||
eventFired: occurrenceTime,
|
||||
data
|
||||
}
|
||||
getEventsEndPoint(incidentId),
|
||||
{
|
||||
eventTypeId,
|
||||
occurred: occurrenceTime,
|
||||
eventFired: occurrenceTime,
|
||||
data
|
||||
}
|
||||
])
|
||||
|
||||
export const getEventActionSet = (incidentId, eventId) => ({
|
||||
try: () => ({
|
||||
type: REQUEST_EVENT,
|
||||
incidentId,
|
||||
id: eventId
|
||||
}),
|
||||
try: () => ({
|
||||
type: REQUEST_EVENT,
|
||||
incidentId,
|
||||
id: eventId
|
||||
}),
|
||||
|
||||
succeed: (event) => (dispatch) => {
|
||||
dispatch({
|
||||
type: RECEIVE_EVENT,
|
||||
event,
|
||||
id: eventId
|
||||
})
|
||||
|
||||
dispatch(updatePagination())
|
||||
},
|
||||
|
||||
fail: (failureReason) => ({
|
||||
type: RECEIVE_EVENT_FAILURE,
|
||||
failureReason,
|
||||
incidentId,
|
||||
id: eventId
|
||||
succeed: (event) => (dispatch) => {
|
||||
dispatch({
|
||||
type: RECEIVE_EVENT,
|
||||
event,
|
||||
id: eventId
|
||||
})
|
||||
|
||||
dispatch(updatePagination())
|
||||
},
|
||||
|
||||
fail: (failureReason) => ({
|
||||
type: RECEIVE_EVENT_FAILURE,
|
||||
failureReason,
|
||||
incidentId,
|
||||
id: eventId
|
||||
})
|
||||
})
|
||||
|
||||
export const getEventsActionSet = (incidentId) => ({
|
||||
try: () => ({
|
||||
type: REQUEST_EVENTS,
|
||||
incidentId
|
||||
}),
|
||||
try: () => ({
|
||||
type: REQUEST_EVENTS,
|
||||
incidentId
|
||||
}),
|
||||
|
||||
succeed: (events, response) => (dispatch) => {
|
||||
let linksHeader
|
||||
for (let header of response.headers){
|
||||
if(header[0] === linksHeaderName){
|
||||
linksHeader = JSON.parse(header[1])
|
||||
}
|
||||
}
|
||||
succeed: (events, response) => (dispatch) => {
|
||||
let linksHeader
|
||||
for (let header of response.headers) {
|
||||
if (header[0] === linksHeaderName) {
|
||||
linksHeader = JSON.parse(header[1])
|
||||
}
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: RECEIVE_EVENTS,
|
||||
events,
|
||||
incidentId,
|
||||
pagination: linksHeader
|
||||
})
|
||||
dispatch({
|
||||
type: RECEIVE_EVENTS,
|
||||
events,
|
||||
incidentId,
|
||||
pagination: linksHeader
|
||||
})
|
||||
|
||||
|
||||
if(linksHeader.NextPageLink){
|
||||
dispatch(reduxBackedPromise(
|
||||
if (linksHeader.NextPageLink) {
|
||||
dispatch(reduxBackedPromise(
|
||||
[linksHeader.NextPageLink],
|
||||
getEventsActionSet(incidentId)
|
||||
))
|
||||
}
|
||||
else{
|
||||
dispatch(updatePagination())
|
||||
}
|
||||
},
|
||||
} else {
|
||||
dispatch(updatePagination())
|
||||
}
|
||||
},
|
||||
|
||||
fail: (failureReason) => ({
|
||||
type: RECEIVE_EVENTS_FAILURE,
|
||||
failureReason,
|
||||
incidentId
|
||||
})
|
||||
fail: (failureReason) => ({
|
||||
type: RECEIVE_EVENTS_FAILURE,
|
||||
failureReason,
|
||||
incidentId
|
||||
})
|
||||
})
|
||||
|
||||
export const addEvent = (event, incidentId) => ({
|
||||
type: ADD_EVENT,
|
||||
incidentId,
|
||||
event
|
||||
type: ADD_EVENT,
|
||||
incidentId,
|
||||
event
|
||||
})
|
||||
|
||||
export const postEventActionSet = (incidentId) => ({
|
||||
try: () => ({
|
||||
type: POST_EVENT_TRY,
|
||||
incidentId
|
||||
}),
|
||||
try: () => ({
|
||||
type: POST_EVENT_TRY,
|
||||
incidentId
|
||||
}),
|
||||
|
||||
succeed: (event) => dispatch => {
|
||||
dispatch({
|
||||
type: POST_EVENT_SUCCEED,
|
||||
incidentId,
|
||||
event
|
||||
})
|
||||
|
||||
dispatch(updatePagination())
|
||||
},
|
||||
|
||||
fail: (failureReason) => ({
|
||||
type: POST_EVENT_FAIL,
|
||||
incidentId,
|
||||
failureReason
|
||||
succeed: (event) => dispatch => {
|
||||
dispatch({
|
||||
type: POST_EVENT_SUCCEED,
|
||||
incidentId,
|
||||
event
|
||||
})
|
||||
})
|
||||
|
||||
dispatch(updatePagination())
|
||||
},
|
||||
|
||||
fail: (failureReason) => ({
|
||||
type: POST_EVENT_FAIL,
|
||||
incidentId,
|
||||
failureReason
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { reduxBackedPromise } from './actionHelpers'
|
||||
import { reduxBackedPromise } from 'actions/actionHelpers'
|
||||
|
||||
export const TRY_GET_EVENT_TYPE = 'TRY_GET_EVENT_TYPE'
|
||||
export const GET_EVENT_TYPE_SUCCESS = 'GET_EVENT_TYPE_SUCCESS'
|
||||
|
@ -18,36 +18,36 @@ export const fetchEventTypes = () => reduxBackedPromise(
|
|||
)
|
||||
|
||||
export const getEventTypeActionSet = (eventTypeId) => ({
|
||||
try: () => ({
|
||||
type: TRY_GET_EVENT_TYPE,
|
||||
id: eventTypeId
|
||||
}),
|
||||
try: () => ({
|
||||
type: TRY_GET_EVENT_TYPE,
|
||||
id: eventTypeId
|
||||
}),
|
||||
|
||||
succeed: (eventType) => ({
|
||||
type: GET_EVENT_TYPE_SUCCESS,
|
||||
id: eventTypeId,
|
||||
eventType
|
||||
}),
|
||||
succeed: (eventType) => ({
|
||||
type: GET_EVENT_TYPE_SUCCESS,
|
||||
id: eventTypeId,
|
||||
eventType
|
||||
}),
|
||||
|
||||
fail: (failureReason) => ({
|
||||
type: GET_EVENT_TYPE_FAILURE,
|
||||
id: eventTypeId,
|
||||
failureReason
|
||||
})
|
||||
fail: (failureReason) => ({
|
||||
type: GET_EVENT_TYPE_FAILURE,
|
||||
id: eventTypeId,
|
||||
failureReason
|
||||
})
|
||||
})
|
||||
|
||||
export const getEventTypesActionSet = ({
|
||||
try: () => ({
|
||||
type: TRY_GET_EVENT_TYPES
|
||||
}),
|
||||
try: () => ({
|
||||
type: TRY_GET_EVENT_TYPES
|
||||
}),
|
||||
|
||||
succeed: (eventTypes) => ({
|
||||
type: GET_EVENT_TYPES_SUCCESS,
|
||||
eventTypes
|
||||
}),
|
||||
succeed: (eventTypes) => ({
|
||||
type: GET_EVENT_TYPES_SUCCESS,
|
||||
eventTypes
|
||||
}),
|
||||
|
||||
fail: (failureReason) => ({
|
||||
type: GET_EVENT_TYPES_FAILURE,
|
||||
failureReason
|
||||
})
|
||||
})
|
||||
fail: (failureReason) => ({
|
||||
type: GET_EVENT_TYPES_FAILURE,
|
||||
failureReason
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export const TOGGLE_COLLAPSE = 'TOGGLE_COLLAPSE'
|
||||
|
||||
export const toggleCollapse = (elementName) => ({
|
||||
type: TOGGLE_COLLAPSE,
|
||||
elementName
|
||||
})
|
||||
type: TOGGLE_COLLAPSE,
|
||||
elementName
|
||||
})
|
||||
|
|
|
@ -2,113 +2,111 @@ import queryString from 'query-string'
|
|||
import deepEquals from 'deep-equal'
|
||||
import ByPath from 'object-path'
|
||||
|
||||
import * as eventActions from './eventActions'
|
||||
import * as eventActions from 'actions/eventActions'
|
||||
|
||||
export const CHANGE_EVENT_FILTER = 'CHANGE_EVENT_FILTER'
|
||||
|
||||
export const changeEventFilter = (history) => (filter) => {
|
||||
getUrlFromFilter(history, filter)
|
||||
return {
|
||||
type: CHANGE_EVENT_FILTER,
|
||||
filter
|
||||
}
|
||||
getUrlFromFilter(history, filter)
|
||||
return {
|
||||
type: CHANGE_EVENT_FILTER,
|
||||
filter
|
||||
}
|
||||
}
|
||||
|
||||
export const addFilter = (history) => (filter, eventType) => {
|
||||
let newFilter = {}
|
||||
let oldFilter = filter
|
||||
if (!eventType || !eventType.id) {
|
||||
return
|
||||
}
|
||||
if (oldFilter && oldFilter.eventTypes && oldFilter.eventTypes.includes(eventType.id)) {
|
||||
newFilter = {...oldFilter}
|
||||
}
|
||||
else {
|
||||
newFilter = {
|
||||
...oldFilter,
|
||||
eventTypes: oldFilter.eventTypes ?
|
||||
oldFilter.eventTypes.concat(eventType.id)
|
||||
let newFilter = {}
|
||||
let oldFilter = filter
|
||||
if (!eventType || !eventType.id) {
|
||||
return
|
||||
}
|
||||
if (oldFilter && oldFilter.eventTypes && oldFilter.eventTypes.includes(eventType.id)) {
|
||||
newFilter = {...oldFilter}
|
||||
} else {
|
||||
newFilter = {
|
||||
...oldFilter,
|
||||
eventTypes: oldFilter.eventTypes
|
||||
? oldFilter.eventTypes.concat(eventType.id)
|
||||
: [eventType.id]
|
||||
}
|
||||
}
|
||||
return applyFilter(history)(oldFilter, newFilter)
|
||||
}
|
||||
return applyFilter(history)(oldFilter, newFilter)
|
||||
}
|
||||
|
||||
export const removeFilter = (history, relativeFilterPath) => (oldFilter, filterToDelete) => {
|
||||
if (!ByPath.get(oldFilter, relativeFilterPath).includes(filterToDelete)) {
|
||||
return
|
||||
}
|
||||
let newFilter = { ...oldFilter }
|
||||
const isFilterToKeep = existingFilter => filterToDelete !== existingFilter
|
||||
ByPath.set(newFilter, relativeFilterPath, ByPath.get(oldFilter, relativeFilterPath).filter(isFilterToKeep))
|
||||
return applyFilter(history)(oldFilter, newFilter)
|
||||
if (!ByPath.get(oldFilter, relativeFilterPath).includes(filterToDelete)) {
|
||||
return
|
||||
}
|
||||
let newFilter = { ...oldFilter }
|
||||
const isFilterToKeep = existingFilter => filterToDelete !== existingFilter
|
||||
ByPath.set(newFilter, relativeFilterPath, ByPath.get(oldFilter, relativeFilterPath).filter(isFilterToKeep))
|
||||
return applyFilter(history)(oldFilter, newFilter)
|
||||
}
|
||||
|
||||
const applyFilter = (history) => (oldFilter, newFilter) => (dispatch) => {
|
||||
if (!newFilter.incidentId) {
|
||||
throw new Error('Need to filter on incidentId!')
|
||||
}
|
||||
if (!deepEquals(oldFilter, newFilter)) {
|
||||
dispatch(changeEventFilter(history)(newFilter))
|
||||
dispatch(eventActions.fetchEvents(newFilter))
|
||||
}
|
||||
if (!newFilter.incidentId) {
|
||||
throw new Error('Need to filter on incidentId!')
|
||||
}
|
||||
if (!deepEquals(oldFilter, newFilter)) {
|
||||
dispatch(changeEventFilter(history)(newFilter))
|
||||
dispatch(eventActions.fetchEvents(newFilter))
|
||||
}
|
||||
}
|
||||
|
||||
export const synchronizeFilters = (filter, incidentId, ticketId, history) => {
|
||||
const newFilter = Object.assign({ incidentId: incidentId, ticketId: ticketId }, filter)
|
||||
return applyFilter(history)(filter, newFilter)
|
||||
const newFilter = Object.assign({ incidentId: incidentId, ticketId: ticketId }, filter)
|
||||
return applyFilter(history)(filter, newFilter)
|
||||
}
|
||||
|
||||
export const serializeFiltersForUrl = (filters) => {
|
||||
if (!filters) {
|
||||
return ''
|
||||
}
|
||||
const eventTypes = serializeEventTypesForQuery(filters.eventTypes)
|
||||
const filterTokens = Object.entries(filters)
|
||||
.filter(filter => filter[0] !== 'incidentId'
|
||||
&& filter[0] !== 'eventTypes'
|
||||
&& filter[0] !== 'fromUrl'
|
||||
&& filter[0] !== 'ticketId')
|
||||
if (!filters) {
|
||||
return ''
|
||||
}
|
||||
const eventTypes = serializeEventTypesForQuery(filters.eventTypes)
|
||||
const filterTokens = Object.entries(filters)
|
||||
.filter(filter => filter[0] !== 'incidentId' &&
|
||||
filter[0] !== 'eventTypes' &&
|
||||
filter[0] !== 'fromUrl' &&
|
||||
filter[0] !== 'ticketId')
|
||||
.map(filter => `${filter[0]}=${filter[1]}`)
|
||||
const finalFilterTokens = eventTypes
|
||||
const finalFilterTokens = eventTypes
|
||||
? filterTokens.concat(eventTypes)
|
||||
: filterTokens
|
||||
return finalFilterTokens && finalFilterTokens.length > 0 ? '?' + finalFilterTokens.join('&')
|
||||
return finalFilterTokens && finalFilterTokens.length > 0 ? '?' + finalFilterTokens.join('&')
|
||||
: ''
|
||||
}
|
||||
|
||||
export const serializeEventTypesForQuery = (eventTypes) => {
|
||||
if (!eventTypes || eventTypes.length === 0) {
|
||||
return ''
|
||||
}
|
||||
return eventTypes.map(eventType => `eventTypes=${eventType}`).join('&')
|
||||
if (!eventTypes || eventTypes.length === 0) {
|
||||
return ''
|
||||
}
|
||||
return eventTypes.map(eventType => `eventTypes=${eventType}`).join('&')
|
||||
}
|
||||
|
||||
export const getFilterFromUrl = (urlFilterInfo) => {
|
||||
let filter = queryString.parse(urlFilterInfo)
|
||||
if (typeof(filter) !== 'object' || !filter.eventTypes) {
|
||||
return null
|
||||
}
|
||||
if (!Array.isArray(filter.eventTypes)){
|
||||
filter.eventTypes = [filter.eventTypes]
|
||||
}
|
||||
filter.eventTypes = filter.eventTypes.map(e => parseInt(e))
|
||||
return filter
|
||||
let filter = queryString.parse(urlFilterInfo)
|
||||
if (typeof (filter) !== 'object' || !filter.eventTypes) {
|
||||
return null
|
||||
}
|
||||
if (!Array.isArray(filter.eventTypes)) {
|
||||
filter.eventTypes = [filter.eventTypes]
|
||||
}
|
||||
filter.eventTypes = filter.eventTypes.map(e => parseInt(e))
|
||||
return filter
|
||||
}
|
||||
|
||||
export const getUrlFromFilter = (history, filter) => {
|
||||
if (filter && filter.eventTypes) {
|
||||
history.push(generateUrl(history, filter))
|
||||
}
|
||||
if (filter && filter.eventTypes) {
|
||||
history.push(generateUrl(history, filter))
|
||||
}
|
||||
}
|
||||
|
||||
export const generateUrl = (history, filter) => {
|
||||
return /tickets/ + filter.ticketId + '?' + serializeEventTypesForQuery(filter.eventTypes)
|
||||
return /tickets/ + filter.ticketId + '?' + serializeEventTypesForQuery(filter.eventTypes)
|
||||
}
|
||||
|
||||
export const findEventTypeInRef = (referenceData) => (eventType) => {
|
||||
return referenceData.hasOwnProperty(eventType) ?
|
||||
referenceData[eventType]
|
||||
:
|
||||
{id: eventType, name: 'unknown'}
|
||||
}
|
||||
return referenceData.hasOwnProperty(eventType)
|
||||
? referenceData[eventType]
|
||||
: {id: eventType, name: 'unknown'}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
|
||||
|
||||
export const UPDATE_INPUT = 'UPDATE_INPUT'
|
||||
export const CLEAR_INPUT = 'CLEAR_INPUT'
|
||||
export const CLEAR_FORM = 'CLEAR_FORM'
|
||||
|
||||
export const updateInput = (form, field, value) => ({
|
||||
type: UPDATE_INPUT,
|
||||
form,
|
||||
field,
|
||||
value
|
||||
type: UPDATE_INPUT,
|
||||
form,
|
||||
field,
|
||||
value
|
||||
})
|
||||
|
||||
export const clearInput = (form, field) => ({
|
||||
type: CLEAR_INPUT,
|
||||
form,
|
||||
field
|
||||
type: CLEAR_INPUT,
|
||||
form,
|
||||
field
|
||||
})
|
||||
|
||||
export const clearForm = (form) => ({
|
||||
type: CLEAR_FORM,
|
||||
form
|
||||
})
|
||||
export const clearForm = (form) => ({
|
||||
type: CLEAR_FORM,
|
||||
form
|
||||
})
|
||||
|
|
|
@ -1,27 +1,26 @@
|
|||
import { reduxBackedPromise } from './actionHelpers'
|
||||
import { reduxBackedPromise } from 'actions/actionHelpers'
|
||||
|
||||
export const TRY_GET_GLOBAL_ACTIONS = 'TRY_GET_GLOBAL_ACTIONS'
|
||||
export const GET_GLOBAL_ACTIONS_SUCCESS = 'GET_GLOBAL_ACTIONS_SUCCESS'
|
||||
export const GET_GLOBAL_ACTIONS_FAILURE = 'GET_GLOBAL_ACTIONS_FAILURE'
|
||||
|
||||
|
||||
export const fetchGlobalActions = () => reduxBackedPromise(
|
||||
['globalActions/'],
|
||||
getGlobalActionsActionSet
|
||||
)
|
||||
|
||||
export const getGlobalActionsActionSet = ({
|
||||
try: () => ({
|
||||
type: TRY_GET_GLOBAL_ACTIONS
|
||||
}),
|
||||
try: () => ({
|
||||
type: TRY_GET_GLOBAL_ACTIONS
|
||||
}),
|
||||
|
||||
succeed: (globalActions) => ({
|
||||
type: GET_GLOBAL_ACTIONS_SUCCESS,
|
||||
globalActions
|
||||
}),
|
||||
succeed: (globalActions) => ({
|
||||
type: GET_GLOBAL_ACTIONS_SUCCESS,
|
||||
globalActions
|
||||
}),
|
||||
|
||||
fail: (failureReason) => ({
|
||||
type: GET_GLOBAL_ACTIONS_FAILURE,
|
||||
failureReason
|
||||
})
|
||||
fail: (failureReason) => ({
|
||||
type: GET_GLOBAL_ACTIONS_FAILURE,
|
||||
failureReason
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import moment from 'moment'
|
||||
import { reduxBackedPromise } from './actionHelpers'
|
||||
import * as ticketActions from './ticketActions'
|
||||
import { reduxBackedPromise } from 'actions/actionHelpers'
|
||||
import * as ticketActions from 'actions/ticketActions'
|
||||
|
||||
export const REQUEST_INCIDENT = 'REQUEST_INCIDENT'
|
||||
export const RECEIVE_INCIDENT = 'RECEIVE_INCIDENT'
|
||||
|
@ -16,7 +16,6 @@ export const REQUEST_INCIDENT_BY_TICKET_ID = 'REQUEST_INCIDENT_BY_TICKET_ID'
|
|||
export const FETCH_INCIDENTS_BY_TICKET_ID_SUCCESS = 'FETCH_INCIDENTS_BY_TICKET_ID_SUCCESS'
|
||||
export const FETCH_INCIDENTS_BY_TICKET_ID_FAILURE = 'FETCH_INCIDENTS_BY_TICKET_ID_FAILURE'
|
||||
|
||||
|
||||
export const fetchIncident = incidentId => reduxBackedPromise(
|
||||
['incidents/' + incidentId],
|
||||
getIncidentActionSet(incidentId)
|
||||
|
@ -37,122 +36,120 @@ export const postIncident = (ticketId, ticketSystem) => reduxBackedPromise(
|
|||
'POST'
|
||||
)
|
||||
|
||||
|
||||
export const getIncidentActionSet = (incidentId) => ({
|
||||
try: () => ({
|
||||
type: REQUEST_INCIDENT,
|
||||
id: incidentId
|
||||
}),
|
||||
try: () => ({
|
||||
type: REQUEST_INCIDENT,
|
||||
id: incidentId
|
||||
}),
|
||||
|
||||
succeed: (incident) => (dispatch) => {
|
||||
dispatch({
|
||||
type: RECEIVE_INCIDENT,
|
||||
incident,
|
||||
id: incidentId
|
||||
})
|
||||
},
|
||||
|
||||
fail: (failureReason) => ({
|
||||
type: RECEIVE_INCIDENT_FAILURE,
|
||||
error: failureReason
|
||||
succeed: (incident) => (dispatch) => {
|
||||
dispatch({
|
||||
type: RECEIVE_INCIDENT,
|
||||
incident,
|
||||
id: incidentId
|
||||
})
|
||||
},
|
||||
|
||||
fail: (failureReason) => ({
|
||||
type: RECEIVE_INCIDENT_FAILURE,
|
||||
error: failureReason
|
||||
})
|
||||
})
|
||||
|
||||
export const getIncidentsByTicketIdActionSet = (ticketId) => ({
|
||||
try: () => ({
|
||||
type: REQUEST_INCIDENT_BY_TICKET_ID,
|
||||
ticketId
|
||||
}),
|
||||
|
||||
succeed: (incidents) => ({
|
||||
type: FETCH_INCIDENTS_BY_TICKET_ID_SUCCESS,
|
||||
ticketId,
|
||||
incidents
|
||||
}),
|
||||
try: () => ({
|
||||
type: REQUEST_INCIDENT_BY_TICKET_ID,
|
||||
ticketId
|
||||
}),
|
||||
|
||||
fail: (error) => ({
|
||||
type: FETCH_INCIDENTS_BY_TICKET_ID_FAILURE,
|
||||
ticketId,
|
||||
error
|
||||
})
|
||||
succeed: (incidents) => ({
|
||||
type: FETCH_INCIDENTS_BY_TICKET_ID_SUCCESS,
|
||||
ticketId,
|
||||
incidents
|
||||
}),
|
||||
|
||||
fail: (error) => ({
|
||||
type: FETCH_INCIDENTS_BY_TICKET_ID_FAILURE,
|
||||
ticketId,
|
||||
error
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
export const fetchIncidentIfNeeded = (incident, ticketId, ticket, ticketSystem, preferences, incidentIsFetching, incidentIsError) =>
|
||||
(dispatch) =>
|
||||
(incidentIsFetching || incidentIsError)
|
||||
? null //No refresh needed
|
||||
? null // No refresh needed
|
||||
: basicIncidentInfoLoaded(incident)
|
||||
? fullIncidentInfoLoaded(incident, ticket, ticketSystem, preferences)
|
||||
? null //No refresh needed
|
||||
? null // No refresh needed
|
||||
: dispatch(fetchIncident(incident.id))
|
||||
: ticketId
|
||||
? dispatch(fetchIncidentsByTicketId(ticketId))
|
||||
: dispatch(fetchIncidents())
|
||||
|
||||
const basicIncidentInfoLoaded = (incident) => incident && incident.id
|
||||
const fullIncidentInfoLoaded = (incident, ticket, ticketSystem, preferences) => !incident.IsFetching
|
||||
&& ticketSystem
|
||||
&& isTicketInfoRecent(ticket, preferences)
|
||||
const basicIncidentInfoLoaded = (incident) => incident && incident.id
|
||||
const fullIncidentInfoLoaded = (incident, ticket, ticketSystem, preferences) => !incident.IsFetching &&
|
||||
ticketSystem &&
|
||||
isTicketInfoRecent(ticket, preferences)
|
||||
|
||||
const isTicketInfoRecent = (ticket, preferences) => ticket
|
||||
&& ticket.lastRefresh
|
||||
&& moment(ticket.lastRefresh).isAfter(moment().subtract(preferences.refreshIntervalInSeconds, 'seconds'))
|
||||
const isTicketInfoRecent = (ticket, preferences) => ticket &&
|
||||
ticket.lastRefresh &&
|
||||
moment(ticket.lastRefresh).isAfter(moment().subtract(preferences.refreshIntervalInSeconds, 'seconds'))
|
||||
|
||||
export const getIncidentsActionSet = ({
|
||||
try: () => ({
|
||||
type: REQUEST_INCIDENTS
|
||||
}),
|
||||
try: () => ({
|
||||
type: REQUEST_INCIDENTS
|
||||
}),
|
||||
|
||||
succeed: (incidents) => ({
|
||||
type: RECEIVE_INCIDENTS,
|
||||
incidents,
|
||||
receivedAt: moment()
|
||||
}),
|
||||
succeed: (incidents) => ({
|
||||
type: RECEIVE_INCIDENTS,
|
||||
incidents,
|
||||
receivedAt: moment()
|
||||
}),
|
||||
|
||||
fail: (error) => ({
|
||||
type: RECEIVE_INCIDENTS_FAILURE,
|
||||
error
|
||||
})
|
||||
fail: (error) => ({
|
||||
type: RECEIVE_INCIDENTS_FAILURE,
|
||||
error
|
||||
})
|
||||
})
|
||||
|
||||
export const createIncidentActionSet = (ticketId, ticketSystem) => ({
|
||||
try: () => ({
|
||||
type: TRY_CREATE_INCIDENT,
|
||||
ticketId,
|
||||
ticketSystem
|
||||
}),
|
||||
try: () => ({
|
||||
type: TRY_CREATE_INCIDENT,
|
||||
ticketId,
|
||||
ticketSystem
|
||||
}),
|
||||
|
||||
succeed: (incident) => ({
|
||||
type: CREATE_INCIDENT_SUCCESS,
|
||||
incident
|
||||
}),
|
||||
succeed: (incident) => ({
|
||||
type: CREATE_INCIDENT_SUCCESS,
|
||||
incident
|
||||
}),
|
||||
|
||||
fail: (reason) => ({
|
||||
type: CREATE_INCIDENT_FAILURE,
|
||||
reason
|
||||
})
|
||||
fail: (reason) => ({
|
||||
type: CREATE_INCIDENT_FAILURE,
|
||||
reason
|
||||
})
|
||||
})
|
||||
|
||||
const postIncidentFetchArgs = (ticketId, ticketSystem) => {
|
||||
return [
|
||||
'incidents/',
|
||||
{
|
||||
title: 'placeholder',
|
||||
primaryTicket: {
|
||||
originId: ticketId,
|
||||
ticketingSystemId: ticketSystem.id
|
||||
}
|
||||
}
|
||||
]
|
||||
return [
|
||||
'incidents/',
|
||||
{
|
||||
title: 'placeholder',
|
||||
primaryTicket: {
|
||||
originId: ticketId,
|
||||
ticketingSystemId: ticketSystem.id
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export const updateIncidentCreationInput = (input) => ({
|
||||
type: UPDATE_INCIDENT_CREATION_INPUT,
|
||||
input
|
||||
type: UPDATE_INCIDENT_CREATION_INPUT,
|
||||
input
|
||||
})
|
||||
|
||||
export const duplicateIncident = (ticketId) => (dispatch) => {
|
||||
dispatch(createIncidentActionSet(ticketId, {}).fail({ message: 'An incident already exists for this ticket'}))
|
||||
dispatch(ticketActions.updateTicketQuery(ticketId))
|
||||
}
|
||||
dispatch(createIncidentActionSet(ticketId, {}).fail({message: 'An incident already exists for this ticket'}))
|
||||
dispatch(ticketActions.updateTicketQuery(ticketId))
|
||||
}
|
||||
|
|
|
@ -5,31 +5,30 @@ export const RECEIVE_MESSAGE = 'RECEIVE_MESSAGE'
|
|||
export const ACKNOWLEDGE_MESSAGES = 'ACKNOWLEDGE_MESSAGES'
|
||||
export const CONNECTION_CLOSED = 'CONNECTION_CLOSED'
|
||||
|
||||
|
||||
export const tryEstablishConnection = () => ({
|
||||
type: ESTABLISH_CONNECTION_TRY
|
||||
type: ESTABLISH_CONNECTION_TRY
|
||||
})
|
||||
|
||||
export const succeedEstablishConnection = () => ({
|
||||
type: ESTABLISH_CONNECTION_SUCCEED
|
||||
type: ESTABLISH_CONNECTION_SUCCEED
|
||||
})
|
||||
|
||||
export const failEstablishConnection = (error, stack) => ({
|
||||
type: ESTABLISH_CONNECTION_FAIL,
|
||||
error,
|
||||
stack
|
||||
type: ESTABLISH_CONNECTION_FAIL,
|
||||
error,
|
||||
stack
|
||||
})
|
||||
|
||||
export const receiveMessage = () => ({
|
||||
type: RECEIVE_MESSAGE
|
||||
type: RECEIVE_MESSAGE
|
||||
})
|
||||
|
||||
export const acknowledgeMessages = () => ({
|
||||
type: ACKNOWLEDGE_MESSAGES
|
||||
type: ACKNOWLEDGE_MESSAGES
|
||||
})
|
||||
|
||||
export const connectionClosed = (error, stack) => ({
|
||||
type: CONNECTION_CLOSED,
|
||||
error,
|
||||
stack
|
||||
})
|
||||
type: CONNECTION_CLOSED,
|
||||
error,
|
||||
stack
|
||||
})
|
||||
|
|
|
@ -5,23 +5,23 @@ export const SCREEN_SIZE_LARGE = 'SCREEN_SIZE_LARGE'
|
|||
export const SCREEN_SIZE_FULL = 'SCREEN_SIZE_FULL'
|
||||
|
||||
export const buttonFontEnlarge = () => ({
|
||||
type: BUTTON_FONT_ENLARGE
|
||||
type: BUTTON_FONT_ENLARGE
|
||||
})
|
||||
|
||||
export const screenSizeSmall = () => ({
|
||||
type: SCREEN_SIZE_SMALL
|
||||
type: SCREEN_SIZE_SMALL
|
||||
})
|
||||
|
||||
export const screenSizeMedium = () => ({
|
||||
type: SCREEN_SIZE_MEDIUM
|
||||
type: SCREEN_SIZE_MEDIUM
|
||||
})
|
||||
|
||||
export const screenSizeLarge = () => ({
|
||||
type: SCREEN_SIZE_LARGE
|
||||
type: SCREEN_SIZE_LARGE
|
||||
})
|
||||
|
||||
export const screenSizeFull = () => ({
|
||||
type: SCREEN_SIZE_FULL
|
||||
type: SCREEN_SIZE_FULL
|
||||
})
|
||||
|
||||
const mediaQueriesToActions = [
|
||||
|
@ -32,14 +32,13 @@ const mediaQueriesToActions = [
|
|||
]
|
||||
|
||||
const CreateScreenSizeListeners = (mediaQueriesToActions) => (window, store) => {
|
||||
mediaQueriesToActions.map(mqta => CreateScreenSizeListener(mqta[0], mqta[1], window, store))
|
||||
mediaQueriesToActions.map(mqta => CreateScreenSizeListener(mqta[0], mqta[1], window, store))
|
||||
}
|
||||
|
||||
const CreateScreenSizeListener = (mediaQuery, action, window, store) => {
|
||||
const listener = window.matchMedia(mediaQuery)
|
||||
if( listener.matches ) { store.dispatch(action) }
|
||||
listener.onchange = ls => { if(ls.matches) { store.dispatch(action) } }
|
||||
const listener = window.matchMedia(mediaQuery)
|
||||
if (listener.matches) { store.dispatch(action) }
|
||||
listener.onchange = ls => { if (ls.matches) { store.dispatch(action) } }
|
||||
}
|
||||
|
||||
|
||||
export const ListenForScreenSize = CreateScreenSizeListeners(mediaQueriesToActions)
|
||||
export const ListenForScreenSize = CreateScreenSizeListeners(mediaQueriesToActions)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export const UPDATE_TICKET_QUERY = 'UPDATE_TICKET_QUERY'
|
||||
|
||||
export const updateTicketQuery = ticketQuery => ({
|
||||
type: UPDATE_TICKET_QUERY,
|
||||
ticketQuery
|
||||
type: UPDATE_TICKET_QUERY,
|
||||
ticketQuery
|
||||
})
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import Login from './Login'
|
||||
import LoginError from './LoginError'
|
||||
import Login from 'components/Auth/Login'
|
||||
import LoginError from 'components/Auth/LoginError'
|
||||
|
||||
export const EnsureLoggedInContainer = ({error, isLoggedIn, children}) => {
|
||||
if (error) {
|
||||
return <LoginError/>
|
||||
return <LoginError />
|
||||
}
|
||||
if (isLoggedIn) {
|
||||
return children
|
||||
}
|
||||
return <Login/>
|
||||
return <Login />
|
||||
}
|
||||
|
||||
EnsureLoggedInContainer.propTypes = {
|
||||
|
@ -27,4 +27,4 @@ export const mapStateToProps = (state) => {
|
|||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(EnsureLoggedInContainer)
|
||||
export default connect(mapStateToProps)(EnsureLoggedInContainer)
|
||||
|
|
|
@ -1,31 +1,27 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import { login } from '../../services/authNService'
|
||||
import { login } from 'services/authNService'
|
||||
|
||||
export class Login extends React.Component {
|
||||
static propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
login: PropTypes.func,
|
||||
isLoggedIn: PropTypes.bool.isRequired,
|
||||
signInAutomatically: PropTypes.bool.isRequired
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
//exported separately for testing
|
||||
LoginComponentDidMount(this.props)
|
||||
}
|
||||
static propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
login: PropTypes.func,
|
||||
isLoggedIn: PropTypes.bool.isRequired,
|
||||
signInAutomatically: PropTypes.bool.isRequired
|
||||
}
|
||||
|
||||
render() {
|
||||
const { dispatch } = this.props
|
||||
return (
|
||||
<button id="SignIn" onClick={() => dispatch(login)}>Sign In</button>
|
||||
)
|
||||
}
|
||||
componentDidMount () {
|
||||
// exported separately for testing
|
||||
LoginComponentDidMount(this.props)
|
||||
}
|
||||
|
||||
render () {
|
||||
const { dispatch } = this.props
|
||||
return (
|
||||
<button id='SignIn' onClick={() => dispatch(login)}>Sign In</button>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export const LoginComponentDidMount = ({
|
||||
|
@ -34,15 +30,15 @@ export const LoginComponentDidMount = ({
|
|||
signInAutomatically,
|
||||
dispatch
|
||||
}) => {
|
||||
if(!isLoggedIn && !loginInProgress && signInAutomatically) {
|
||||
dispatch(login)
|
||||
}
|
||||
if (!isLoggedIn && !loginInProgress && signInAutomatically) {
|
||||
dispatch(login)
|
||||
}
|
||||
}
|
||||
|
||||
export const mapStateToProps = (state) => {
|
||||
return {
|
||||
...state.auth
|
||||
}
|
||||
return {
|
||||
...state.auth
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(Login)
|
||||
export default connect(mapStateToProps)(Login)
|
||||
|
|
|
@ -3,21 +3,21 @@ import PropTypes from 'prop-types'
|
|||
import { connect } from 'react-redux'
|
||||
|
||||
export const LoginError = ({error}) => {
|
||||
return (
|
||||
<div>
|
||||
return (
|
||||
<div>
|
||||
There was a problem logging you in! {error}
|
||||
</div>
|
||||
)
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export function mapStateToProps(state) {
|
||||
return{
|
||||
error: state.auth.error
|
||||
}
|
||||
export function mapStateToProps (state) {
|
||||
return {
|
||||
error: state.auth.error
|
||||
}
|
||||
}
|
||||
|
||||
LoginError.propTypes = {
|
||||
error: PropTypes.string.isRequired
|
||||
error: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(LoginError)
|
||||
export default connect(mapStateToProps)(LoginError)
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import React from 'react'
|
||||
import FlatButtonStyled from './elements/FlatButtonStyled'
|
||||
import { clearCache } from '../services/authNService'
|
||||
import FlatButtonStyled from 'components/elements/FlatButtonStyled'
|
||||
import { clearCache } from 'services/authNService'
|
||||
|
||||
export const Debug = () => {
|
||||
return (<div>
|
||||
<FlatButtonStyled
|
||||
label='Clear Auth Cache'
|
||||
onTouchTap={() => clearCache()}
|
||||
return (<div>
|
||||
<FlatButtonStyled
|
||||
label='Clear Auth Cache'
|
||||
onTouchTap={() => clearCache()}
|
||||
/>
|
||||
</div>)
|
||||
</div>)
|
||||
}
|
||||
|
||||
export default Debug
|
||||
export default Debug
|
||||
|
|
|
@ -1,82 +1,82 @@
|
|||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import * as engagementActions from '../actions/engagementActions'
|
||||
import IconButtonStyled from './elements/IconButtonStyled'
|
||||
import * as engagementActions from 'actions/engagementActions'
|
||||
import IconButtonStyled from 'components/elements/IconButtonStyled'
|
||||
import PeopleIcon from 'material-ui/svg-icons/social/people'
|
||||
import AddCircleOutlineIcon from 'material-ui/svg-icons/content/add-circle-outline'
|
||||
import RemoveCircleOutlineIcon from 'material-ui/svg-icons/content/remove-circle-outline'
|
||||
|
||||
export const mapStateToPropsEngagements = (state, ownProps) => {
|
||||
return {
|
||||
...ownProps,
|
||||
user: {
|
||||
alias: state.auth.userAlias,
|
||||
team: state.auth.userTeam,
|
||||
role: state.auth.userRole
|
||||
}
|
||||
return {
|
||||
...ownProps,
|
||||
user: {
|
||||
alias: state.auth.userAlias,
|
||||
team: state.auth.userTeam,
|
||||
role: state.auth.userRole
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const Engagements = ({dispatch, incidentId, engagements, user}) => {
|
||||
return (
|
||||
<div>
|
||||
<span>
|
||||
<IconButtonStyled tooltip="Engagement">
|
||||
<PeopleIcon />
|
||||
</IconButtonStyled>
|
||||
return (
|
||||
<div>
|
||||
<span>
|
||||
<IconButtonStyled tooltip='Engagement'>
|
||||
<PeopleIcon />
|
||||
</IconButtonStyled>
|
||||
|
||||
{Array
|
||||
{Array
|
||||
.from(engagements.filter(engagement => !engagement.timeDisengaged))
|
||||
.map(engagement =>
|
||||
<Engagement
|
||||
key={'engagement' + engagement.id}
|
||||
engagement={engagement}
|
||||
user={user}
|
||||
dispatch={dispatch}
|
||||
<Engagement
|
||||
key={'engagement' + engagement.id}
|
||||
engagement={engagement}
|
||||
user={user}
|
||||
dispatch={dispatch}
|
||||
/>)
|
||||
}
|
||||
</span>
|
||||
<Engage dispatch={dispatch} incidentId={incidentId} user={user}/>
|
||||
</div>
|
||||
)
|
||||
</span>
|
||||
<Engage dispatch={dispatch} incidentId={incidentId} user={user} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const Engagement = ({dispatch, engagement, user}) => {
|
||||
return (
|
||||
<span>
|
||||
{engagement.participant ? engagement.participant.alias : 'No Alias Recorded (BUG)'}
|
||||
<IconButtonStyled
|
||||
tooltip='Disengage'
|
||||
onTouchTap={() => dispatch(engagementActions.disengage(user, engagement))}
|
||||
return (
|
||||
<span>
|
||||
{engagement.participant ? engagement.participant.alias : 'No Alias Recorded (BUG)'}
|
||||
<IconButtonStyled
|
||||
tooltip='Disengage'
|
||||
onTouchTap={() => dispatch(engagementActions.disengage(user, engagement))}
|
||||
>
|
||||
<RemoveCircleOutlineIcon />
|
||||
</IconButtonStyled>
|
||||
</span>
|
||||
)
|
||||
<RemoveCircleOutlineIcon />
|
||||
</IconButtonStyled>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
export const mapStateToPropsEngage = (state, ownProps) => {
|
||||
return {
|
||||
...ownProps,
|
||||
user: {
|
||||
alias: state.auth.userAlias,
|
||||
team: state.auth.userTeam,
|
||||
role: state.auth.userRole
|
||||
}
|
||||
return {
|
||||
...ownProps,
|
||||
user: {
|
||||
alias: state.auth.userAlias,
|
||||
team: state.auth.userTeam,
|
||||
role: state.auth.userRole
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const Engage = ({dispatch, incidentId, user}) => {
|
||||
return (
|
||||
<IconButtonStyled
|
||||
tooltip='Engage'
|
||||
onTouchTap={() => dispatch(engagementActions.engage(incidentId, user))}
|
||||
return (
|
||||
<IconButtonStyled
|
||||
tooltip='Engage'
|
||||
onTouchTap={() => dispatch(engagementActions.engage(incidentId, user))}
|
||||
>
|
||||
<AddCircleOutlineIcon />
|
||||
</IconButtonStyled>
|
||||
)
|
||||
<AddCircleOutlineIcon />
|
||||
</IconButtonStyled>
|
||||
)
|
||||
}
|
||||
|
||||
export const EngageRedux = connect(mapStateToPropsEngage)(Engage)
|
||||
const EngagementsRedux = connect(mapStateToPropsEngagements)(Engagements)
|
||||
export default EngagementsRedux
|
||||
export default EngagementsRedux
|
||||
|
|
|
@ -2,24 +2,21 @@ import React from 'react'
|
|||
import { connect } from 'react-redux'
|
||||
import { Redirect } from 'react-router'
|
||||
|
||||
|
||||
|
||||
export const Home = ({ ticket }) => {
|
||||
if (ticket && ticket.originId) {
|
||||
return <Redirect to={`/tickets/${ticket.originId}`} />
|
||||
}
|
||||
return <Redirect to={'/search'} />
|
||||
if (ticket && ticket.originId) {
|
||||
return <Redirect to={`/tickets/${ticket.originId}`} />
|
||||
}
|
||||
return <Redirect to={'/search'} />
|
||||
}
|
||||
|
||||
export const mapStateToProps = (state) => {
|
||||
// this gross thing finds all actual tickets, omitting the refresh metadata, and then picks the most recently visited one out
|
||||
// the sort function works because the dates are UTC and thus lexically sortable to start with
|
||||
return {
|
||||
ticket: (state.tickets && state.tickets.map) ? Object.values(state.tickets.map).filter(ele => { return ele.lastRefresh })
|
||||
return {
|
||||
ticket: (state.tickets && state.tickets.map) ? Object.values(state.tickets.map).filter(ele => { return ele.lastRefresh })
|
||||
.sort((a, b) => { return (a.lastRefresh > b.lastRefresh) ? -1 : 1 })[0]
|
||||
: undefined
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(Home)
|
||||
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
import React from 'react'
|
||||
import KeyboardArrowRight from 'material-ui/svg-icons/hardware/keyboard-arrow-right'
|
||||
import StepperStyled from '../elements/StepperStyled'
|
||||
import StepperStyled from 'components/elements/StepperStyled'
|
||||
|
||||
const stepLabels = [
|
||||
'Detect',
|
||||
'Engage',
|
||||
'Notify',
|
||||
'Mitigated',
|
||||
'Resolved'
|
||||
'Detect',
|
||||
'Engage',
|
||||
'Notify',
|
||||
'Mitigated',
|
||||
'Resolved'
|
||||
]
|
||||
|
||||
const Checkpoint = () => {
|
||||
return (
|
||||
<StepperStyled
|
||||
activeStep={1}
|
||||
connector={<KeyboardArrowRight />}
|
||||
labels={stepLabels}
|
||||
stepLabelClass={'incident-steplabel'}
|
||||
<StepperStyled
|
||||
activeStep={1}
|
||||
connector={<KeyboardArrowRight />}
|
||||
labels={stepLabels}
|
||||
stepLabelClass={'incident-steplabel'}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default Checkpoint
|
||||
export default Checkpoint
|
||||
|
|
|
@ -1,36 +1,36 @@
|
|||
import { connect } from 'react-redux'
|
||||
|
||||
import PropTypes from 'prop-types'
|
||||
import { CollapsibleGridSet } from '../elements/CollapsibleGrid'
|
||||
import { mapStateToProps } from './DisplayIncident'
|
||||
import { IncidentSummary, IncidentSummaryName } from './IncidentSummary'
|
||||
import { IncidentEvents, IncidentEventsName } from './IncidentEvents'
|
||||
import { CollapsibleGridSet } from 'components/elements/CollapsibleGrid'
|
||||
import { mapStateToProps } from 'components/Incident/DisplayIncident'
|
||||
import { IncidentSummary, IncidentSummaryName } from 'components/Incident/IncidentSummary'
|
||||
import { IncidentEvents, IncidentEventsName } from 'components/Incident/IncidentEvents'
|
||||
|
||||
export const CompareIncidents = ({firstIncident, firstTicket, firstTicketSystem, secondIncident, secondTicket, secondTicketSystem, expandSection, dispatch}) => {
|
||||
const ticketIdToIncidentIdMap = [[firstTicket.originId, firstIncident.id], [secondTicket.originId, secondIncident.id]]
|
||||
return CollapsibleGridSet('incident-container', 'incident-row', 'incident-col', [
|
||||
IncidentSummary(firstIncident, firstTicket, firstTicketSystem, firstTicket.originId, dispatch),
|
||||
IncidentSummary(secondIncident, secondTicket, secondTicketSystem, secondTicket.originId, dispatch),
|
||||
IncidentEvents(ticketIdToIncidentIdMap)
|
||||
],
|
||||
const ticketIdToIncidentIdMap = [[firstTicket.originId, firstIncident.id], [secondTicket.originId, secondIncident.id]]
|
||||
return CollapsibleGridSet('incident-container', 'incident-row', 'incident-col', [
|
||||
IncidentSummary(firstIncident, firstTicket, firstTicketSystem, firstTicket.originId, dispatch),
|
||||
IncidentSummary(secondIncident, secondTicket, secondTicketSystem, secondTicket.originId, dispatch),
|
||||
IncidentEvents(ticketIdToIncidentIdMap)
|
||||
],
|
||||
[
|
||||
IncidentSummaryName(firstTicket.originId),
|
||||
IncidentSummaryName(secondTicket.originId),
|
||||
IncidentEventsName()
|
||||
IncidentSummaryName(firstTicket.originId),
|
||||
IncidentSummaryName(secondTicket.originId),
|
||||
IncidentEventsName()
|
||||
],
|
||||
expandSection,
|
||||
dispatch)
|
||||
}
|
||||
|
||||
CompareIncidents.propTypes = {
|
||||
firstIncident: PropTypes.object,
|
||||
firstTicket: PropTypes.object,
|
||||
firstTicketSystem: PropTypes.object.isRequired,
|
||||
secondIncident: PropTypes.object,
|
||||
secondTicket: PropTypes.object,
|
||||
secondTicketSystem: PropTypes.object.isRequired,
|
||||
expandSection: PropTypes.object,
|
||||
dispatch: PropTypes.func.isRequired
|
||||
firstIncident: PropTypes.object,
|
||||
firstTicket: PropTypes.object,
|
||||
firstTicketSystem: PropTypes.object.isRequired,
|
||||
secondIncident: PropTypes.object,
|
||||
secondTicket: PropTypes.object,
|
||||
secondTicketSystem: PropTypes.object.isRequired,
|
||||
expandSection: PropTypes.object,
|
||||
dispatch: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(CompareIncidents)
|
||||
|
|
|
@ -3,89 +3,82 @@ import { Redirect } from 'react-router'
|
|||
import { Route } from 'react-router-dom'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, { Component } from 'react'
|
||||
import CompareIncidents from './CompareIncidents'
|
||||
import { fetchIncidentIfNeeded } from '../../actions/incidentActions'
|
||||
import { ErrorLoadingIncident, CurrentlyLoadingIncident, UnexpectedFailureToLoadIncident, getInfoByTicketId } from './Ticket'
|
||||
import CompareIncidents from 'components/Incident/CompareIncidents'
|
||||
import { fetchIncidentIfNeeded } from 'actions/incidentActions'
|
||||
import { ErrorLoadingIncident, CurrentlyLoadingIncident, UnexpectedFailureToLoadIncident, getInfoByTicketId } from 'components/Incident/Ticket'
|
||||
|
||||
class CompareTickets extends Component {
|
||||
static propTypes = {
|
||||
first: PropTypes.object.isRequired,
|
||||
second: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
preferences: PropTypes.object.isRequired
|
||||
}
|
||||
static propTypes = {
|
||||
first: PropTypes.object.isRequired,
|
||||
second: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
preferences: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
componentDidMount () {
|
||||
const {
|
||||
first,
|
||||
second,
|
||||
preferences,
|
||||
dispatch
|
||||
} = this.props
|
||||
dispatch(fetchIncidentIfNeeded(first.incident, first.ticketId, first.ticket, first.ticketSystem, preferences))
|
||||
dispatch(fetchIncidentIfNeeded(second.incident, second.ticketId, second.ticket, second.ticketSystem, preferences))
|
||||
}
|
||||
dispatch(fetchIncidentIfNeeded(first.incident, first.ticketId, first.ticket, first.ticketSystem, preferences))
|
||||
dispatch(fetchIncidentIfNeeded(second.incident, second.ticketId, second.ticket, second.ticketSystem, preferences))
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
render () {
|
||||
const {
|
||||
first,
|
||||
second
|
||||
} = this.props
|
||||
|
||||
if(first.incidentIsFetching)
|
||||
{
|
||||
return CurrentlyLoadingIncident(first.incident, first.ticketId)
|
||||
}
|
||||
if(second.incidentIsFetching)
|
||||
{
|
||||
return CurrentlyLoadingIncident(second.incident, second.ticketId)
|
||||
}
|
||||
if(!first.incident || !first.ticket || first.incident.error)
|
||||
{
|
||||
return ErrorLoadingIncident(first.incident, first.ticketId)
|
||||
}
|
||||
if(!second.incident || !second.ticket || second.incident.error)
|
||||
{
|
||||
return ErrorLoadingIncident(second.incident, second.ticketId)
|
||||
}
|
||||
if(!first.incident || !first.ticket || first.incident.error)
|
||||
{
|
||||
return UnexpectedFailureToLoadIncident()
|
||||
}
|
||||
if(!second.incident || !second.ticket || second.incident.error)
|
||||
{
|
||||
return UnexpectedFailureToLoadIncident()
|
||||
}
|
||||
if(first.incident.primaryTicket.originId === first.ticket.originId
|
||||
&& second.incident.primaryTicket.originId === second.ticket.originId)
|
||||
{
|
||||
return <CompareIncidents
|
||||
firstIncident={first.incident}
|
||||
firstTicket={first.ticket}
|
||||
firstTicketSystem={first.ticketSystem}
|
||||
secondIncident={second.incident}
|
||||
secondTicket={second.ticket}
|
||||
secondTicketSystem={second.ticketSystem}
|
||||
/>
|
||||
}
|
||||
return (
|
||||
<Redirect to={`/tickets/${first.incident.primaryTicket.originId}/compare/${second.incident.primaryTicket.originId}`}>
|
||||
<Route path='/tickets/:firstTicketId/compare/:secondTicketId' component={connectedCompareTickets}/>
|
||||
</Redirect>
|
||||
)
|
||||
if (first.incidentIsFetching) {
|
||||
return CurrentlyLoadingIncident(first.incident, first.ticketId)
|
||||
}
|
||||
if (second.incidentIsFetching) {
|
||||
return CurrentlyLoadingIncident(second.incident, second.ticketId)
|
||||
}
|
||||
if (!first.incident || !first.ticket || first.incident.error) {
|
||||
return ErrorLoadingIncident(first.incident, first.ticketId)
|
||||
}
|
||||
if (!second.incident || !second.ticket || second.incident.error) {
|
||||
return ErrorLoadingIncident(second.incident, second.ticketId)
|
||||
}
|
||||
if (!first.incident || !first.ticket || first.incident.error) {
|
||||
return UnexpectedFailureToLoadIncident()
|
||||
}
|
||||
if (!second.incident || !second.ticket || second.incident.error) {
|
||||
return UnexpectedFailureToLoadIncident()
|
||||
}
|
||||
if (first.incident.primaryTicket.originId === first.ticket.originId &&
|
||||
second.incident.primaryTicket.originId === second.ticket.originId) {
|
||||
return <CompareIncidents
|
||||
firstIncident={first.incident}
|
||||
firstTicket={first.ticket}
|
||||
firstTicketSystem={first.ticketSystem}
|
||||
secondIncident={second.incident}
|
||||
secondTicket={second.ticket}
|
||||
secondTicketSystem={second.ticketSystem}
|
||||
/>
|
||||
}
|
||||
return (
|
||||
<Redirect to={`/tickets/${first.incident.primaryTicket.originId}/compare/${second.incident.primaryTicket.originId}`}>
|
||||
<Route path='/tickets/:firstTicketId/compare/:secondTicketId' component={connectedCompareTickets} />
|
||||
</Redirect>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const { match } = ownProps
|
||||
const firstTicketId = parseInt(match.params.firstTicketId)
|
||||
const secondTicketId = parseInt(match.params.secondTicketId)
|
||||
return {
|
||||
first: getInfoByTicketId(state, firstTicketId),
|
||||
second: getInfoByTicketId(state, secondTicketId),
|
||||
preferences: state.tickets.preferences
|
||||
}
|
||||
const { match } = ownProps
|
||||
const firstTicketId = parseInt(match.params.firstTicketId)
|
||||
const secondTicketId = parseInt(match.params.secondTicketId)
|
||||
return {
|
||||
first: getInfoByTicketId(state, firstTicketId),
|
||||
second: getInfoByTicketId(state, secondTicketId),
|
||||
preferences: state.tickets.preferences
|
||||
}
|
||||
}
|
||||
|
||||
const connectedCompareTickets = connect(mapStateToProps)(CompareTickets)
|
||||
export default connectedCompareTickets
|
||||
export default connectedCompareTickets
|
||||
|
|
|
@ -6,38 +6,37 @@ import MenuItem from 'material-ui/MenuItem'
|
|||
import { Link } from 'react-router-dom'
|
||||
|
||||
export const ComparisonLinks = ({otherIncidentTicketIds, ticketId}) => {
|
||||
let key = 0
|
||||
return <SelectField floatingLabelText="Compare With Incident">
|
||||
{otherIncidentTicketIds.map(otherTicketId =>
|
||||
<MenuItem
|
||||
key={key++}
|
||||
primaryText={
|
||||
<Link to={`/tickets/${ticketId}/compare/${otherTicketId}`}>
|
||||
{otherTicketId}
|
||||
</Link>
|
||||
let key = 0
|
||||
return <SelectField floatingLabelText='Compare With Incident'>
|
||||
{otherIncidentTicketIds.map(otherTicketId =>
|
||||
<MenuItem
|
||||
key={key++}
|
||||
primaryText={
|
||||
<Link to={`/tickets/${ticketId}/compare/${otherTicketId}`}>
|
||||
{otherTicketId}
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</SelectField>
|
||||
|
||||
</SelectField>
|
||||
}
|
||||
|
||||
export const mapStateToProps = (state, ownProps) => {
|
||||
const { ticketId } = ownProps
|
||||
const thisIncidentId = state.tickets.map[ticketId].incidentId
|
||||
const otherIncidentTicketIds = Object.values(state.incidents.map)
|
||||
const { ticketId } = ownProps
|
||||
const thisIncidentId = state.tickets.map[ticketId].incidentId
|
||||
const otherIncidentTicketIds = Object.values(state.incidents.map)
|
||||
.filter(incident => incident && incident.primaryTicket && incident.primaryTicket.originId)
|
||||
.filter(incident => incident.id !== thisIncidentId)
|
||||
.map(incident => incident.primaryTicket.originId)
|
||||
return {
|
||||
ticketId: ownProps.ticketId,
|
||||
otherIncidentTicketIds
|
||||
}
|
||||
return {
|
||||
ticketId: ownProps.ticketId,
|
||||
otherIncidentTicketIds
|
||||
}
|
||||
}
|
||||
|
||||
ComparisonLinks.propTypes = {
|
||||
otherIncidentTicketIds: PropTypes.array,
|
||||
ticketId: PropTypes.number
|
||||
otherIncidentTicketIds: PropTypes.array,
|
||||
ticketId: PropTypes.number
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(ComparisonLinks)
|
||||
export default connect(mapStateToProps)(ComparisonLinks)
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
import PropTypes from 'prop-types'
|
||||
import { CollapsibleGridSet } from '../elements/CollapsibleGrid'
|
||||
import { CollapsibleGridSet } from 'components/elements/CollapsibleGrid'
|
||||
import { connect } from 'react-redux'
|
||||
import { IncidentSummary, IncidentSummaryName } from './IncidentSummary'
|
||||
import { IncidentEvents, IncidentEventsName } from './IncidentEvents'
|
||||
import { IncidentSummary, IncidentSummaryName } from 'components/Incident/IncidentSummary'
|
||||
import { IncidentEvents, IncidentEventsName } from 'components/Incident/IncidentEvents'
|
||||
|
||||
export const DisplayIncident = ({incident, ticket, ticketSystem, expandSection, dispatch}) => {
|
||||
return CollapsibleGridSet('incident-container', 'incident-row', 'incident-col', [
|
||||
IncidentSummary({incident, ticket, ticketSystem, ticketOriginId:ticket.originId, dispatch}),
|
||||
IncidentEvents([[ticket.originId, incident.id]])
|
||||
],
|
||||
return CollapsibleGridSet('incident-container', 'incident-row', 'incident-col', [
|
||||
IncidentSummary({incident, ticket, ticketSystem, ticketOriginId: ticket.originId, dispatch}),
|
||||
IncidentEvents([[ticket.originId, incident.id]])
|
||||
],
|
||||
[
|
||||
IncidentSummaryName(),
|
||||
IncidentEventsName()
|
||||
IncidentSummaryName(),
|
||||
IncidentEventsName()
|
||||
],
|
||||
expandSection, dispatch)
|
||||
}
|
||||
|
||||
DisplayIncident.propTypes = {
|
||||
incident: PropTypes.object,
|
||||
ticket: PropTypes.object,
|
||||
ticketSystem: PropTypes.object,
|
||||
expandSection: PropTypes.object,
|
||||
dispatch: PropTypes.func.isRequired
|
||||
incident: PropTypes.object,
|
||||
ticket: PropTypes.object,
|
||||
ticketSystem: PropTypes.object,
|
||||
expandSection: PropTypes.object,
|
||||
dispatch: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export const mapStateToProps = (state, ownProps) => ({
|
||||
...ownProps,
|
||||
expandSection: state.expandSection
|
||||
...ownProps,
|
||||
expandSection: state.expandSection
|
||||
})
|
||||
|
||||
export default connect(mapStateToProps)(DisplayIncident)
|
||||
|
|
|
@ -1,27 +1,27 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Timeline from '../Timeline/Timeline'
|
||||
import Timeline from 'components/Timeline/Timeline'
|
||||
|
||||
export const IncidentEventsName = () => {
|
||||
return 'IncidentEvents'
|
||||
return 'IncidentEvents'
|
||||
}
|
||||
|
||||
export const IncidentEvents = (ticketToIncidentIdMap) => [
|
||||
[
|
||||
[
|
||||
[
|
||||
(key) =><strong key={key}>
|
||||
(key) => <strong key={key}>
|
||||
Incident Timeline:
|
||||
</strong>
|
||||
]
|
||||
],
|
||||
[
|
||||
<Timeline
|
||||
ticketId={ticketToIncidentIdMap[0][0]}
|
||||
incidentId={ticketToIncidentIdMap[0][1]}
|
||||
/>
|
||||
]
|
||||
],
|
||||
[
|
||||
<Timeline
|
||||
ticketId={ticketToIncidentIdMap[0][0]}
|
||||
incidentId={ticketToIncidentIdMap[0][1]}
|
||||
/>
|
||||
]
|
||||
]
|
||||
|
||||
IncidentEvents.propTypes = {
|
||||
ticketToIncidentIdMap: PropTypes.object
|
||||
ticketToIncidentIdMap: PropTypes.object
|
||||
}
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import BadgeStyled from '../elements/BadgeStyled'
|
||||
import BadgeStyled from 'components/elements/BadgeStyled'
|
||||
import NotificationsIcon from 'material-ui/svg-icons/social/notifications'
|
||||
import IconButtonStyled from '../elements/IconButtonStyled'
|
||||
import Checkpoint from './Checkpoint'
|
||||
import IconButtonStyled from 'components/elements/IconButtonStyled'
|
||||
import Checkpoint from 'components/Incident/Checkpoint'
|
||||
|
||||
export const IncidentProgressName = (ticketId) => {
|
||||
return 'IncidentProgress' + (ticketId ? '_' + ticketId : '')
|
||||
return 'IncidentProgress' + (ticketId ? '_' + ticketId : '')
|
||||
}
|
||||
|
||||
export const IncidentProgress = (ticketId) => [
|
||||
[
|
||||
[
|
||||
[
|
||||
(key) =>
|
||||
<strong key={key}>
|
||||
Incident Progress{ticketId ? ` for ${ticketId}`:''}:
|
||||
(key) =>
|
||||
<strong key={key}>
|
||||
Incident Progress{ticketId ? ` for ${ticketId}` : ''}:
|
||||
|
||||
<BadgeStyled badgeContent={4}>
|
||||
<IconButtonStyled tooltip="Suggested actions">
|
||||
<NotificationsIcon />
|
||||
</IconButtonStyled>
|
||||
<IconButtonStyled tooltip='Suggested actions'>
|
||||
<NotificationsIcon />
|
||||
</IconButtonStyled>
|
||||
</BadgeStyled>
|
||||
</strong>
|
||||
]
|
||||
],
|
||||
</strong>
|
||||
]
|
||||
],
|
||||
[Checkpoint()]
|
||||
]
|
||||
|
||||
IncidentProgress.propTypes = {
|
||||
ticketId: PropTypes.object
|
||||
ticketId: PropTypes.object
|
||||
}
|
||||
|
|
|
@ -2,60 +2,55 @@ import { connect } from 'react-redux'
|
|||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Redirect } from 'react-router'
|
||||
import * as incidentActions from '../../actions/incidentActions'
|
||||
import LoadingMessage from '../elements/LoadingMessage'
|
||||
import * as incidentActions from 'actions/incidentActions'
|
||||
import LoadingMessage from 'components/elements/LoadingMessage'
|
||||
|
||||
export class IncidentRedirect extends Component {
|
||||
static propTypes = {
|
||||
static propTypes = {
|
||||
incidentIsFetching: PropTypes.bool,
|
||||
ticketId: PropTypes.number,
|
||||
incidentId: PropTypes.number,
|
||||
dispatch: PropTypes.func
|
||||
}
|
||||
}
|
||||
|
||||
constructor(props){
|
||||
super(props)
|
||||
}
|
||||
componentDidMount () {
|
||||
IncidentRedirectComponentDidMount(this.props)
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
IncidentRedirectComponentDidMount(this.props)
|
||||
render () {
|
||||
if (this.props.ticketId) {
|
||||
return (<Redirect to={`/tickets/${this.props.ticketId}`} />)
|
||||
}
|
||||
|
||||
render() {
|
||||
if(this.props.ticketId){
|
||||
return (<Redirect to={`/tickets/${this.props.ticketId}`}/>)
|
||||
}
|
||||
if(this.props.incidentIsFetching)
|
||||
{
|
||||
return LoadingMessage('Loading incident information')
|
||||
}
|
||||
return (<div>Unexpected error or interruption when loading incident</div>)
|
||||
if (this.props.incidentIsFetching) {
|
||||
return LoadingMessage('Loading incident information')
|
||||
}
|
||||
return (<div>Unexpected error or interruption when loading incident</div>)
|
||||
}
|
||||
}
|
||||
|
||||
export const IncidentRedirectComponentDidMount = (props) => {
|
||||
const { ticketId, incidentId, dispatch } = props
|
||||
if(!ticketId){
|
||||
dispatch(incidentActions.fetchIncident(incidentId))
|
||||
}
|
||||
const { ticketId, incidentId, dispatch } = props
|
||||
if (!ticketId) {
|
||||
dispatch(incidentActions.fetchIncident(incidentId))
|
||||
}
|
||||
}
|
||||
|
||||
export const mapStateToProps = (state, ownProps) => {
|
||||
const incidentId = (ownProps && ownProps.match && ownProps.match.params)
|
||||
const incidentId = (ownProps && ownProps.match && ownProps.match.params)
|
||||
? ownProps.match.params.incidentId
|
||||
: null
|
||||
const incident = (state && state.incidents && state.incidents.map)
|
||||
const incident = (state && state.incidents && state.incidents.map)
|
||||
? state.incidents.map[incidentId]
|
||||
: null
|
||||
return {
|
||||
incidentId,
|
||||
incidentIsFetching: (state && state.incidents && state.incidents.fetchingByIncidentId && Array.isArray(state.incidents.fetchingByIncidentId))
|
||||
return {
|
||||
incidentId,
|
||||
incidentIsFetching: (state && state.incidents && state.incidents.fetchingByIncidentId && Array.isArray(state.incidents.fetchingByIncidentId))
|
||||
? state.incidents.fetchingByIncidentId.includes(incidentId)
|
||||
: null,
|
||||
ticketId: (incident && incident.primaryTicket)
|
||||
ticketId: (incident && incident.primaryTicket)
|
||||
? incident.primaryTicket.originId
|
||||
: null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(IncidentRedirect)
|
||||
|
|
|
@ -1,81 +1,81 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import SyncIcon from 'material-ui/svg-icons/notification/sync'
|
||||
import IconButtonStyled from '../elements/IconButtonStyled'
|
||||
import ModeEditIcon from 'material-ui/svg-icons/editor/mode-edit'
|
||||
import Engagements from '../Engagements'
|
||||
import GlobalActions from '../Timeline/Playbook/GlobalActions'
|
||||
|
||||
import IconButtonStyled from 'components/elements/IconButtonStyled'
|
||||
import Engagements from 'components/Engagements'
|
||||
import GlobalActions from 'components/Timeline/Playbook/GlobalActions'
|
||||
|
||||
export const IncidentSummaryName = (ticketId) => {
|
||||
return 'IncidentSummary' + (ticketId ? '_' + ticketId : '')
|
||||
return 'IncidentSummary' + (ticketId ? '_' + ticketId : '')
|
||||
}
|
||||
|
||||
|
||||
export const IncidentSummary = ({incident, ticket, ticketSystem, ticketOriginId, dispatch}) =>
|
||||
[
|
||||
[
|
||||
HeaderRow(ticketOriginId),
|
||||
TicketDetailsRow(ticketSystem, ticket),
|
||||
TitleRow(incident),
|
||||
GlobalActionsRow(incident, ticketOriginId),
|
||||
EngagementsRow(incident, dispatch)
|
||||
]
|
||||
]
|
||||
IncidentSummary.propTypes = {
|
||||
incident: PropTypes.object,
|
||||
ticket: PropTypes.object,
|
||||
ticketSystem: PropTypes.object,
|
||||
expandSection: PropTypes.object,
|
||||
dispatch: PropTypes.func.isRequired
|
||||
incident: PropTypes.object,
|
||||
ticket: PropTypes.object,
|
||||
ticketSystem: PropTypes.object,
|
||||
expandSection: PropTypes.object,
|
||||
dispatch: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
const HeaderRow = (ticketId) => [
|
||||
[
|
||||
(key) =>
|
||||
<strong key={key}>
|
||||
Incident Summary{ticketId ? ` for ${ticketId}`:''}:
|
||||
[
|
||||
(key) =>
|
||||
<strong key={key}>
|
||||
Incident Summary{ticketId ? ` for ${ticketId}` : ''}:
|
||||
|
||||
<IconButtonStyled tooltip="Refresh">
|
||||
<SyncIcon />
|
||||
<IconButtonStyled tooltip='Refresh'>
|
||||
<SyncIcon />
|
||||
</IconButtonStyled>
|
||||
</strong>
|
||||
]
|
||||
</strong>
|
||||
]
|
||||
]
|
||||
|
||||
const TicketDetailsRow = (ticketSystem, ticket) => [
|
||||
BasicInfoColumn(ticketSystem, ticket),
|
||||
IncidentManagerColumn(ticket)
|
||||
BasicInfoColumn(ticketSystem, ticket),
|
||||
IncidentManagerColumn(ticket)
|
||||
]
|
||||
|
||||
const BasicInfoColumn = (ticketSystem, ticket) => [
|
||||
(key) =>
|
||||
<a href={`${ticketSystem.ticketUriPrefix}${ticket.originId}${ticketSystem.ticketUriSuffix}`} key={key} target="_blank">
|
||||
{ticket.originId}
|
||||
</a>,
|
||||
(key) =>
|
||||
<div key={key}>
|
||||
{ticket.severity}
|
||||
</div>
|
||||
(key) =>
|
||||
<a href={`${ticketSystem.ticketUriPrefix}${ticket.originId}${ticketSystem.ticketUriSuffix}`} key={key} target='_blank'>
|
||||
{ticket.originId}
|
||||
</a>,
|
||||
(key) =>
|
||||
<div key={key}>
|
||||
{ticket.severity}
|
||||
</div>
|
||||
]
|
||||
|
||||
const IncidentManagerColumn = (ticket) => [
|
||||
(key) =>
|
||||
<div key={key}>
|
||||
{ticket.imName}
|
||||
</div>,
|
||||
(key) =>
|
||||
<IconButtonStyled tooltip="Edit IM" key={key}>
|
||||
<ModeEditIcon />
|
||||
</IconButtonStyled>
|
||||
(key) =>
|
||||
<div key={key}>
|
||||
{ticket.imName}
|
||||
</div>,
|
||||
(key) =>
|
||||
<IconButtonStyled tooltip='Edit IM' key={key}>
|
||||
<ModeEditIcon />
|
||||
</IconButtonStyled>
|
||||
]
|
||||
|
||||
const noTitleMessage = 'No Title!'
|
||||
|
||||
const TitleRow = (incident) => [
|
||||
<div>
|
||||
{DoesIncidentHaveTitle(incident) ? incident.title
|
||||
<div>
|
||||
{DoesIncidentHaveTitle(incident) ? incident.title
|
||||
: DoesPrimaryTicketHaveNativeTitle(incident) ? incident.primaryTicket.title
|
||||
: DoesPrimaryTicketHaveDataTitle(incident) ? incident.primaryTicket.data.Title
|
||||
: noTitleMessage}
|
||||
</div>
|
||||
</div>
|
||||
]
|
||||
|
||||
const DoesIncidentHaveTitle = (incident) =>
|
||||
|
@ -88,19 +88,19 @@ const DoesPrimaryTicketHaveDataTitle = (incident) =>
|
|||
incident && incident.primaryTicket && incident.primaryTicket.data && incident.primaryTicket.data.Title
|
||||
|
||||
const EngagementsRow = (incident, dispatch) => [
|
||||
<Engagements
|
||||
incidentId={incident.id}
|
||||
engagements={incident.engagements}
|
||||
dispatch={dispatch}
|
||||
<Engagements
|
||||
incidentId={incident.id}
|
||||
engagements={incident.engagements}
|
||||
dispatch={dispatch}
|
||||
/>
|
||||
]
|
||||
|
||||
const GlobalActionsRow = (incident, ticketId) => [
|
||||
[
|
||||
(key) => <GlobalActions
|
||||
incidentId={incident.id}
|
||||
ticketId={ticketId}
|
||||
key={key}
|
||||
[
|
||||
(key) => <GlobalActions
|
||||
incidentId={incident.id}
|
||||
ticketId={ticketId}
|
||||
key={key}
|
||||
/>
|
||||
]
|
||||
]
|
||||
]
|
||||
|
|
|
@ -3,33 +3,33 @@ import { Redirect } from 'react-router'
|
|||
import { Route } from 'react-router-dom'
|
||||
import PropTypes from 'prop-types'
|
||||
import React, { Component } from 'react'
|
||||
import DisplayIncident from './DisplayIncident'
|
||||
import LoadingMessage from '../elements/LoadingMessage'
|
||||
import ErrorMessage from '../elements/ErrorMessage'
|
||||
import * as incidentActions from '../../actions/incidentActions'
|
||||
import { fetchEventTypes } from '../../actions/eventTypeActions'
|
||||
import DisplayIncident from 'components/Incident/DisplayIncident'
|
||||
import LoadingMessage from 'components/elements/LoadingMessage'
|
||||
import ErrorMessage from 'components/elements/ErrorMessage'
|
||||
import * as incidentActions from 'actions/incidentActions'
|
||||
import { fetchEventTypes } from 'actions/eventTypeActions'
|
||||
|
||||
class Ticket extends Component {
|
||||
static propTypes = {
|
||||
incidentId: PropTypes.number,
|
||||
incident: PropTypes.object,
|
||||
incidentIsFetching: PropTypes.bool,
|
||||
incidentIsError: PropTypes.bool,
|
||||
ticket: PropTypes.object,
|
||||
ticketId: PropTypes.number,
|
||||
ticketSystem: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
preferences: PropTypes.object.isRequired
|
||||
}
|
||||
static propTypes = {
|
||||
incidentId: PropTypes.number,
|
||||
incident: PropTypes.object,
|
||||
incidentIsFetching: PropTypes.bool,
|
||||
incidentIsError: PropTypes.bool,
|
||||
ticket: PropTypes.object,
|
||||
ticketId: PropTypes.number,
|
||||
ticketSystem: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
preferences: PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { dispatch, incident, ticketId, ticket, ticketSystem, preferences, incidentIsFetching, incidentIsError } = this.props
|
||||
dispatch(incidentActions.fetchIncidentIfNeeded(incident, ticketId, ticket, ticketSystem, preferences, incidentIsFetching, incidentIsError))
|
||||
dispatch(fetchEventTypes())
|
||||
}
|
||||
componentDidMount () {
|
||||
const { dispatch, incident, ticketId, ticket, ticketSystem, preferences, incidentIsFetching, incidentIsError } = this.props
|
||||
dispatch(incidentActions.fetchIncidentIfNeeded(incident, ticketId, ticket, ticketSystem, preferences, incidentIsFetching, incidentIsError))
|
||||
dispatch(fetchEventTypes())
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
render () {
|
||||
const {
|
||||
incident,
|
||||
ticket,
|
||||
ticketId,
|
||||
|
@ -38,56 +38,52 @@ class Ticket extends Component {
|
|||
incidentIsError
|
||||
} = this.props
|
||||
|
||||
if(incidentIsFetching)
|
||||
{
|
||||
return CurrentlyLoadingIncident(incident, ticketId)
|
||||
}
|
||||
if(incidentIsError)
|
||||
{
|
||||
return ErrorLoadingIncident(incident, ticketId)
|
||||
}
|
||||
if(!incident || !incident.primaryTicket || !ticket || incident.error)
|
||||
{
|
||||
return UnexpectedFailureToLoadIncident()
|
||||
}
|
||||
if(incident.primaryTicket.originId && incident.primaryTicket.originId === ticket.originId)
|
||||
{
|
||||
return <DisplayIncident
|
||||
incident={incident}
|
||||
ticket={ticket}
|
||||
ticketSystem={ticketSystem}
|
||||
/>
|
||||
}
|
||||
return (
|
||||
<Redirect to={`/tickets/${incident.primaryTicket.originId}`}>
|
||||
<Route path='/tickets/:ticketId' component={connectedTicket}/>
|
||||
</Redirect>
|
||||
)
|
||||
if (incidentIsFetching) {
|
||||
return CurrentlyLoadingIncident(incident, ticketId)
|
||||
}
|
||||
if (incidentIsError) {
|
||||
return ErrorLoadingIncident(incident, ticketId)
|
||||
}
|
||||
if (!incident || !incident.primaryTicket || !ticket || incident.error) {
|
||||
return UnexpectedFailureToLoadIncident()
|
||||
}
|
||||
if (incident.primaryTicket.originId && incident.primaryTicket.originId === ticket.originId) {
|
||||
return <DisplayIncident
|
||||
incident={incident}
|
||||
ticket={ticket}
|
||||
ticketSystem={ticketSystem}
|
||||
/>
|
||||
}
|
||||
return (
|
||||
<Redirect to={`/tickets/${incident.primaryTicket.originId}`}>
|
||||
<Route path='/tickets/:ticketId' component={connectedTicket} />
|
||||
</Redirect>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const ticketId = parseInt(ownProps.match.params.ticketId)
|
||||
return {
|
||||
...getInfoByTicketId(state, ticketId),
|
||||
preferences: state.tickets.preferences
|
||||
}
|
||||
const ticketId = parseInt(ownProps.match.params.ticketId)
|
||||
return {
|
||||
...getInfoByTicketId(state, ticketId),
|
||||
preferences: state.tickets.preferences
|
||||
}
|
||||
}
|
||||
|
||||
export const getInfoByTicketId = (state, ticketId) => {
|
||||
const { incidents, tickets } = state
|
||||
const ticket = tickets.map[ticketId]
|
||||
const incident = getIncident(ticket, incidents)
|
||||
return {
|
||||
incident,
|
||||
ticket,
|
||||
ticketId,
|
||||
ticketSystem: tickets.systems[getTicketSystemId(ticket)],
|
||||
incidentIsFetching: incidents.fetchingByTicketId.includes(ticketId) ||
|
||||
const { incidents, tickets } = state
|
||||
const ticket = tickets.map[ticketId]
|
||||
const incident = getIncident(ticket, incidents)
|
||||
return {
|
||||
incident,
|
||||
ticket,
|
||||
ticketId,
|
||||
ticketSystem: tickets.systems[getTicketSystemId(ticket)],
|
||||
incidentIsFetching: incidents.fetchingByTicketId.includes(ticketId) ||
|
||||
(incident && incident.id && incidents.fetchingByIncidentId.includes(incident.id)),
|
||||
incidentIsError: incidents.errorByTicketId.includes(ticketId) ||
|
||||
incidentIsError: incidents.errorByTicketId.includes(ticketId) ||
|
||||
(incident && incident.id && incidents.errorByIncidentId.includes(incident.id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const getTicketSystemId = (ticket) => ticket ? (ticket.ticketSystemId ? ticket.ticketSystemId : 1) : 1
|
||||
|
@ -115,5 +111,3 @@ const DetermineRetryAction = (incident, ticketId) => (incident && incident.id)
|
|||
|
||||
const connectedTicket = connect(mapStateToProps)(Ticket)
|
||||
export default connectedTicket
|
||||
|
||||
|
||||
|
|
|
@ -6,14 +6,14 @@ import { BrowserRouter as Router, Route } from 'react-router-dom'
|
|||
import createBrowserHistory from 'history/createBrowserHistory'
|
||||
import { PersistGate } from 'redux-persist/lib/integration/react'
|
||||
|
||||
import CreateIncident from './Search/CreateIncident'
|
||||
import Ticket from './Incident/Ticket'
|
||||
import CompareTickets from './Incident/CompareTickets'
|
||||
import EnsureLoggedInContainer from './Auth/EnsureLoggedIn'
|
||||
import incidentRedirect from './Incident/incidentRedirect'
|
||||
import Home from './Home'
|
||||
import TopNav from './TopNav/TopNav'
|
||||
import Debug from './Debug'
|
||||
import CreateIncident from 'components/Search/CreateIncident'
|
||||
import Ticket from 'components/Incident/Ticket'
|
||||
import CompareTickets from 'components/Incident/CompareTickets'
|
||||
import EnsureLoggedInContainer from 'components/Auth/EnsureLoggedIn'
|
||||
import incidentRedirect from 'components/Incident/incidentRedirect'
|
||||
import Home from 'components/Home'
|
||||
import TopNav from 'components/TopNav/TopNav'
|
||||
import Debug from 'components/Debug'
|
||||
|
||||
const history = createBrowserHistory()
|
||||
|
||||
|
@ -28,13 +28,13 @@ export default class MainComponent extends React.Component {
|
|||
<Router history={history} >
|
||||
<div>
|
||||
<TopNav />
|
||||
<Route exact path="/" component={Home} />
|
||||
<Route exact path="/extension.html" component={Home} />
|
||||
<Route path="/search" component={CreateIncident} />
|
||||
<Route path="/tickets/:ticketId" component={Ticket} />
|
||||
<Route path="/tickets/:firstTicketId/compare/:secondTicketId" component={CompareTickets} />
|
||||
<Route path="/incidents/:incidentId" component={incidentRedirect} />
|
||||
<Route path="/debug" render={() => <Debug />}/>
|
||||
<Route exact path='/' component={Home} />
|
||||
<Route exact path='/extension.html' component={Home} />
|
||||
<Route path='/search' component={CreateIncident} />
|
||||
<Route path='/tickets/:ticketId' component={Ticket} />
|
||||
<Route path='/tickets/:firstTicketId/compare/:secondTicketId' component={CompareTickets} />
|
||||
<Route path='/incidents/:incidentId' component={incidentRedirect} />
|
||||
<Route path='/debug' render={() => <Debug />} />
|
||||
</div>
|
||||
</Router>
|
||||
</EnsureLoggedInContainer>
|
||||
|
|
|
@ -2,44 +2,44 @@ import React from 'react'
|
|||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import { TextField } from 'material-ui'
|
||||
import FlatButtonStyled from '../elements/FlatButtonStyled'
|
||||
import { updateIncidentCreationInput } from '../../actions/incidentActions'
|
||||
import FlatButtonStyled from 'components/elements/FlatButtonStyled'
|
||||
import { updateIncidentCreationInput } from 'actions/incidentActions'
|
||||
|
||||
const onSubmit = (input, history) => () => {
|
||||
if (input) {
|
||||
history.push(/tickets/ + input)
|
||||
}
|
||||
if (input) {
|
||||
history.push(/tickets/ + input)
|
||||
}
|
||||
}
|
||||
|
||||
export const CreateIncident = ({input, creationError, history, dispatch}) => {
|
||||
return <form id='incident-search' onSubmit={onSubmit(input, history)}>
|
||||
<TextField
|
||||
hintText='Ticket Id of primary ticket'
|
||||
floatingLabelText='Ticket Id'
|
||||
onChange={(event, newValue) => dispatch(updateIncidentCreationInput(newValue))}
|
||||
value={input}
|
||||
errorText={creationError}
|
||||
return <form id='incident-search' onSubmit={onSubmit(input, history)}>
|
||||
<TextField
|
||||
hintText='Ticket Id of primary ticket'
|
||||
floatingLabelText='Ticket Id'
|
||||
onChange={(event, newValue) => dispatch(updateIncidentCreationInput(newValue))}
|
||||
value={input}
|
||||
errorText={creationError}
|
||||
/>
|
||||
<FlatButtonStyled
|
||||
label='Submit'
|
||||
onTouchTap={onSubmit(input, history)}
|
||||
<FlatButtonStyled
|
||||
label='Submit'
|
||||
onTouchTap={onSubmit(input, history)}
|
||||
/>
|
||||
</form>
|
||||
</form>
|
||||
}
|
||||
|
||||
export const mapStateToProps = (state) => {
|
||||
return {
|
||||
input: state.incidents.creation.input,
|
||||
ticketSystem: state.tickets.systems[1],
|
||||
creationError: state.incidents.creation.error ? state.incidents.creation.error.message : ''
|
||||
}
|
||||
return {
|
||||
input: state.incidents.creation.input,
|
||||
ticketSystem: state.tickets.systems[1],
|
||||
creationError: state.incidents.creation.error ? state.incidents.creation.error.message : ''
|
||||
}
|
||||
}
|
||||
|
||||
CreateIncident.propTypes = {
|
||||
input: PropTypes.string,
|
||||
creationError: PropTypes.string,
|
||||
history: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired
|
||||
input: PropTypes.string,
|
||||
creationError: PropTypes.string,
|
||||
history: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(CreateIncident)
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import RaisedButtonStyled from '../../components/elements/RaisedButtonStyled'
|
||||
import * as formActions from '../../actions/formActions'
|
||||
import * as eventActions from '../../actions/eventActions'
|
||||
import RaisedButtonStyled from 'components/elements/RaisedButtonStyled'
|
||||
import * as formActions from 'actions/formActions'
|
||||
import * as eventActions from 'actions/eventActions'
|
||||
|
||||
export const addEventFormName = 'AddEvents'
|
||||
export const eventInputKey = 'eventInput'
|
||||
|
@ -15,15 +15,15 @@ export const AddEvent = ({
|
|||
eventInput,
|
||||
eventTypeIdInput
|
||||
}) => <div>
|
||||
{EventInput(eventInput, handleInputChange(dispatch, eventInputKey))}
|
||||
<br/>
|
||||
{EventTypeIdInput(eventTypeIdInput, handleInputChange(dispatch, eventTypeIdInputKey))}
|
||||
<br/>
|
||||
<RaisedButtonStyled
|
||||
onTouchTap={() => {
|
||||
dispatch(eventActions.postEvent(incidentId, eventTypeIdInput))
|
||||
dispatch(formActions.clearForm(addEventFormName))
|
||||
}}
|
||||
{EventInput(eventInput, handleInputChange(dispatch, eventInputKey))}
|
||||
<br />
|
||||
{EventTypeIdInput(eventTypeIdInput, handleInputChange(dispatch, eventTypeIdInputKey))}
|
||||
<br />
|
||||
<RaisedButtonStyled
|
||||
onTouchTap={() => {
|
||||
dispatch(eventActions.postEvent(incidentId, eventTypeIdInput))
|
||||
dispatch(formActions.clearForm(addEventFormName))
|
||||
}}
|
||||
>
|
||||
Add Event
|
||||
</RaisedButtonStyled>
|
||||
|
@ -36,22 +36,22 @@ const handleInputChange = (dispatch, key) => (event) => {
|
|||
const EventInput = (eventInput, updateEventInput) => <label>
|
||||
Event:
|
||||
<input
|
||||
name="event"
|
||||
type="text"
|
||||
name='event'
|
||||
type='text'
|
||||
style={{width: '74%'}}
|
||||
onChange={updateEventInput}
|
||||
value={eventInput ? eventInput : ''}
|
||||
value={eventInput || ''}
|
||||
/>
|
||||
</label>
|
||||
|
||||
const EventTypeIdInput = (eventTypeIdInput, updateEventTypeIdInput) => <label>
|
||||
EventTypeId:
|
||||
<input
|
||||
name="eventTypeId"
|
||||
type="text"
|
||||
name='eventTypeId'
|
||||
type='text'
|
||||
style={{width: '74%'}}
|
||||
onChange={updateEventTypeIdInput}
|
||||
value={eventTypeIdInput ? eventTypeIdInput : 0}
|
||||
value={eventTypeIdInput || 0}
|
||||
/>
|
||||
</label>
|
||||
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
import React from 'react'
|
||||
import { Card, CardHeader, CardText } from 'material-ui/Card'
|
||||
import AddEvent from './AddEvent'
|
||||
import AddEvent from 'components/Timeline/AddEvent'
|
||||
|
||||
export const AddEventCard = (incidentId) => <Card>
|
||||
<CardHeader
|
||||
title={'Add Event'}
|
||||
actAsExpander={true}
|
||||
showExpandableButton={true}
|
||||
<CardHeader
|
||||
title={'Add Event'}
|
||||
actAsExpander
|
||||
showExpandableButton
|
||||
/>
|
||||
|
||||
<CardText expandable={true}>
|
||||
<AddEvent incidentId={incidentId} />
|
||||
</CardText>
|
||||
|
||||
<CardText expandable>
|
||||
<AddEvent incidentId={incidentId} />
|
||||
</CardText>
|
||||
</Card>
|
||||
|
||||
export default AddEventCard
|
||||
|
||||
|
|
|
@ -3,13 +3,12 @@ import { connect } from 'react-redux'
|
|||
import PropTypes from 'prop-types'
|
||||
import moment from 'moment'
|
||||
import { Card, CardHeader, CardText } from 'material-ui/Card'
|
||||
import BootstrapPlaybook from './Playbook/BootstrapPlaybook'
|
||||
import Playbook from './Playbook/Playbook'
|
||||
import { LoadTextFromEvent } from '../../services/playbookService'
|
||||
import ErrorMessage from '../elements/ErrorMessage'
|
||||
import LoadingMessage from '../elements/LoadingMessage'
|
||||
import { TestConditionSet } from '../../services/playbookService'
|
||||
import * as eventTypeActions from '../../actions/eventTypeActions'
|
||||
import BootstrapPlaybook from 'components/Timeline/Playbook/BootstrapPlaybook'
|
||||
import Playbook from 'components/Timeline/Playbook/Playbook'
|
||||
import { LoadTextFromEvent, TestConditionSet } from 'services/playbookService'
|
||||
import ErrorMessage from 'components/elements/ErrorMessage'
|
||||
import LoadingMessage from 'components/elements/LoadingMessage'
|
||||
import * as eventTypeActions from 'actions/eventTypeActions'
|
||||
|
||||
export const Event = ({
|
||||
text,
|
||||
|
@ -25,40 +24,40 @@ export const Event = ({
|
|||
actions,
|
||||
engagementId
|
||||
}) => {
|
||||
const itemHighlight = (event && event.timeReceived) ? {
|
||||
animationName: 'yellowfade',
|
||||
animationDuration: '30s',
|
||||
animationDelay: -(moment().diff(event.timeReceived, 'seconds')) + 's'
|
||||
const itemHighlight = (event && event.timeReceived) ? {
|
||||
animationName: 'yellowfade',
|
||||
animationDuration: '30s',
|
||||
animationDelay: -(moment().diff(event.timeReceived, 'seconds')) + 's'
|
||||
} : {}
|
||||
const isAllPlaybookInfoAvailable = !!(actions && Array.isArray(actions) && actions.length > 0)
|
||||
|
||||
return eventTypeIsFetching && !eventHasValidDisplayText(event)
|
||||
const isAllPlaybookInfoAvailable = !!(actions && Array.isArray(actions) && actions.length > 0)
|
||||
|
||||
return eventTypeIsFetching && !eventHasValidDisplayText(event)
|
||||
? LoadingMessage('Fetching Event Type Information', eventTypeActions.fetchEventType(eventTypeId))
|
||||
: eventTypeIsError && !eventHasValidDisplayText(event)
|
||||
? ErrorMessage('Error fetching eventType!', eventTypeActions.fetchEventType(eventTypeId))
|
||||
: <div style={itemHighlight}>
|
||||
<BootstrapPlaybook
|
||||
eventId={eventId}
|
||||
eventTypeId={eventTypeId}
|
||||
ticketId={ticketId}
|
||||
incidentId={incidentId}
|
||||
<BootstrapPlaybook
|
||||
eventId={eventId}
|
||||
eventTypeId={eventTypeId}
|
||||
ticketId={ticketId}
|
||||
incidentId={incidentId}
|
||||
/>
|
||||
<Card
|
||||
className="incident-card"
|
||||
style={{ backgroundColor }}
|
||||
<Card
|
||||
className='incident-card'
|
||||
style={{ backgroundColor }}
|
||||
>
|
||||
<CardHeader
|
||||
title={ticketId ? `${ticketId}: ${text}` : text}
|
||||
subtitle={time ? time.local().format('LTS') : 'Time unknown!'}
|
||||
actAsExpander={true}
|
||||
showExpandableButton={true}
|
||||
iconStyle={{
|
||||
color: isAllPlaybookInfoAvailable ? 'black' : 'Lightgrey'
|
||||
}}
|
||||
<CardHeader
|
||||
title={ticketId ? `${ticketId}: ${text}` : text}
|
||||
subtitle={time ? time.local().format('LTS') : 'Time unknown!'}
|
||||
actAsExpander
|
||||
showExpandableButton
|
||||
iconStyle={{
|
||||
color: isAllPlaybookInfoAvailable ? 'black' : 'Lightgrey'
|
||||
}}
|
||||
/>
|
||||
{
|
||||
{
|
||||
isAllPlaybookInfoAvailable &&
|
||||
<CardText expandable={true}>
|
||||
<CardText expandable>
|
||||
Select the Actions below:
|
||||
<Playbook
|
||||
eventId={eventId}
|
||||
|
@ -70,19 +69,19 @@ export const Event = ({
|
|||
/>
|
||||
</CardText>
|
||||
}
|
||||
</Card>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
}
|
||||
|
||||
Event.propTypes = {
|
||||
text: PropTypes.string.isRequired,
|
||||
time: PropTypes.instanceOf(moment),
|
||||
backgroundColor: PropTypes.string,
|
||||
ticketId: PropTypes.string,
|
||||
eventId: PropTypes.number,
|
||||
eventTypeId: PropTypes.number,
|
||||
eventTypeIsFetching: PropTypes.bool,
|
||||
event: PropTypes.object
|
||||
text: PropTypes.string.isRequired,
|
||||
time: PropTypes.instanceOf(moment),
|
||||
backgroundColor: PropTypes.string,
|
||||
ticketId: PropTypes.string,
|
||||
eventId: PropTypes.number,
|
||||
eventTypeId: PropTypes.number,
|
||||
eventTypeIsFetching: PropTypes.bool,
|
||||
event: PropTypes.object
|
||||
}
|
||||
|
||||
const eventHasValidDisplayText = (event) => event && event.data && event.data.DisplayText
|
||||
|
@ -93,37 +92,38 @@ export const mapStateToEventProps = (state, ownProps) => {
|
|||
const ticket = state.tickets.map[ownProps.ticketId]
|
||||
const auth = state.auth
|
||||
const engagement = state.engagements.list.find(
|
||||
engagement => engagement
|
||||
&& engagement.incidentId === ownProps.incidentId
|
||||
&& engagement.participant
|
||||
&& engagement.participant.alias === auth.userAlias
|
||||
&& engagement.participant.team === auth.userTeam
|
||||
&& engagement.participant.role === auth.userRole
|
||||
engagement => engagement &&
|
||||
engagement.incidentId === ownProps.incidentId &&
|
||||
engagement.participant &&
|
||||
engagement.participant.alias === auth.userAlias &&
|
||||
engagement.participant.team === auth.userTeam &&
|
||||
engagement.participant.role === auth.userRole
|
||||
)
|
||||
const actions = eventType.actions
|
||||
const actions = eventType ? eventType.actions : null
|
||||
var populatedConditionSetTest = TestConditionSet(event, ticket, eventType, engagement)
|
||||
const qualifiedActions = actions.filter(
|
||||
action => action.conditionSets.reduce(
|
||||
(allConditionSetsMet, currentConditionSet) => allConditionSetsMet
|
||||
? populatedConditionSetTest(currentConditionSet)
|
||||
: false,
|
||||
true
|
||||
)
|
||||
)
|
||||
return {
|
||||
...ownProps,
|
||||
ticket,
|
||||
engagementId: engagement? engagement.id:null,
|
||||
eventId: event.id,
|
||||
eventTypeId: event.eventTypeId,
|
||||
eventTypeIsFetching: state.eventTypes.fetching.includes(event.eventTypeId),
|
||||
eventTypeIsError: state.eventTypes.error.includes(event.eventTypeId),
|
||||
time: moment(event.occurred ? event.occurred : event.Occurred),
|
||||
dismissed: event.dismissed,
|
||||
backgroundColor: event.backgroundColor,
|
||||
text: LoadTextFromEvent(event, eventType, ticket, engagement),
|
||||
actions: qualifiedActions
|
||||
}
|
||||
const qualifiedActions = actions
|
||||
? actions.filter(
|
||||
action => action.conditionSets.reduce(
|
||||
(allConditionSetsMet, currentConditionSet) => allConditionSetsMet
|
||||
? populatedConditionSetTest(currentConditionSet)
|
||||
: false,
|
||||
true
|
||||
)
|
||||
) : []
|
||||
return {
|
||||
...ownProps,
|
||||
ticket,
|
||||
engagementId: engagement ? engagement.id : null,
|
||||
eventId: event.id,
|
||||
eventTypeId: event.eventTypeId,
|
||||
eventTypeIsFetching: state.eventTypes.fetching.includes(event.eventTypeId),
|
||||
eventTypeIsError: state.eventTypes.error.includes(event.eventTypeId),
|
||||
time: moment(event.occurred ? event.occurred : event.Occurred),
|
||||
dismissed: event.dismissed,
|
||||
backgroundColor: event.backgroundColor,
|
||||
text: LoadTextFromEvent(event, eventType, ticket, engagement),
|
||||
actions: qualifiedActions
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToEventProps)(Event)
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import IconButtonStyled from '../elements/IconButtonStyled'
|
||||
import FilterChips from '../elements/FilterChips'
|
||||
import IconButtonStyled from 'components/elements/IconButtonStyled'
|
||||
import FilterChips from 'components/elements/FilterChips'
|
||||
import ArrowDown from 'material-ui/svg-icons/navigation/arrow-downward'
|
||||
import ArrowUp from 'material-ui/svg-icons/navigation/arrow-upward'
|
||||
import AutoComplete from 'material-ui/AutoComplete'
|
||||
import * as formActions from '../../actions/formActions'
|
||||
import * as eventActions from '../../actions/eventActions'
|
||||
import * as filterActions from '../../actions/filterActions'
|
||||
import * as formActions from 'actions/formActions'
|
||||
import * as eventActions from 'actions/eventActions'
|
||||
import * as filterActions from 'actions/filterActions'
|
||||
|
||||
export const dataSourceConfig = {
|
||||
text: 'name',
|
||||
|
@ -30,18 +30,17 @@ export const filterSearchForm = {
|
|||
field: 'input'
|
||||
}
|
||||
|
||||
|
||||
const EventFilter = ({pagination, filter, filterSearchField, filterTypes, dispatch, history}) => {
|
||||
return (
|
||||
<div className="incident-EventFilter">
|
||||
const EventFilter = ({pagination, filter, filterSearchField, filterTypes, dispatch, history}) => {
|
||||
return (
|
||||
<div className='incident-EventFilter'>
|
||||
<FilterChips
|
||||
selectSpecificFilter={'eventTypes'}
|
||||
lookupFilterObject={'events.filter'}
|
||||
recordLookup={'eventTypes.records'}
|
||||
onRequestDelete={(filter, id) => () => dispatch(filterActions.removeFilter(history, 'eventTypes')(filter,id))}
|
||||
onRequestDelete={(filter, id) => () => dispatch(filterActions.removeFilter(history, 'eventTypes')(filter, id))}
|
||||
/>
|
||||
<AutoComplete
|
||||
floatingLabelText="Filter by event type"
|
||||
floatingLabelText='Filter by event type'
|
||||
filter={AutoComplete.caseInsensitiveFilter}
|
||||
dataSource={filterTypes}
|
||||
searchText={filterSearchField || ''}
|
||||
|
@ -60,15 +59,15 @@ const EventFilter = ({pagination, filter, filterSearchField, filterTypes, dispat
|
|||
>
|
||||
{
|
||||
pagination && pagination.order === 'desc'
|
||||
? <ArrowDown/>
|
||||
: <ArrowUp/>
|
||||
? <ArrowDown />
|
||||
: <ArrowUp />
|
||||
}
|
||||
</IconButtonStyled>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
const { events } = state
|
||||
return {
|
||||
...ownProps,
|
||||
|
|
|
@ -1,36 +1,35 @@
|
|||
import React from 'react'
|
||||
import RaisedButtonStyled from '../elements/RaisedButtonStyled'
|
||||
import * as eventActions from '../../actions/eventActions'
|
||||
import RaisedButtonStyled from 'components/elements/RaisedButtonStyled'
|
||||
import * as eventActions from 'actions/eventActions'
|
||||
|
||||
const EventFooter = ({pagination, dispatch}) => {
|
||||
const linkRange = 2
|
||||
const maxPagesToLinkTo = 2 * linkRange + 1
|
||||
const pagesForDirectLink = []
|
||||
for( var i = 0; i < maxPagesToLinkTo; i++) {
|
||||
pagesForDirectLink.push(pagination.page - linkRange + i)
|
||||
}
|
||||
const existingPagesForDirectLink = pagesForDirectLink.filter((page) => page > 1 && page < pagination.total)
|
||||
const needsLeadingDots = !pagesForDirectLink.includes(1)
|
||||
const needsFollowingDots = !pagesForDirectLink.includes(pagination.total)
|
||||
let localKey = 0
|
||||
const linkRange = 2
|
||||
const maxPagesToLinkTo = 2 * linkRange + 1
|
||||
const pagesForDirectLink = []
|
||||
for (var i = 0; i < maxPagesToLinkTo; i++) {
|
||||
pagesForDirectLink.push(pagination.page - linkRange + i)
|
||||
}
|
||||
const existingPagesForDirectLink = pagesForDirectLink.filter((page) => page > 1 && page < pagination.total)
|
||||
const needsLeadingDots = !pagesForDirectLink.includes(1)
|
||||
const needsFollowingDots = !pagesForDirectLink.includes(pagination.total)
|
||||
let localKey = 0
|
||||
return (
|
||||
<div className="incident-EventFooter">
|
||||
{<RaisedButtonStyled key={localKey++} label="1" primary={pagination.page === 1} onTouchTap={() => dispatch(eventActions.pagination.goToPage(1)) } />}
|
||||
{needsLeadingDots ? <span key={localKey++}>. . .</span> : null}
|
||||
{
|
||||
<div className='incident-EventFooter'>
|
||||
{<RaisedButtonStyled key={localKey++} label='1' primary={pagination.page === 1} onTouchTap={() => dispatch(eventActions.pagination.goToPage(1))} />}
|
||||
{needsLeadingDots ? <span key={localKey++}>. . .</span> : null}
|
||||
{
|
||||
existingPagesForDirectLink.map(pageNumber =>
|
||||
<RaisedButtonStyled
|
||||
key={localKey++}
|
||||
label={pageNumber.toString()}
|
||||
primary={pageNumber === pagination.page }
|
||||
onTouchTap={() => dispatch(eventActions.pagination.goToPage(pageNumber))}
|
||||
<RaisedButtonStyled
|
||||
key={localKey++}
|
||||
label={pageNumber.toString()}
|
||||
primary={pageNumber === pagination.page}
|
||||
onTouchTap={() => dispatch(eventActions.pagination.goToPage(pageNumber))}
|
||||
/>)
|
||||
}
|
||||
{needsFollowingDots ? <span key={localKey++}>. . .</span> : null}
|
||||
<RaisedButtonStyled key={localKey++} label={pagination.total} primary={pagination.page === pagination.total} onTouchTap={() => dispatch(eventActions.pagination.goToPage(pagination.total))} />
|
||||
</div>
|
||||
{needsFollowingDots ? <span key={localKey++}>. . .</span> : null}
|
||||
<RaisedButtonStyled key={localKey++} label={pagination.total} primary={pagination.page === pagination.total} onTouchTap={() => dispatch(eventActions.pagination.goToPage(pagination.total))} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
export default EventFooter
|
||||
export default EventFooter
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react'
|
||||
import Event from './Event'
|
||||
import Event from 'components/Timeline/Event'
|
||||
|
||||
export const Events = ({events, ticketId, incidentId}) => {
|
||||
return (<div>{
|
||||
|
|
|
@ -1,20 +1,16 @@
|
|||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { fetchGlobalActions } from '../../../actions/globalActionActions'
|
||||
import LoadingMessage from '../../elements/LoadingMessage'
|
||||
import { fetchGlobalActions } from 'actions/globalActionActions'
|
||||
import LoadingMessage from 'components/elements/LoadingMessage'
|
||||
|
||||
export class BootstrapGlobalActions extends React.Component {
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.dispatch(fetchGlobalActions())
|
||||
}
|
||||
componentDidMount () {
|
||||
this.props.dispatch(fetchGlobalActions())
|
||||
}
|
||||
|
||||
render() {
|
||||
return LoadingMessage('Loading incident actions', fetchGlobalActions())
|
||||
}
|
||||
render () {
|
||||
return LoadingMessage('Loading incident actions', fetchGlobalActions())
|
||||
}
|
||||
}
|
||||
|
||||
export default connect()(BootstrapGlobalActions)
|
||||
|
|
|
@ -1,39 +1,33 @@
|
|||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
import { BootstrapIfNeeded } from '../../../services/playbookService'
|
||||
import { BootstrapIfNeeded } from 'services/playbookService'
|
||||
|
||||
export class BootstrapPlaybook extends React.Component {
|
||||
static propTypes = {
|
||||
bootStrapIfNeeded: PropTypes.func,
|
||||
eventType: PropTypes.object,
|
||||
isFetching: PropTypes.bool
|
||||
}
|
||||
static propTypes = {
|
||||
bootStrapIfNeeded: PropTypes.func,
|
||||
eventType: PropTypes.object,
|
||||
isFetching: PropTypes.bool
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
BootstrapIfNeeded(this.props)
|
||||
}
|
||||
componentDidMount () {
|
||||
BootstrapIfNeeded(this.props)
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
BootstrapIfNeeded(this.props)
|
||||
}
|
||||
componentDidUpdate () {
|
||||
BootstrapIfNeeded(this.props)
|
||||
}
|
||||
|
||||
render() {
|
||||
return null
|
||||
}
|
||||
render () {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export const mapStateToBootstrapPlaybookProps = (state, ownProps) => ({
|
||||
...ownProps,
|
||||
eventType: state.eventTypes.records[ownProps.eventTypeId],
|
||||
isFetching: state.eventTypes.fetching.includes(ownProps.eventTypeId),
|
||||
isError: state.eventTypes.error.includes(ownProps.eventTypeId)
|
||||
...ownProps,
|
||||
eventType: state.eventTypes.records[ownProps.eventTypeId],
|
||||
isFetching: state.eventTypes.fetching.includes(ownProps.eventTypeId),
|
||||
isError: state.eventTypes.error.includes(ownProps.eventTypeId)
|
||||
})
|
||||
|
||||
export default connect(mapStateToBootstrapPlaybookProps)(BootstrapPlaybook)
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { TestConditionSet } from '../../../services/playbookService'
|
||||
import Play from './Play'
|
||||
import { TestConditionSet } from 'services/playbookService'
|
||||
import Play from 'components/Timeline/Playbook/Play'
|
||||
|
||||
export const DisplayGlobalActions = ({
|
||||
actions,
|
||||
|
@ -9,9 +9,9 @@ export const DisplayGlobalActions = ({
|
|||
engagementId,
|
||||
incidentId
|
||||
}) => {
|
||||
let localKey = 0
|
||||
return <div>
|
||||
{ AreAnyActionsAvailable(actions)
|
||||
let localKey = 0
|
||||
return <div>
|
||||
{ AreAnyActionsAvailable(actions)
|
||||
? actions.map(action => DisplayGlobalAction(
|
||||
action,
|
||||
ticketId,
|
||||
|
@ -20,7 +20,7 @@ export const DisplayGlobalActions = ({
|
|||
localKey++
|
||||
))
|
||||
: null}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
const AreAnyActionsAvailable = (actions) =>
|
||||
|
@ -33,25 +33,25 @@ export const DisplayGlobalAction = (
|
|||
incidentId,
|
||||
key
|
||||
) => <div key={key}>
|
||||
<span>
|
||||
{action.name}
|
||||
</span>
|
||||
<br/>
|
||||
<Play
|
||||
action={action}
|
||||
incidentId={incidentId}
|
||||
ticketId={ticketId}
|
||||
engagementId={engagementId}
|
||||
<span>
|
||||
{action.name}
|
||||
</span>
|
||||
<br />
|
||||
<Play
|
||||
action={action}
|
||||
incidentId={incidentId}
|
||||
ticketId={ticketId}
|
||||
engagementId={engagementId}
|
||||
/>
|
||||
</div>
|
||||
|
||||
export const mapStateToDisplayGlobalActionsProps = (state, ownProps) => {
|
||||
const ticket = state.tickets.map[ownProps.ticketId]
|
||||
const engagement = FindCurrentUserEngagement(state, ownProps.incidentId)
|
||||
const ticket = state.tickets.map[ownProps.ticketId]
|
||||
const engagement = FindCurrentUserEngagement(state, ownProps.incidentId)
|
||||
|
||||
const actions = Object.values(state.globalActions)
|
||||
var populatedConditionSetTest = TestConditionSet(null, ticket, null, engagement)
|
||||
const qualifiedActions = actions.filter(
|
||||
const actions = Object.values(state.globalActions)
|
||||
var populatedConditionSetTest = TestConditionSet(null, ticket, null, engagement)
|
||||
const qualifiedActions = actions.filter(
|
||||
action => action.conditionSets.reduce(
|
||||
(allConditionSetsMet, currentConditionSet) => allConditionSetsMet
|
||||
? populatedConditionSetTest(currentConditionSet)
|
||||
|
@ -60,20 +60,20 @@ export const mapStateToDisplayGlobalActionsProps = (state, ownProps) => {
|
|||
)
|
||||
)
|
||||
|
||||
return {
|
||||
actions: qualifiedActions,
|
||||
engagementId: engagement ? engagement.id : null,
|
||||
...ownProps
|
||||
}
|
||||
return {
|
||||
actions: qualifiedActions,
|
||||
engagementId: engagement ? engagement.id : null,
|
||||
...ownProps
|
||||
}
|
||||
}
|
||||
|
||||
const FindCurrentUserEngagement = (state, incidentId) => state.engagements.list.find(
|
||||
engagement => engagement
|
||||
&& engagement.incidentId === incidentId
|
||||
&& engagement.participant
|
||||
&& engagement.participant.alias === state.auth.userAlias
|
||||
&& engagement.participant.team === state.auth.userTeam
|
||||
&& engagement.participant.role === state.auth.userRole
|
||||
engagement => engagement &&
|
||||
engagement.incidentId === incidentId &&
|
||||
engagement.participant &&
|
||||
engagement.participant.alias === state.auth.userAlias &&
|
||||
engagement.participant.team === state.auth.userTeam &&
|
||||
engagement.participant.role === state.auth.userRole
|
||||
)
|
||||
|
||||
export default connect(mapStateToDisplayGlobalActionsProps)(DisplayGlobalActions)
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Play from './Play'
|
||||
import { TestConditionSet } from '../../../services/playbookService'
|
||||
|
||||
import Play from 'components/Timeline/Playbook/Play'
|
||||
import { TestConditionSet } from 'services/playbookService'
|
||||
|
||||
export const DisplayPlaybook = ({
|
||||
actions,
|
||||
|
@ -12,55 +11,55 @@ export const DisplayPlaybook = ({
|
|||
engagementId,
|
||||
incidentId
|
||||
}) => {
|
||||
let localKey = 0
|
||||
return <div>
|
||||
{actions.map(action =>
|
||||
<div key={localKey++}>
|
||||
<span>
|
||||
{action.name}
|
||||
</span>
|
||||
<br/>
|
||||
<Play
|
||||
action={action}
|
||||
eventTypeId={eventTypeId}
|
||||
eventId={eventId}
|
||||
incidentId={incidentId}
|
||||
ticketId={ticketId}
|
||||
engagementId={engagementId}
|
||||
let localKey = 0
|
||||
return <div>
|
||||
{actions.map(action =>
|
||||
<div key={localKey++}>
|
||||
<span>
|
||||
{action.name}
|
||||
</span>
|
||||
<br />
|
||||
<Play
|
||||
action={action}
|
||||
eventTypeId={eventTypeId}
|
||||
eventId={eventId}
|
||||
incidentId={incidentId}
|
||||
ticketId={ticketId}
|
||||
engagementId={engagementId}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
DisplayPlaybook.propTypes = {
|
||||
actions: PropTypes.array.isRequired,
|
||||
eventTypeId: PropTypes.number.isRequired,
|
||||
eventId: PropTypes.number.isRequired,
|
||||
ticketId: PropTypes.string.isRequired,
|
||||
engagementId: PropTypes.number,
|
||||
incidentId: PropTypes.number.isRequired
|
||||
actions: PropTypes.array.isRequired,
|
||||
eventTypeId: PropTypes.number.isRequired,
|
||||
eventId: PropTypes.number.isRequired,
|
||||
ticketId: PropTypes.string.isRequired,
|
||||
engagementId: PropTypes.number,
|
||||
incidentId: PropTypes.number.isRequired
|
||||
}
|
||||
|
||||
export const mapStateToDisplayPlaybookProps = (state, ownProps) => {
|
||||
const auth = state.auth
|
||||
const auth = state.auth
|
||||
|
||||
const eventType = state.eventTypes.records[ownProps.eventTypeId]
|
||||
const event = Object.values(state.events.list.list)
|
||||
const eventType = state.eventTypes.records[ownProps.eventTypeId]
|
||||
const event = Object.values(state.events.list.list)
|
||||
.find(event => event.id === ownProps.eventId)
|
||||
const ticket = state.tickets.map[ownProps.ticketId]
|
||||
const engagement = state.engagements.list.find(
|
||||
engagement => engagement
|
||||
&& engagement.incidentId === ownProps.incidentId
|
||||
&& engagement.participant
|
||||
&& engagement.participant.alias === auth.userAlias
|
||||
&& engagement.participant.team === auth.userTeam
|
||||
&& engagement.participant.role === auth.userRole
|
||||
const ticket = state.tickets.map[ownProps.ticketId]
|
||||
const engagement = state.engagements.list.find(
|
||||
engagement => engagement &&
|
||||
engagement.incidentId === ownProps.incidentId &&
|
||||
engagement.participant &&
|
||||
engagement.participant.alias === auth.userAlias &&
|
||||
engagement.participant.team === auth.userTeam &&
|
||||
engagement.participant.role === auth.userRole
|
||||
)
|
||||
|
||||
const actions = eventType.actions
|
||||
var populatedConditionSetTest = TestConditionSet(event, ticket, eventType, engagement)
|
||||
const qualifiedActions = actions.filter(
|
||||
const actions = eventType.actions
|
||||
var populatedConditionSetTest = TestConditionSet(event, ticket, eventType, engagement)
|
||||
const qualifiedActions = actions.filter(
|
||||
action => action.conditionSets.reduce(
|
||||
(allConditionSetsMet, currentConditionSet) => allConditionSetsMet
|
||||
? populatedConditionSetTest(currentConditionSet)
|
||||
|
@ -69,12 +68,11 @@ export const mapStateToDisplayPlaybookProps = (state, ownProps) => {
|
|||
)
|
||||
)
|
||||
|
||||
return {
|
||||
actions: qualifiedActions,
|
||||
engagementId: engagement ? engagement.id : null,
|
||||
...ownProps
|
||||
}
|
||||
return {
|
||||
actions: qualifiedActions,
|
||||
engagementId: engagement ? engagement.id : null,
|
||||
...ownProps
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default DisplayPlaybook
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import DisplayGlobalActions from './DisplayGlobalActions'
|
||||
import BootstrapGlobalActions from './BootstrapGlobalActions'
|
||||
import DisplayGlobalActions from 'components/Timeline/Playbook/DisplayGlobalActions'
|
||||
import BootstrapGlobalActions from 'components/Timeline/Playbook/BootstrapGlobalActions'
|
||||
|
||||
export const GlobalActions = ({
|
||||
incidentId,
|
||||
|
@ -9,14 +9,14 @@ export const GlobalActions = ({
|
|||
actions
|
||||
}) => actions && actions.length
|
||||
? <DisplayGlobalActions
|
||||
incidentId={incidentId}
|
||||
ticketId={ticketId}
|
||||
incidentId={incidentId}
|
||||
ticketId={ticketId}
|
||||
/>
|
||||
: <BootstrapGlobalActions />
|
||||
|
||||
export const mapStateToGlobalActionsProps = (state, ownProps) => ({
|
||||
...ownProps,
|
||||
actions: Object.values(state.globalActions)
|
||||
...ownProps,
|
||||
actions: Object.values(state.globalActions)
|
||||
})
|
||||
|
||||
export default connect(mapStateToGlobalActionsProps)(GlobalActions)
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import FlatButtonStyled from '../../../components/elements/FlatButtonStyled'
|
||||
import { fillTemplate, publishEvent } from '../../../services/playbookService'
|
||||
import FlatButtonStyled from 'components/elements/FlatButtonStyled'
|
||||
import { fillTemplate, publishEvent } from 'services/playbookService'
|
||||
|
||||
export const Play = ({incidentId, isUrl, filledTemplate, name}) => {
|
||||
return isUrl ? <a href={filledTemplate} target="_blank">Link: {name}</a>
|
||||
return isUrl ? <a href={filledTemplate} target='_blank'>Link: {name}</a>
|
||||
: <FlatButtonStyled
|
||||
label={'Publish Event: ' + name}
|
||||
onTouchTap={publishEvent(incidentId, filledTemplate)}
|
||||
label={'Publish Event: ' + name}
|
||||
onTouchTap={publishEvent(incidentId, filledTemplate)}
|
||||
/>
|
||||
}
|
||||
|
||||
export const mapStateToPlayProps = (state, ownProps) => {
|
||||
const eventType = state.eventTypes.records[ownProps.eventTypeId]
|
||||
const event = state.events.pages.list.find(event => event.id === ownProps.eventId)
|
||||
const ticket = state.tickets.map[ownProps.ticketId]
|
||||
const engagement = state.engagements.list.find(engagement => engagement.id === ownProps.engagementId)
|
||||
const action = ownProps.action
|
||||
const filledTemplate = action ? fillTemplate(action.actionTemplate, event, ticket, eventType, engagement) : ''
|
||||
|
||||
return {
|
||||
...ownProps,
|
||||
isUrl: action.actionTemplate.isUrl,
|
||||
name: action.actionTemplate.name,
|
||||
filledTemplate
|
||||
}
|
||||
const eventType = state.eventTypes.records[ownProps.eventTypeId]
|
||||
const event = state.events.pages.list.find(event => event.id === ownProps.eventId)
|
||||
const ticket = state.tickets.map[ownProps.ticketId]
|
||||
const engagement = state.engagements.list.find(engagement => engagement.id === ownProps.engagementId)
|
||||
const action = ownProps.action
|
||||
const filledTemplate = action ? fillTemplate(action.actionTemplate, event, ticket, eventType, engagement) : ''
|
||||
|
||||
return {
|
||||
...ownProps,
|
||||
isUrl: action.actionTemplate.isUrl,
|
||||
name: action.actionTemplate.name,
|
||||
filledTemplate
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToPlayProps)(Play)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import React from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import LoadingMessage from '../../elements/LoadingMessage'
|
||||
import ErrorMessage from '../../elements/ErrorMessage'
|
||||
import DisplayPlaybook from './DisplayPlaybook'
|
||||
import * as eventActions from '../../../actions/eventActions'
|
||||
import * as eventTypeActions from '../../../actions/eventTypeActions'
|
||||
import LoadingMessage from 'components/elements/LoadingMessage'
|
||||
import ErrorMessage from 'components/elements/ErrorMessage'
|
||||
import DisplayPlaybook from 'components/Timeline/Playbook/DisplayPlaybook'
|
||||
import * as eventActions from 'actions/eventActions'
|
||||
import * as eventTypeActions from 'actions/eventTypeActions'
|
||||
|
||||
export const Playbook = ({
|
||||
eventTypeId,
|
||||
|
@ -18,35 +18,34 @@ export const Playbook = ({
|
|||
actions,
|
||||
engagementId
|
||||
}) => {
|
||||
if(eventIsFetching) {
|
||||
return LoadingMessage('Fetching event information...', eventActions.fetchEvent(incidentId, eventId))
|
||||
}
|
||||
if(eventTypeIsFetching) {
|
||||
return LoadingMessage('Fetching event type information...', eventTypeActions.fetchEventType(eventTypeId))
|
||||
}
|
||||
if(eventIsError) {
|
||||
return ErrorMessage('Error fetching event!', eventActions.fetchEvent(incidentId, eventId))
|
||||
}
|
||||
if(eventTypeIsError){
|
||||
return ErrorMessage('Error fetching eventType!', eventTypeActions.fetchEventType(eventTypeId))
|
||||
}
|
||||
return <DisplayPlaybook
|
||||
eventTypeId={eventTypeId}
|
||||
eventId={eventId}
|
||||
ticketId={ticketId}
|
||||
incidentId={incidentId}
|
||||
actions={actions}
|
||||
engagementId={engagementId}
|
||||
if (eventIsFetching) {
|
||||
return LoadingMessage('Fetching event information...', eventActions.fetchEvent(incidentId, eventId))
|
||||
}
|
||||
if (eventTypeIsFetching) {
|
||||
return LoadingMessage('Fetching event type information...', eventTypeActions.fetchEventType(eventTypeId))
|
||||
}
|
||||
if (eventIsError) {
|
||||
return ErrorMessage('Error fetching event!', eventActions.fetchEvent(incidentId, eventId))
|
||||
}
|
||||
if (eventTypeIsError) {
|
||||
return ErrorMessage('Error fetching eventType!', eventTypeActions.fetchEventType(eventTypeId))
|
||||
}
|
||||
return <DisplayPlaybook
|
||||
eventTypeId={eventTypeId}
|
||||
eventId={eventId}
|
||||
ticketId={ticketId}
|
||||
incidentId={incidentId}
|
||||
actions={actions}
|
||||
engagementId={engagementId}
|
||||
/>
|
||||
}
|
||||
|
||||
export const mapStateToPlaybookProps = (state, ownProps) => ({
|
||||
eventTypeIsFetching: state.eventTypes.fetching.includes(ownProps.eventTypeId),
|
||||
eventTypeIsError: state.eventTypes.error.includes(ownProps.eventTypeId),
|
||||
eventIsFetching: state.events.fetching.includes(ownProps.eventid),
|
||||
eventIsError: state.events.error.includes(ownProps.eventId),
|
||||
...ownProps
|
||||
eventTypeIsFetching: state.eventTypes.fetching.includes(ownProps.eventTypeId),
|
||||
eventTypeIsError: state.eventTypes.error.includes(ownProps.eventTypeId),
|
||||
eventIsFetching: state.events.fetching.includes(ownProps.eventid),
|
||||
eventIsError: state.events.error.includes(ownProps.eventId),
|
||||
...ownProps
|
||||
})
|
||||
|
||||
|
||||
export default connect(mapStateToPlaybookProps)(Playbook)
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import { connect } from 'react-redux'
|
||||
import React, { Component } from 'react'
|
||||
import { withRouter } from 'react-router-dom'
|
||||
import EventFilter from './EventFilter'
|
||||
import Footer from './EventFooter'
|
||||
import AddEventCard from './AddEventCard'
|
||||
import EventFilter from 'components/Timeline/EventFilter'
|
||||
import Footer from 'components/Timeline/EventFooter'
|
||||
import AddEventCard from 'components/Timeline/AddEventCard'
|
||||
import PropTypes from 'prop-types'
|
||||
import Events from './Events'
|
||||
import * as eventActions from '../../actions/eventActions'
|
||||
import * as eventTypeActions from '../../actions/eventTypeActions'
|
||||
import * as filterActions from '../../actions/filterActions'
|
||||
import Events from 'components/Timeline/Events'
|
||||
import * as eventActions from 'actions/eventActions'
|
||||
import * as eventTypeActions from 'actions/eventTypeActions'
|
||||
import * as filterActions from 'actions/filterActions'
|
||||
|
||||
class Timeline extends Component {
|
||||
static propTypes = {
|
||||
|
@ -20,31 +20,30 @@ class Timeline extends Component {
|
|||
filter: PropTypes.object
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
componentDidMount () {
|
||||
const { eventTypes, events, ticketId, incidentId, filter, history, dispatch } = this.props
|
||||
updatePagination(incidentId, dispatch)
|
||||
fetchMissingEventTypes(eventTypes, events, dispatch)
|
||||
if (incidentId)
|
||||
{
|
||||
if (incidentId) {
|
||||
dispatch(filterActions.synchronizeFilters(filter, incidentId, ticketId, history))
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
render () {
|
||||
const { events, dispatch, ticketId, incidentId, eventTypes, history } = this.props
|
||||
return (
|
||||
<div>
|
||||
{AddEventCard(incidentId)}
|
||||
<EventFilter history={history} eventTypes={eventTypes}/>
|
||||
<EventFilter history={history} eventTypes={eventTypes} />
|
||||
<Events events={events.pageList} ticketId={ticketId} incidentId={incidentId} />
|
||||
<Footer pagination={events} dispatch={dispatch}/>
|
||||
<Footer pagination={events} dispatch={dispatch} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const updatePagination = (incidentId, dispatch) => {
|
||||
dispatch(eventActions.pagination.filter(incidentId.toString()))
|
||||
dispatch(eventActions.pagination.filter(incidentId.toString()))
|
||||
}
|
||||
|
||||
const fetchMissingEventTypes = (eventTypes, events, dispatch) => {
|
||||
|
|
|
@ -6,16 +6,19 @@ import IconMenu from 'material-ui/IconMenu'
|
|||
import { Link } from 'react-router-dom'
|
||||
import NavigationMenu from 'material-ui/svg-icons/navigation/menu'
|
||||
import IconButton from 'material-ui/IconButton'
|
||||
import * as auth from '../../services/authNService'
|
||||
import * as auth from 'services/authNService'
|
||||
|
||||
|
||||
|
||||
|
||||
export const NavMenu = ({ dispatch }) =>
|
||||
<IconMenu
|
||||
|
||||
iconButtonElement={<IconButton><NavigationMenu /></IconButton>}
|
||||
anchorOrigin={{horizontal: 'left', vertical: 'bottom'}}
|
||||
targetOrigin={{horizontal: 'left', vertical: 'top'}}
|
||||
>
|
||||
|
||||
<MenuItem primaryText={<Link to="/search" >Incident Search</Link>} />
|
||||
<MenuItem primaryText={<Link to="/" onClick={() => dispatch(auth.logOut)}>LogOut</Link>} />
|
||||
<MenuItem primaryText={<Link to="/debug" >Debug</Link>} />
|
||||
|
@ -25,3 +28,4 @@ NavMenu.propTypes = {
|
|||
dispatch: PropTypes.func
|
||||
}
|
||||
export default connect()(NavMenu)
|
||||
|
||||
|
|
|
@ -7,51 +7,50 @@ import SyncDisabled from 'material-ui/svg-icons/notification/sync-disabled'
|
|||
import Sync from 'material-ui/svg-icons/notification/sync'
|
||||
import IconButton from 'material-ui/IconButton'
|
||||
import { connect } from 'react-redux'
|
||||
import { connectionStatuses } from '../../reducers/signalRReducer'
|
||||
import { resetSignalRConnection } from '../../services/signalRService'
|
||||
import { acknowledgeMessages } from '../../actions/signalRActions'
|
||||
import { connectionStatuses } from 'reducers/signalRReducer'
|
||||
import { resetSignalRConnection } from 'services/signalRService'
|
||||
import { acknowledgeMessages } from 'actions/signalRActions'
|
||||
|
||||
export const NavNotifs = ({signalR, dispatch}) => {
|
||||
const pendingMessages = signalR.pendingMessages ? signalR.pendingMessages : 0
|
||||
return <IconButton tooltip={showNotifsMessage(pendingMessages)}onTouchTap={notifsAction(signalR, dispatch)}>
|
||||
{displayButton(signalR)}
|
||||
</IconButton>
|
||||
const pendingMessages = signalR.pendingMessages ? signalR.pendingMessages : 0
|
||||
return <IconButton tooltip={showNotifsMessage(pendingMessages)}onTouchTap={notifsAction(signalR, dispatch)}>
|
||||
{displayButton(signalR)}
|
||||
</IconButton>
|
||||
}
|
||||
|
||||
const showNotifsMessage = (pendingMessages) => {
|
||||
return pendingMessages === 0 ? 'Check for new messages' : `View ${pendingMessages} messages`
|
||||
return pendingMessages === 0 ? 'Check for new messages' : `View ${pendingMessages} messages`
|
||||
}
|
||||
|
||||
NavNotifs.propTypes = {
|
||||
signalR: PropTypes.object,
|
||||
dispatch: PropTypes.func
|
||||
signalR: PropTypes.object,
|
||||
dispatch: PropTypes.func
|
||||
}
|
||||
|
||||
const notifsAction = (signalR, dispatch) => () => {
|
||||
if(signalR.connectionStatus === connectionStatuses.connected
|
||||
&& signalR.pendingMessages) {
|
||||
dispatch(acknowledgeMessages())
|
||||
}
|
||||
else {
|
||||
resetSignalRConnection(dispatch)
|
||||
}
|
||||
if (signalR.connectionStatus === connectionStatuses.connected &&
|
||||
signalR.pendingMessages) {
|
||||
dispatch(acknowledgeMessages())
|
||||
} else {
|
||||
resetSignalRConnection(dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
const displayButton = (signalR) => {
|
||||
switch(signalR.connectionStatus) {
|
||||
case connectionStatuses.connected:
|
||||
return signalR.pendingMessages ? <Notifications /> : <NotificationsNone />
|
||||
case connectionStatuses.notEstablished:
|
||||
return <Sync />
|
||||
case connectionStatuses.disconnected:
|
||||
return <SyncDisabled />
|
||||
case connectionStatuses.error:
|
||||
return <SyncProblem />
|
||||
}
|
||||
switch (signalR.connectionStatus) {
|
||||
case connectionStatuses.connected:
|
||||
return signalR.pendingMessages ? <Notifications /> : <NotificationsNone />
|
||||
case connectionStatuses.notEstablished:
|
||||
return <Sync />
|
||||
case connectionStatuses.disconnected:
|
||||
return <SyncDisabled />
|
||||
case connectionStatuses.error:
|
||||
return <SyncProblem />
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
signalR: state.signalR
|
||||
signalR: state.signalR
|
||||
})
|
||||
|
||||
export default connect(mapStateToProps)(NavNotifs)
|
||||
export default connect(mapStateToProps)(NavNotifs)
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import React from 'react'
|
||||
import AppBar from 'material-ui/AppBar'
|
||||
import NavMenu from './NavMenu'
|
||||
import NavNotifs from './NavNotifs'
|
||||
import NavMenu from 'components/TopNav/NavMenu'
|
||||
import NavNotifs from 'components/TopNav/NavNotifs'
|
||||
|
||||
export const TopNav = () => {
|
||||
return <AppBar title="SRE Incident Assistant"
|
||||
iconElementLeft={<NavMenu />}
|
||||
iconElementRight={<NavNotifs />}/>
|
||||
return <AppBar title='SRE Incident Assistant'
|
||||
iconElementLeft={<NavMenu />}
|
||||
iconElementRight={<NavNotifs />} />
|
||||
}
|
||||
|
||||
export default TopNav
|
||||
|
|
|
@ -2,29 +2,29 @@ import React from 'react'
|
|||
import Badge from 'material-ui/Badge'
|
||||
|
||||
const styles = {
|
||||
badge: {
|
||||
padding: 0
|
||||
},
|
||||
badgeposition: {
|
||||
top: -4,
|
||||
right: -12,
|
||||
width: 16,
|
||||
height: 16
|
||||
}
|
||||
badge: {
|
||||
padding: 0
|
||||
},
|
||||
badgeposition: {
|
||||
top: -4,
|
||||
right: -12,
|
||||
width: 16,
|
||||
height: 16
|
||||
}
|
||||
}
|
||||
|
||||
export const BadgeStyled = ({badgeContent, primary = true, children}) => {
|
||||
return (
|
||||
<Badge
|
||||
badgeContent={badgeContent}
|
||||
badgeStyle={styles.badgeposition}
|
||||
style={styles.badge}
|
||||
primary={primary}
|
||||
secondary={!primary}
|
||||
return (
|
||||
<Badge
|
||||
badgeContent={badgeContent}
|
||||
badgeStyle={styles.badgeposition}
|
||||
style={styles.badge}
|
||||
primary={primary}
|
||||
secondary={!primary}
|
||||
>
|
||||
{children}
|
||||
</Badge>
|
||||
)
|
||||
{children}
|
||||
</Badge>
|
||||
)
|
||||
}
|
||||
|
||||
export default BadgeStyled
|
||||
export default BadgeStyled
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import FlatButtonStyled from './FlatButtonStyled'
|
||||
import FlatButtonStyled from 'components/elements/FlatButtonStyled'
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
export const DisplayRetryButton = ({actionForRetry, dispatch}) => <FlatButtonStyled
|
||||
label='Retry'
|
||||
primary={true}
|
||||
onTouchTap={() => dispatch(actionForRetry)}
|
||||
label='Retry'
|
||||
primary
|
||||
onTouchTap={() => dispatch(actionForRetry)}
|
||||
/>
|
||||
|
||||
DisplayRetryButton.propTypes = {
|
||||
actionForRetry: PropTypes.func.isRequired,
|
||||
dispatch: PropTypes.func.isRequired
|
||||
actionForRetry: PropTypes.func.isRequired,
|
||||
dispatch: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
const MapStateToPropsRetryButton = (state, ownProps) => ({
|
||||
...ownProps
|
||||
}) //We just want to add dispatch
|
||||
...ownProps
|
||||
}) // We just want to add dispatch
|
||||
|
||||
export const RetryButton = connect(MapStateToPropsRetryButton)(DisplayRetryButton)
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
import React from 'react'
|
||||
import { GridSet } from './Grid'
|
||||
import IconButtonStyled from '../elements/IconButtonStyled'
|
||||
import { GridSet } from 'components/elements/Grid'
|
||||
import IconButtonStyled from 'components/elements/IconButtonStyled'
|
||||
import ArrowDropDownIcon from 'material-ui/svg-icons/navigation/arrow-drop-down'
|
||||
import ArrowDropDownCircleIcon from 'material-ui/svg-icons/navigation/arrow-drop-down-circle'
|
||||
import * as expandSectionActions from '../../actions/expandSectionActions'
|
||||
import * as expandSectionActions from 'actions/expandSectionActions'
|
||||
|
||||
const dispatchOnTouchTap = (collapseName, dispatch) => () => dispatch(expandSectionActions.toggleCollapse(collapseName))
|
||||
|
||||
export const CollapsibleGridSet = (containerClass, rowClass, columnClass, children, collapseNames, collapseState, dispatch) => {
|
||||
let collapseKey = 0
|
||||
const collapseStatus = collapseNames.map(name => collapseState[name])
|
||||
return GridSet (containerClass, rowClass, columnClass, children.map(child => {
|
||||
const isCollapsed = collapseStatus[collapseKey]
|
||||
const currentChild = isCollapsed ? child.slice(0,1) : child
|
||||
const currentName = collapseNames[collapseKey]
|
||||
currentChild[0][0].push(
|
||||
let collapseKey = 0
|
||||
const collapseStatus = collapseNames.map(name => collapseState[name])
|
||||
return GridSet(containerClass, rowClass, columnClass, children.map(child => {
|
||||
const isCollapsed = collapseStatus[collapseKey]
|
||||
const currentChild = isCollapsed ? child.slice(0, 1) : child
|
||||
const currentName = collapseNames[collapseKey]
|
||||
currentChild[0][0].push(
|
||||
(key) =>
|
||||
<IconButtonStyled
|
||||
tooltip="Collapse/expand section"
|
||||
<IconButtonStyled
|
||||
tooltip='Collapse/expand section'
|
||||
onTouchTap={dispatchOnTouchTap(currentName, dispatch)}
|
||||
key={key}
|
||||
>
|
||||
{isCollapsed ? <ArrowDropDownCircleIcon /> : <ArrowDropDownIcon />}
|
||||
</IconButtonStyled>
|
||||
</IconButtonStyled>
|
||||
)
|
||||
collapseKey++
|
||||
return currentChild
|
||||
}))
|
||||
collapseKey++
|
||||
return currentChild
|
||||
}))
|
||||
}
|
||||
|
||||
export default CollapsibleGridSet
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import React from 'react'
|
||||
import ErrorIcon from 'material-ui/svg-icons/alert/error'
|
||||
import { RetryButton } from './Buttons'
|
||||
import { RetryButton } from 'components/elements/Buttons'
|
||||
|
||||
const ErrorMessage = (message, actionForRetry) => <div>
|
||||
<ErrorIcon />
|
||||
<span>{message}</span>
|
||||
{ actionForRetry ? <RetryButton actionForRetry={actionForRetry} /> : null }
|
||||
</div>
|
||||
<ErrorIcon />
|
||||
<span>{message}</span>
|
||||
{ actionForRetry ? <RetryButton actionForRetry={actionForRetry} /> : null }
|
||||
</div>
|
||||
|
||||
export default ErrorMessage
|
||||
|
|
|
@ -5,51 +5,51 @@ import Chip from 'material-ui/Chip'
|
|||
import ByPath from 'object-path'
|
||||
|
||||
export const FilterChips = ({filter, selectSpecificFilter, records, onRequestDelete}) => {
|
||||
const selectedFilters = ByPath.get(filter, selectSpecificFilter)
|
||||
return selectedFilters
|
||||
const selectedFilters = ByPath.get(filter, selectSpecificFilter)
|
||||
return selectedFilters
|
||||
? selectedFilters
|
||||
.map((selectedFilter) => hydrateChip(selectedFilter, records))
|
||||
.map(chip => renderChip(chip.id, chip.name, onRequestDelete(filter, chip.id)))
|
||||
: <div></div>
|
||||
: <div />
|
||||
}
|
||||
|
||||
export const mapStateToProps = (state, ownProps) => ({
|
||||
...ownProps,
|
||||
filter: ByPath.get(state, ownProps.lookupFilterObject),
|
||||
records: ByPath.get(state, ownProps.recordLookup)
|
||||
...ownProps,
|
||||
filter: ByPath.get(state, ownProps.lookupFilterObject),
|
||||
records: ByPath.get(state, ownProps.recordLookup)
|
||||
})
|
||||
|
||||
export const renderChip = (id, name, onRequestDelete) => (
|
||||
<Chip
|
||||
key={id}
|
||||
onRequestDelete={onRequestDelete}
|
||||
style={chipStyles.chip}
|
||||
<Chip
|
||||
key={id}
|
||||
onRequestDelete={onRequestDelete}
|
||||
style={chipStyles.chip}
|
||||
>
|
||||
{name}
|
||||
</Chip>
|
||||
{name}
|
||||
</Chip>
|
||||
)
|
||||
|
||||
export const hydrateChip = (id, records) => ({
|
||||
id: id,
|
||||
name: records[id] ? records[id].name : 'unknown'
|
||||
id: id,
|
||||
name: records[id] ? records[id].name : 'unknown'
|
||||
|
||||
})
|
||||
|
||||
const chipStyles = {
|
||||
chip: {
|
||||
margin: 4
|
||||
},
|
||||
wrapper: {
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap'
|
||||
}
|
||||
chip: {
|
||||
margin: 4
|
||||
},
|
||||
wrapper: {
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap'
|
||||
}
|
||||
}
|
||||
|
||||
FilterChips.propTypes = {
|
||||
selectSpecificFilter: PropTypes.string,
|
||||
lookupFilterObject: PropTypes.string,
|
||||
recordLookup: PropTypes.string,
|
||||
onRequestDelete: PropTypes.func
|
||||
selectSpecificFilter: PropTypes.string,
|
||||
lookupFilterObject: PropTypes.string,
|
||||
recordLookup: PropTypes.string,
|
||||
onRequestDelete: PropTypes.func
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(FilterChips)
|
||||
|
|
|
@ -3,37 +3,36 @@ import PropTypes from 'prop-types'
|
|||
import FlatButton from 'material-ui/FlatButton'
|
||||
|
||||
const styles = {
|
||||
flatbutton: {
|
||||
fontSize: 12,
|
||||
minWidth: '12%',
|
||||
height: 20,
|
||||
margin: 2,
|
||||
textTransform: 'capitalize',
|
||||
position: 'relative',
|
||||
top: -8
|
||||
}
|
||||
flatbutton: {
|
||||
fontSize: 12,
|
||||
minWidth: '12%',
|
||||
height: 20,
|
||||
margin: 2,
|
||||
textTransform: 'capitalize',
|
||||
position: 'relative',
|
||||
top: -8
|
||||
}
|
||||
}
|
||||
|
||||
export const FlatButtonStyled = ({label, primary, keyboardFocused, onTouchTap}) => {
|
||||
return (
|
||||
<FlatButton
|
||||
label={label}
|
||||
labelStyle={styles.flatbutton}
|
||||
style={styles.flatbutton}
|
||||
primary={primary}
|
||||
//secondary={!primary}
|
||||
keyboardFocused={keyboardFocused}
|
||||
onTouchTap={onTouchTap}
|
||||
>
|
||||
</FlatButton>
|
||||
)
|
||||
return (
|
||||
<FlatButton
|
||||
label={label}
|
||||
labelStyle={styles.flatbutton}
|
||||
style={styles.flatbutton}
|
||||
primary={primary}
|
||||
// secondary={!primary}
|
||||
keyboardFocused={keyboardFocused}
|
||||
onTouchTap={onTouchTap}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
FlatButtonStyled.propTypes = {
|
||||
label: PropTypes.string.isRequired,
|
||||
primary: PropTypes.bool,
|
||||
keyboardFocused: PropTypes.string,
|
||||
onTouchTap: PropTypes.func.isRequired
|
||||
label: PropTypes.string.isRequired,
|
||||
primary: PropTypes.bool,
|
||||
keyboardFocused: PropTypes.string,
|
||||
onTouchTap: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default FlatButtonStyled
|
||||
export default FlatButtonStyled
|
||||
|
|
|
@ -3,53 +3,53 @@ import PropTypes from 'prop-types'
|
|||
import Paper from 'material-ui/Paper'
|
||||
|
||||
export const GridSet = (containerClass, rowClass, columnClass, children) => {
|
||||
let key = 0
|
||||
return (
|
||||
<div className={containerClass}>
|
||||
{children.map(child => Grid(rowClass, columnClass, child, key++))}
|
||||
</div>
|
||||
)
|
||||
let key = 0
|
||||
return (
|
||||
<div className={containerClass}>
|
||||
{children.map(child => Grid(rowClass, columnClass, child, key++))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const Grid = (rowClass, columnClass, children, key = 0) => {
|
||||
let rowKey = 0
|
||||
return (
|
||||
<Paper zDepth={2} key={key}>
|
||||
{
|
||||
let rowKey = 0
|
||||
return (
|
||||
<Paper zDepth={2} key={key}>
|
||||
{
|
||||
children.map(child => {
|
||||
return Array.isArray(child)? GridRow(rowClass, columnClass, child, rowKey++) : child
|
||||
return Array.isArray(child) ? GridRow(rowClass, columnClass, child, rowKey++) : child
|
||||
}
|
||||
)}
|
||||
</Paper>
|
||||
)
|
||||
</Paper>
|
||||
)
|
||||
}
|
||||
|
||||
Grid.propTypes = {
|
||||
rowClass: PropTypes.string.isRequired,
|
||||
columnClass: PropTypes.string.isRequired,
|
||||
children: PropTypes.array.isRequired
|
||||
rowClass: PropTypes.string.isRequired,
|
||||
columnClass: PropTypes.string.isRequired,
|
||||
children: PropTypes.array.isRequired
|
||||
}
|
||||
|
||||
export const GridRow = (rowClass, columnClass, children, rowKey = 0) => {
|
||||
let columnKey = 0
|
||||
return (
|
||||
<div className={rowClass} key={rowKey}>
|
||||
{children.map(child => {
|
||||
let localkey = 0
|
||||
return (
|
||||
<div className={columnClass} key={columnKey++}>
|
||||
{Array.isArray(child)? child.map(grandchild => grandchild(localkey++)) : child}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
let columnKey = 0
|
||||
return (
|
||||
<div className={rowClass} key={rowKey}>
|
||||
{children.map(child => {
|
||||
let localkey = 0
|
||||
return (
|
||||
<div className={columnClass} key={columnKey++}>
|
||||
{Array.isArray(child) ? child.map(grandchild => grandchild(localkey++)) : child}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
GridRow.propTypes = {
|
||||
rowClass: PropTypes.string.isRequired,
|
||||
columnClass: PropTypes.string.isRequired,
|
||||
children: PropTypes.array.isRequired
|
||||
rowClass: PropTypes.string.isRequired,
|
||||
columnClass: PropTypes.string.isRequired,
|
||||
children: PropTypes.array.isRequired
|
||||
}
|
||||
|
||||
export default Grid
|
||||
export default Grid
|
||||
|
|
|
@ -2,24 +2,24 @@ import React from 'react'
|
|||
import IconButton from 'material-ui/IconButton'
|
||||
|
||||
const styles = {
|
||||
iconbutton: {
|
||||
width: 18,
|
||||
height: 18,
|
||||
padding: 0
|
||||
}
|
||||
iconbutton: {
|
||||
width: 18,
|
||||
height: 18,
|
||||
padding: 0
|
||||
}
|
||||
}
|
||||
|
||||
export const IconButtonStyled = ({tooltip, onTouchTap, children}) => {
|
||||
return (
|
||||
<IconButton
|
||||
tooltip={tooltip}
|
||||
iconStyle={styles.iconbutton}
|
||||
style={styles.iconbutton}
|
||||
onTouchTap={onTouchTap}
|
||||
return (
|
||||
<IconButton
|
||||
tooltip={tooltip}
|
||||
iconStyle={styles.iconbutton}
|
||||
style={styles.iconbutton}
|
||||
onTouchTap={onTouchTap}
|
||||
>
|
||||
{children}
|
||||
</IconButton>
|
||||
)
|
||||
{children}
|
||||
</IconButton>
|
||||
)
|
||||
}
|
||||
|
||||
export default IconButtonStyled
|
||||
|
|
|
@ -7,14 +7,13 @@ const Link = ({ active, children, onClick }) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<a href="#"
|
||||
onClick={e => {
|
||||
e.preventDefault()
|
||||
if(onClick)
|
||||
{
|
||||
onClick()
|
||||
}
|
||||
}}
|
||||
<a href='#'
|
||||
onClick={e => {
|
||||
e.preventDefault()
|
||||
if (onClick) {
|
||||
onClick()
|
||||
}
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
|
@ -27,4 +26,4 @@ Link.propTypes = {
|
|||
onClick: PropTypes.func
|
||||
}
|
||||
|
||||
export default Link
|
||||
export default Link
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import CircularProgress from 'material-ui/CircularProgress'
|
||||
import { RetryButton } from './Buttons'
|
||||
import { RetryButton } from 'components/elements/Buttons'
|
||||
|
||||
const LoadingMessage = (message, actionForRetry) => <div>
|
||||
<CircularProgress />
|
||||
<span>{message}</span>
|
||||
{ actionForRetry ? <RetryButton actionForRetry={actionForRetry} /> : null }
|
||||
</div>
|
||||
<CircularProgress />
|
||||
<span>{message}</span>
|
||||
{ actionForRetry ? <RetryButton actionForRetry={actionForRetry} /> : null }
|
||||
</div>
|
||||
|
||||
LoadingMessage.propTypes = {
|
||||
message: PropTypes.string.isRequired,
|
||||
actionForRetry: PropTypes.func.isRequired
|
||||
message: PropTypes.string.isRequired,
|
||||
actionForRetry: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default LoadingMessage
|
||||
|
|
|
@ -3,34 +3,34 @@ import PropTypes from 'prop-types'
|
|||
import RaisedButton from 'material-ui/RaisedButton'
|
||||
|
||||
const styles = {
|
||||
raisedbutton: {
|
||||
fontSize: 12,
|
||||
minWidth: '10%',
|
||||
height: 28,
|
||||
textTransform: 'lowercase',
|
||||
padding: '1px'
|
||||
}
|
||||
raisedbutton: {
|
||||
fontSize: 12,
|
||||
minWidth: '10%',
|
||||
height: 28,
|
||||
textTransform: 'lowercase',
|
||||
padding: '1px'
|
||||
}
|
||||
}
|
||||
|
||||
export const RaisedButtonStyled = ({label, type, primary, onTouchTap, children}) => {
|
||||
return (
|
||||
<RaisedButton
|
||||
label={label}
|
||||
type={type}
|
||||
labelStyle={styles.raisedbutton}
|
||||
style={styles.raisedbutton}
|
||||
primary={primary}
|
||||
onTouchTap={onTouchTap}
|
||||
return (
|
||||
<RaisedButton
|
||||
label={label}
|
||||
type={type}
|
||||
labelStyle={styles.raisedbutton}
|
||||
style={styles.raisedbutton}
|
||||
primary={primary}
|
||||
onTouchTap={onTouchTap}
|
||||
>
|
||||
{children}
|
||||
</RaisedButton>
|
||||
)
|
||||
{children}
|
||||
</RaisedButton>
|
||||
)
|
||||
}
|
||||
|
||||
RaisedButtonStyled.propTypes = {
|
||||
type: PropTypes.string,
|
||||
primary: PropTypes.bool,
|
||||
onTouchTap: PropTypes.func,
|
||||
children: PropTypes.string
|
||||
type: PropTypes.string,
|
||||
primary: PropTypes.bool,
|
||||
onTouchTap: PropTypes.func,
|
||||
children: PropTypes.string
|
||||
}
|
||||
export default RaisedButtonStyled
|
||||
export default RaisedButtonStyled
|
||||
|
|
|
@ -2,33 +2,33 @@ import React from 'react'
|
|||
import { Stepper, Step, StepLabel } from 'material-ui/Stepper'
|
||||
|
||||
export const styles = {
|
||||
steplabel: {
|
||||
fontSize: 12,
|
||||
height: 36,
|
||||
padding: 3,
|
||||
margin: 3
|
||||
}
|
||||
steplabel: {
|
||||
fontSize: 12,
|
||||
height: 36,
|
||||
padding: 3,
|
||||
margin: 3
|
||||
}
|
||||
}
|
||||
|
||||
export const StepperStyled = ({activeStep, connector, labels, stepLabelClass}) => {
|
||||
return (
|
||||
<Stepper
|
||||
activeStep={activeStep}
|
||||
connector={connector}
|
||||
style={styles.steplabel}
|
||||
return (
|
||||
<Stepper
|
||||
activeStep={activeStep}
|
||||
connector={connector}
|
||||
style={styles.steplabel}
|
||||
>
|
||||
{labels.map(label =>
|
||||
<Step key={label}>
|
||||
<StepLabel
|
||||
className={stepLabelClass}
|
||||
style={styles.steplabel}
|
||||
{labels.map(label =>
|
||||
<Step key={label}>
|
||||
<StepLabel
|
||||
className={stepLabelClass}
|
||||
style={styles.steplabel}
|
||||
>
|
||||
{label}
|
||||
</StepLabel>
|
||||
</Step>
|
||||
{label}
|
||||
</StepLabel>
|
||||
</Step>
|
||||
)}
|
||||
</Stepper>
|
||||
)
|
||||
</Stepper>
|
||||
)
|
||||
}
|
||||
|
||||
export default StepperStyled
|
||||
export default StepperStyled
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
# About this folder
|
||||
|
||||
This folder holds configuration files for different environments.
|
||||
|
||||
You can use it to provide your app with different settings based on the
|
||||
current environment, e.g. to configure different API base urls depending on
|
||||
whether your setup runs in dev mode or is built for distribution.
|
||||
|
||||
***Note that there is a Webpack alias defined in /cfg/base.js which redirects `'config'` to `'${projectRoot}/config/$env'`***
|
||||
|
||||
You can include the configuration into your code like this:
|
||||
|
||||
**ES2015 Modules**
|
||||
|
||||
```js
|
||||
import config from 'config';
|
||||
```
|
||||
|
||||
**Common JS**
|
||||
|
||||
Due to Babel6 we need to append `.default`.
|
||||
|
||||
```js
|
||||
let config = require('config').default;
|
||||
```
|
||||
|
||||
**Example**
|
||||
|
||||
```javascript
|
||||
import React from 'react';
|
||||
import config from 'config';
|
||||
|
||||
class MyComponent extends React.Component {
|
||||
constructor(props, ctx) {
|
||||
super(props, ctx);
|
||||
let currentAppEnv = config.appEnv;
|
||||
}
|
||||
}
|
||||
```
|
|
@ -1,7 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
// The global 'constants' is being defined by Webpack in /cfg/[dev|dist|test|localhost].js
|
||||
// eslint-disable-next-line no-undef
|
||||
let config = constants
|
||||
|
||||
export default config
|
|
@ -1,9 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
import baseConfig from './base'
|
||||
|
||||
let config = {
|
||||
appEnv: 'dev' // feel free to remove the appEnv property here
|
||||
}
|
||||
|
||||
export default Object.freeze(Object.assign({}, baseConfig, config))
|
|
@ -1,9 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
import baseConfig from './base'
|
||||
|
||||
let config = {
|
||||
appEnv: 'dist' // feel free to remove the appEnv property here
|
||||
}
|
||||
|
||||
export default Object.freeze(Object.assign({}, baseConfig, config))
|
|
@ -0,0 +1,16 @@
|
|||
let config
|
||||
try {
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
export default config
|
|
@ -1,9 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
import baseConfig from './base'
|
||||
|
||||
let config = {
|
||||
appEnv: 'localhost' // feel free to remove the appEnv property here
|
||||
}
|
||||
|
||||
export default Object.freeze(Object.assign({}, baseConfig, config))
|
|
@ -1,10 +0,0 @@
|
|||
'use strict'
|
||||
|
||||
import baseConfig from './base'
|
||||
|
||||
let config = {
|
||||
appEnv: 'test', // don't remove the appEnv property here
|
||||
authVersion: 'TEST'
|
||||
}
|
||||
|
||||
export default Object.freeze(Object.assign(baseConfig, config))
|
|
@ -1,10 +1,10 @@
|
|||
import { createStore, applyMiddleware, compose } from 'redux'
|
||||
import thunk from 'redux-thunk'
|
||||
import establishSignalRConnection from './services/signalRService'
|
||||
import { ListenForScreenSize } from './actions/styleActions'
|
||||
import incidentApp from './reducers'
|
||||
import establishSignalRConnection from 'services/signalRService'
|
||||
import { ListenForScreenSize } from 'actions/styleActions'
|
||||
import incidentApp from 'reducers'
|
||||
import { persistStore } from 'redux-persist'
|
||||
import { getFilterFromUrl } from './actions/filterActions'
|
||||
import { getFilterFromUrl } from 'actions/filterActions'
|
||||
|
||||
const urlFilter = getFilterFromUrl(window.location.search)
|
||||
const reducer = incidentApp(urlFilter)
|
||||
|
@ -16,4 +16,3 @@ export const persistor = persistStore(store)
|
|||
establishSignalRConnection(store.dispatch)
|
||||
|
||||
ListenForScreenSize(window, store)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { connect } from 'react-redux'
|
||||
//import { setVisibilityFilter } from '../actions'
|
||||
import Link from '../components/Link'
|
||||
// import { setVisibilityFilter } from 'actions'
|
||||
import Link from 'components/Link'
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
|
@ -8,11 +8,11 @@ const mapStateToProps = (state, ownProps) => {
|
|||
}
|
||||
}
|
||||
|
||||
//const mapDispatchToProps = (dispatch, ownProps) => {
|
||||
// const mapDispatchToProps = (dispatch, ownProps) => {
|
||||
const mapDispatchToProps = () => {
|
||||
return {
|
||||
onClick: () => {
|
||||
//dispatch(setVisibilityFilter(ownProps.filter))
|
||||
// dispatch(setVisibilityFilter(ownProps.filter))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,4 +22,4 @@ const FilterLink = connect(
|
|||
mapDispatchToProps
|
||||
)(Link)
|
||||
|
||||
export default FilterLink
|
||||
export default FilterLink
|
||||
|
|
|
@ -3,8 +3,8 @@ import ReactDOM from 'react-dom'
|
|||
import injectTapEventPlugin from 'react-tap-event-plugin'
|
||||
import { AppContainer as HotContainer } from 'react-hot-loader'
|
||||
|
||||
import { store, persistor } from './configureStore'
|
||||
import MainComponent from './components/MainComponent'
|
||||
import { store, persistor } from 'configureStore'
|
||||
import MainComponent from 'components/MainComponent'
|
||||
|
||||
require('./styles/App.css')
|
||||
|
||||
|
|
|
@ -1,55 +1,55 @@
|
|||
import { USER_LOGGED_IN, USER_LOGGED_OUT, USER_LOGIN_ERROR, LOGIN_IN_PROGRESS } from '../actions/authActions.js'
|
||||
import * as authNService from '../services/authNService'
|
||||
import { USER_LOGGED_IN, USER_LOGGED_OUT, USER_LOGIN_ERROR, LOGIN_IN_PROGRESS } from 'actions/authActions.js'
|
||||
import * as authNService from 'services/authNService'
|
||||
|
||||
const getDefaultState = () => {
|
||||
const defaultState = {
|
||||
isLoggedIn: authNService.isLoggedIn(),
|
||||
loginInProgress: authNService.loginInProgress(),
|
||||
signInAutomatically: true,
|
||||
userTeam: 'none',
|
||||
userRole: 'Crisis Manager',
|
||||
userAlias: authNService.getUserAlias()
|
||||
}
|
||||
return defaultState
|
||||
const defaultState = {
|
||||
isLoggedIn: authNService.isLoggedIn(),
|
||||
loginInProgress: authNService.loginInProgress(),
|
||||
signInAutomatically: true,
|
||||
userTeam: 'none',
|
||||
userRole: 'Crisis Manager',
|
||||
userAlias: authNService.getUserAlias()
|
||||
}
|
||||
return defaultState
|
||||
}
|
||||
|
||||
const authReducer = (state = getDefaultState(), action) => {
|
||||
switch (action.type) {
|
||||
case LOGIN_IN_PROGRESS:
|
||||
return {
|
||||
...state,
|
||||
loginInProgress: true,
|
||||
error: null
|
||||
}
|
||||
case USER_LOGGED_IN:
|
||||
return {
|
||||
...state,
|
||||
isLoggedIn: true,
|
||||
error: null,
|
||||
loginInProgress: false,
|
||||
signInAutomatically: true,
|
||||
userAlias: authNService.getUserAlias(action.user)
|
||||
}
|
||||
case USER_LOGGED_OUT:
|
||||
return {
|
||||
...state,
|
||||
isLoggedIn: false,
|
||||
error: null,
|
||||
loginInProgress: false,
|
||||
signInAutomatically: false,
|
||||
userAlias: null
|
||||
}
|
||||
case USER_LOGIN_ERROR:
|
||||
return {
|
||||
...state,
|
||||
isLoggedIn: false,
|
||||
error: action.error,
|
||||
loginInProgress: false,
|
||||
userAlias: null
|
||||
}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
switch (action.type) {
|
||||
case LOGIN_IN_PROGRESS:
|
||||
return {
|
||||
...state,
|
||||
loginInProgress: true,
|
||||
error: null
|
||||
}
|
||||
case USER_LOGGED_IN:
|
||||
return {
|
||||
...state,
|
||||
isLoggedIn: true,
|
||||
error: null,
|
||||
loginInProgress: false,
|
||||
signInAutomatically: true,
|
||||
userAlias: authNService.getUserAlias(action.user)
|
||||
}
|
||||
case USER_LOGGED_OUT:
|
||||
return {
|
||||
...state,
|
||||
isLoggedIn: false,
|
||||
error: null,
|
||||
loginInProgress: false,
|
||||
signInAutomatically: false,
|
||||
userAlias: null
|
||||
}
|
||||
case USER_LOGIN_ERROR:
|
||||
return {
|
||||
...state,
|
||||
isLoggedIn: false,
|
||||
error: action.error,
|
||||
loginInProgress: false,
|
||||
userAlias: null
|
||||
}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
export default authReducer
|
||||
export default authReducer
|
||||
|
|
|
@ -1,38 +1,37 @@
|
|||
import paginated from 'paginated-redux'
|
||||
import * as engagementActions from '../actions/engagementActions'
|
||||
import * as incidentActions from '../actions/incidentActions'
|
||||
import { mergeWithOverwrite } from './reducerHelpers/merge'
|
||||
import * as engagementActions from 'actions/engagementActions'
|
||||
import * as incidentActions from 'actions/incidentActions'
|
||||
import { mergeWithOverwrite } from 'reducers/reducerHelpers/merge'
|
||||
|
||||
const defaultEngagementCollection = []
|
||||
|
||||
|
||||
const addEngagementToState = (state, engagement) => {
|
||||
return addEngagementsToState(state, [engagement])
|
||||
return addEngagementsToState(state, [engagement])
|
||||
}
|
||||
|
||||
const addEngagementsToState = (state, engagements) => {
|
||||
return mergeWithOverwrite(state, engagements)
|
||||
return mergeWithOverwrite(state, engagements)
|
||||
}
|
||||
|
||||
export const list = (state = defaultEngagementCollection, action) => {
|
||||
switch(action.type){
|
||||
case incidentActions.RECEIVE_INCIDENT:
|
||||
return addEngagementsToState(state, action.incident.engagements)
|
||||
case incidentActions.RECEIVE_INCIDENTS:
|
||||
case incidentActions.FETCH_INCIDENTS_BY_TICKET_ID_SUCCESS:
|
||||
return addEngagementsToState(state,
|
||||
switch (action.type) {
|
||||
case incidentActions.RECEIVE_INCIDENT:
|
||||
return addEngagementsToState(state, action.incident.engagements)
|
||||
case incidentActions.RECEIVE_INCIDENTS:
|
||||
case incidentActions.FETCH_INCIDENTS_BY_TICKET_ID_SUCCESS:
|
||||
return addEngagementsToState(state,
|
||||
action.incidents
|
||||
.map(incident => incident.engagements)
|
||||
.reduce( (a, b) => a.concat(b), [] )
|
||||
.reduce((a, b) => a.concat(b), [])
|
||||
)
|
||||
case engagementActions.ENGAGE_SUCCESS:
|
||||
case engagementActions.DISENGAGE_SUCCESS:
|
||||
return addEngagementToState(state, action.engagement)
|
||||
default:
|
||||
return state
|
||||
}
|
||||
case engagementActions.ENGAGE_SUCCESS:
|
||||
case engagementActions.DISENGAGE_SUCCESS:
|
||||
return addEngagementToState(state, action.engagement)
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
export const engagements = paginated(list, engagementActions.pagination.types)
|
||||
|
||||
export default engagements
|
||||
export default engagements
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
import { combineReducers } from 'redux'
|
||||
import paginated from 'paginated-redux'
|
||||
import moment from 'moment'
|
||||
import filter from './filterReducer'
|
||||
import * as filterActions from '../actions/filterActions'
|
||||
import * as eventActions from '../actions/eventActions'
|
||||
import { mergeWithOverwrite } from './reducerHelpers/merge'
|
||||
import buildFetching from './reducerHelpers/fetching'
|
||||
import buildError from './reducerHelpers/error'
|
||||
import filter from 'reducers/filterReducer'
|
||||
import * as filterActions from 'actions/filterActions'
|
||||
import * as eventActions from 'actions/eventActions'
|
||||
import { mergeWithOverwrite } from 'reducers/reducerHelpers/merge'
|
||||
import buildFetching from 'reducers/reducerHelpers/fetching'
|
||||
import buildError from 'reducers/reducerHelpers/error'
|
||||
|
||||
const defaultEventCollection = []
|
||||
|
||||
const makeSearchable = (event) => ({
|
||||
...event,
|
||||
filterableIncidentId: event.incidentId.toString()
|
||||
...event,
|
||||
filterableIncidentId: event.incidentId.toString()
|
||||
})
|
||||
|
||||
const addEventsToState = (state, events) => mergeWithOverwrite(state, events.map(event => makeSearchable(event)))
|
||||
|
||||
export const rawList = (state = defaultEventCollection, action) => {
|
||||
switch(action.type){
|
||||
case eventActions.RECEIVE_EVENT:
|
||||
case eventActions.POST_EVENT_SUCCEED:
|
||||
return addEventsToState(state, [{...action.event, timeReceived: moment()}])
|
||||
case eventActions.RECEIVE_EVENTS:
|
||||
return addEventsToState(state, action.events)
|
||||
case filterActions.CHANGE_EVENT_FILTER:
|
||||
return defaultEventCollection
|
||||
default:
|
||||
return state
|
||||
}
|
||||
switch (action.type) {
|
||||
case eventActions.RECEIVE_EVENT:
|
||||
case eventActions.POST_EVENT_SUCCEED:
|
||||
return addEventsToState(state, [{...action.event, timeReceived: moment()}])
|
||||
case eventActions.RECEIVE_EVENTS:
|
||||
return addEventsToState(state, action.events)
|
||||
case filterActions.CHANGE_EVENT_FILTER:
|
||||
return defaultEventCollection
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
const actionSet = {
|
||||
try: eventActions.REQUEST_EVENT,
|
||||
succeed: eventActions.RECEIVE_EVENT,
|
||||
fail: eventActions.RECEIVE_EVENT_FAILURE
|
||||
try: eventActions.REQUEST_EVENT,
|
||||
succeed: eventActions.RECEIVE_EVENT,
|
||||
fail: eventActions.RECEIVE_EVENT_FAILURE
|
||||
}
|
||||
|
||||
const fetching = buildFetching(actionSet)
|
||||
|
@ -42,19 +42,19 @@ const fetching = buildFetching(actionSet)
|
|||
const error = buildError(actionSet)
|
||||
|
||||
const pageArgs = {
|
||||
defaultPage: 1,
|
||||
defaultSortOrder: 'desc',
|
||||
defaultSortBy: 'occurred',
|
||||
defaultPer: 10,
|
||||
defaultFilter: '',
|
||||
defaultTotal: 0
|
||||
defaultPage: 1,
|
||||
defaultSortOrder: 'desc',
|
||||
defaultSortBy: 'occurred',
|
||||
defaultPer: 10,
|
||||
defaultFilter: '',
|
||||
defaultTotal: 0
|
||||
}
|
||||
|
||||
export const pages = paginated(rawList, eventActions.pagination.types, pageArgs)
|
||||
|
||||
export default (defaultFilter) => combineReducers({
|
||||
fetching,
|
||||
error,
|
||||
pages,
|
||||
filter: filter(defaultFilter)
|
||||
fetching,
|
||||
error,
|
||||
pages,
|
||||
filter: filter(defaultFilter)
|
||||
})
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import { combineReducers } from 'redux'
|
||||
import * as eventTypeActions from '../actions/eventTypeActions'
|
||||
import { mergeToStateById } from './reducerHelpers/merge'
|
||||
import buildFetching from './reducerHelpers/fetching'
|
||||
import buildError from './reducerHelpers/error'
|
||||
import * as eventTypeActions from 'actions/eventTypeActions'
|
||||
import { mergeToStateById } from 'reducers/reducerHelpers/merge'
|
||||
import buildFetching from 'reducers/reducerHelpers/fetching'
|
||||
import buildError from 'reducers/reducerHelpers/error'
|
||||
import { persistReducer } from 'redux-persist'
|
||||
import storage from 'redux-persist/lib/storage' // default: localStorage if web, AsyncStorage if react-native
|
||||
|
||||
const defaultEventTypeCollection = {}
|
||||
|
||||
const actionSet = {
|
||||
try: eventTypeActions.TRY_GET_EVENT_TYPE,
|
||||
succeed: eventTypeActions.GET_EVENT_TYPE_SUCCESS,
|
||||
fail: eventTypeActions.GET_EVENT_TYPE_FAILURE
|
||||
try: eventTypeActions.TRY_GET_EVENT_TYPE,
|
||||
succeed: eventTypeActions.GET_EVENT_TYPE_SUCCESS,
|
||||
fail: eventTypeActions.GET_EVENT_TYPE_FAILURE
|
||||
}
|
||||
|
||||
const fetching = buildFetching(actionSet)
|
||||
|
@ -19,22 +19,22 @@ const fetching = buildFetching(actionSet)
|
|||
const error = buildError(actionSet)
|
||||
|
||||
export const records = (state = defaultEventTypeCollection, action) => {
|
||||
switch(action.type){
|
||||
case eventTypeActions.GET_EVENT_TYPE_SUCCESS:
|
||||
return mergeToStateById(state, action.eventType)
|
||||
case eventTypeActions.GET_EVENT_TYPES_SUCCESS:
|
||||
return mergeToStateById(state, action.eventTypes)
|
||||
default:
|
||||
return state
|
||||
}
|
||||
switch (action.type) {
|
||||
case eventTypeActions.GET_EVENT_TYPE_SUCCESS:
|
||||
return mergeToStateById(state, action.eventType)
|
||||
case eventTypeActions.GET_EVENT_TYPES_SUCCESS:
|
||||
return mergeToStateById(state, action.eventTypes)
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
const persistedRecords = persistReducer({ key: 'eventType', storage }, records)
|
||||
|
||||
export const eventTypeReducer = combineReducers({
|
||||
fetching,
|
||||
error,
|
||||
records: persistedRecords
|
||||
fetching,
|
||||
error,
|
||||
records: persistedRecords
|
||||
})
|
||||
|
||||
export default eventTypeReducer
|
||||
export default eventTypeReducer
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import { TOGGLE_COLLAPSE } from '../actions/expandSectionActions'
|
||||
import { TOGGLE_COLLAPSE } from 'actions/expandSectionActions'
|
||||
|
||||
|
||||
export default function expandSectionReducer(state = {}, action) {
|
||||
switch (action.type) {
|
||||
case TOGGLE_COLLAPSE:
|
||||
return {
|
||||
...state,
|
||||
[action.elementName]: !state[action.elementName]
|
||||
}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
export default function expandSectionReducer (state = {}, action) {
|
||||
switch (action.type) {
|
||||
case TOGGLE_COLLAPSE:
|
||||
return {
|
||||
...state,
|
||||
[action.elementName]: !state[action.elementName]
|
||||
}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import * as filterActions from '../actions/filterActions'
|
||||
import * as filterActions from 'actions/filterActions'
|
||||
|
||||
export const filter = (defaultFilter) => (state = defaultFilter, action) => {
|
||||
switch (action.type) {
|
||||
case filterActions.CHANGE_EVENT_FILTER:
|
||||
return {...state, eventTypes: [], ticketId: null, ...action.filter}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
switch (action.type) {
|
||||
case filterActions.CHANGE_EVENT_FILTER:
|
||||
return {...state, eventTypes: [], ticketId: null, ...action.filter}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
export default filter
|
||||
export default filter
|
||||
|
|
|
@ -1,36 +1,36 @@
|
|||
import * as formActions from '../actions/formActions'
|
||||
import * as formActions from 'actions/formActions'
|
||||
|
||||
const defaultForms = {}
|
||||
|
||||
const updateInput = (state, form, field, value = null) => {
|
||||
var newState = {...state}
|
||||
const oldForm = state[form]
|
||||
var newForm = {...oldForm}
|
||||
var newState = {...state}
|
||||
const oldForm = state[form]
|
||||
var newForm = {...oldForm}
|
||||
|
||||
newForm[field] = value
|
||||
newState[form] = newForm
|
||||
return newState
|
||||
newForm[field] = value
|
||||
newState[form] = newForm
|
||||
return newState
|
||||
}
|
||||
|
||||
const clearInput = (state, form, field) => updateInput(state, form, field)
|
||||
|
||||
const clearForm = (state, form) => {
|
||||
var newState = {...state}
|
||||
newState[form] = null
|
||||
return newState
|
||||
var newState = {...state}
|
||||
newState[form] = null
|
||||
return newState
|
||||
}
|
||||
|
||||
export const reducer = (state = defaultForms, action) => {
|
||||
switch(action.type) {
|
||||
case formActions.UPDATE_INPUT:
|
||||
return updateInput(state, action.form, action.field, action.value)
|
||||
case formActions.CLEAR_INPUT:
|
||||
return clearInput(state, action.form, action.field)
|
||||
case formActions.CLEAR_FORM:
|
||||
return clearForm(state, action.form)
|
||||
default:
|
||||
return state
|
||||
}
|
||||
switch (action.type) {
|
||||
case formActions.UPDATE_INPUT:
|
||||
return updateInput(state, action.form, action.field, action.value)
|
||||
case formActions.CLEAR_INPUT:
|
||||
return clearInput(state, action.form, action.field)
|
||||
case formActions.CLEAR_FORM:
|
||||
return clearForm(state, action.form)
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
export default reducer
|
||||
export default reducer
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import * as globalActionActions from '../actions/globalActionActions'
|
||||
import { mergeToStateById } from './reducerHelpers/merge'
|
||||
import * as globalActionActions from 'actions/globalActionActions'
|
||||
import { mergeToStateById } from 'reducers/reducerHelpers/merge'
|
||||
|
||||
const defaultGlobalActionCollection = {}
|
||||
|
||||
export const records = (state = defaultGlobalActionCollection, action) => {
|
||||
switch(action.type){
|
||||
case globalActionActions.GET_GLOBAL_ACTIONS_SUCCESS:
|
||||
return mergeToStateById(state, action.globalActions)
|
||||
default:
|
||||
return state
|
||||
}
|
||||
switch (action.type) {
|
||||
case globalActionActions.GET_GLOBAL_ACTIONS_SUCCESS:
|
||||
return mergeToStateById(state, action.globalActions)
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
export default records
|
||||
|
|
|
@ -1,101 +1,101 @@
|
|||
import { combineReducers } from 'redux'
|
||||
import * as incidentActions from '../actions/incidentActions'
|
||||
import { ENGAGE_SUCCESS, DISENGAGE_SUCCESS } from '../actions/engagementActions'
|
||||
import buildFetching from './reducerHelpers/fetching'
|
||||
import buildError from './reducerHelpers/error'
|
||||
import * as incidentActions from 'actions/incidentActions'
|
||||
import { ENGAGE_SUCCESS, DISENGAGE_SUCCESS } from 'actions/engagementActions'
|
||||
import buildFetching from 'reducers/reducerHelpers/fetching'
|
||||
import buildError from 'reducers/reducerHelpers/error'
|
||||
|
||||
const defaultIncidents = []
|
||||
|
||||
const mapIncidents = (incidents) => {
|
||||
let incidentsMap = {}
|
||||
incidents.map(incident => incidentsMap[incident.id] = incident)
|
||||
return incidentsMap
|
||||
let incidentsMap = {}
|
||||
incidents.map(incident => { incidentsMap[incident.id] = incident })
|
||||
return incidentsMap
|
||||
}
|
||||
|
||||
const defaultIncidentMap = mapIncidents(defaultIncidents)
|
||||
|
||||
const startFetch = {
|
||||
IsFetching: true
|
||||
IsFetching: true
|
||||
}
|
||||
|
||||
const endFetch = {
|
||||
IsFetching: false
|
||||
IsFetching: false
|
||||
}
|
||||
|
||||
const addIncidentToState = (state, incident, incidentPropertyUpdates) => {
|
||||
return addIncidentsToState(state, [incident], incidentPropertyUpdates)
|
||||
return addIncidentsToState(state, [incident], incidentPropertyUpdates)
|
||||
}
|
||||
|
||||
const addIncidentsToState = (state, incidents, incidentPropertyUpdates) => {
|
||||
let newState = {...state}
|
||||
incidents.map(incident => newState[incident.id] = Object.assign({}, incident, incidentPropertyUpdates))
|
||||
return newState
|
||||
let newState = {...state}
|
||||
incidents.map(incident => { newState[incident.id] = Object.assign({}, incident, incidentPropertyUpdates) })
|
||||
return newState
|
||||
}
|
||||
|
||||
export const map = (state = defaultIncidentMap, action) => {
|
||||
switch(action.type) {
|
||||
case incidentActions.RECEIVE_INCIDENT:
|
||||
case incidentActions.CREATE_INCIDENT_SUCCESS:
|
||||
return addIncidentToState(state, action.incident, endFetch)
|
||||
case incidentActions.RECEIVE_INCIDENT_FAILURE:
|
||||
return addIncidentToState(state, {id: action.id, error: action.error}, endFetch)
|
||||
case incidentActions.RECEIVE_INCIDENTS:
|
||||
case incidentActions.FETCH_INCIDENTS_BY_TICKET_ID_SUCCESS:
|
||||
return addIncidentsToState(state, action.incidents, endFetch)
|
||||
case incidentActions.REQUEST_INCIDENT:
|
||||
const localIncidentRecord = state[action.incidentId]
|
||||
return addIncidentToState(state, localIncidentRecord ? localIncidentRecord : { id: action.incidentId } , startFetch)
|
||||
case incidentActions.REQUEST_INCIDENTS:
|
||||
return addIncidentsToState(state, Object.values(state), startFetch)
|
||||
case ENGAGE_SUCCESS:
|
||||
case DISENGAGE_SUCCESS:
|
||||
const existingIncident = state[action.engagement.incidentId]
|
||||
return addIncidentToState(state, existingIncident, {
|
||||
engagements: Array
|
||||
switch (action.type) {
|
||||
case incidentActions.RECEIVE_INCIDENT:
|
||||
case incidentActions.CREATE_INCIDENT_SUCCESS:
|
||||
return addIncidentToState(state, action.incident, endFetch)
|
||||
case incidentActions.RECEIVE_INCIDENT_FAILURE:
|
||||
return addIncidentToState(state, {id: action.id, error: action.error}, endFetch)
|
||||
case incidentActions.RECEIVE_INCIDENTS:
|
||||
case incidentActions.FETCH_INCIDENTS_BY_TICKET_ID_SUCCESS:
|
||||
return addIncidentsToState(state, action.incidents, endFetch)
|
||||
case incidentActions.REQUEST_INCIDENT:
|
||||
const localIncidentRecord = state[action.incidentId]
|
||||
return addIncidentToState(state, localIncidentRecord || { id: action.incidentId }, startFetch)
|
||||
case incidentActions.REQUEST_INCIDENTS:
|
||||
return addIncidentsToState(state, Object.values(state), startFetch)
|
||||
case ENGAGE_SUCCESS:
|
||||
case DISENGAGE_SUCCESS:
|
||||
const existingIncident = state[action.engagement.incidentId]
|
||||
return addIncidentToState(state, existingIncident, {
|
||||
engagements: Array
|
||||
.from(existingIncident.engagements)
|
||||
.filter(engagement => engagement.id !== action.engagement.id)
|
||||
.concat(action.engagement)
|
||||
})
|
||||
default:
|
||||
return state
|
||||
}
|
||||
})
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
const defaultCreationState = {
|
||||
input: ''
|
||||
input: ''
|
||||
}
|
||||
|
||||
export const creation = (state = defaultCreationState, action) =>{
|
||||
switch(action.type){
|
||||
case incidentActions.UPDATE_INCIDENT_CREATION_INPUT:
|
||||
return {
|
||||
...state,
|
||||
input: action.input
|
||||
}
|
||||
case incidentActions.TRY_CREATE_INCIDENT:
|
||||
return {
|
||||
...state,
|
||||
error: null
|
||||
}
|
||||
case incidentActions.CREATE_INCIDENT_FAILURE:
|
||||
return {
|
||||
...state,
|
||||
error: action.reason
|
||||
}
|
||||
case incidentActions.CREATE_INCIDENT_SUCCESS:
|
||||
return {
|
||||
input: '',
|
||||
error: null
|
||||
}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
export const creation = (state = defaultCreationState, action) => {
|
||||
switch (action.type) {
|
||||
case incidentActions.UPDATE_INCIDENT_CREATION_INPUT:
|
||||
return {
|
||||
...state,
|
||||
input: action.input
|
||||
}
|
||||
case incidentActions.TRY_CREATE_INCIDENT:
|
||||
return {
|
||||
...state,
|
||||
error: null
|
||||
}
|
||||
case incidentActions.CREATE_INCIDENT_FAILURE:
|
||||
return {
|
||||
...state,
|
||||
error: action.reason
|
||||
}
|
||||
case incidentActions.CREATE_INCIDENT_SUCCESS:
|
||||
return {
|
||||
input: '',
|
||||
error: null
|
||||
}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
const actionSetByIncidentId = {
|
||||
try: incidentActions.REQUEST_INCIDENT,
|
||||
succeed: incidentActions.RECEIVE_INCIDENT,
|
||||
fail: incidentActions.RECEIVE_INCIDENT_FAILURE
|
||||
try: incidentActions.REQUEST_INCIDENT,
|
||||
succeed: incidentActions.RECEIVE_INCIDENT,
|
||||
fail: incidentActions.RECEIVE_INCIDENT_FAILURE
|
||||
}
|
||||
|
||||
const fetchingByIncidentId = buildFetching(actionSetByIncidentId)
|
||||
|
@ -103,9 +103,9 @@ const fetchingByIncidentId = buildFetching(actionSetByIncidentId)
|
|||
const errorByIncidentId = buildError(actionSetByIncidentId)
|
||||
|
||||
const actionSetByTicketId = {
|
||||
try: incidentActions.REQUEST_INCIDENT_BY_TICKET_ID,
|
||||
succeed: incidentActions.FETCH_INCIDENTS_BY_TICKET_ID_SUCCESS,
|
||||
fail: incidentActions.FETCH_INCIDENTS_BY_TICKET_ID_FAILURE
|
||||
try: incidentActions.REQUEST_INCIDENT_BY_TICKET_ID,
|
||||
succeed: incidentActions.FETCH_INCIDENTS_BY_TICKET_ID_SUCCESS,
|
||||
fail: incidentActions.FETCH_INCIDENTS_BY_TICKET_ID_FAILURE
|
||||
}
|
||||
|
||||
const fetchingByTicketId = buildFetching(actionSetByTicketId,
|
||||
|
@ -119,12 +119,12 @@ const errorByTicketId = buildError(actionSetByTicketId,
|
|||
)
|
||||
|
||||
const incidentReducer = combineReducers({
|
||||
map,
|
||||
creation,
|
||||
fetchingByIncidentId,
|
||||
errorByIncidentId,
|
||||
fetchingByTicketId,
|
||||
errorByTicketId
|
||||
map,
|
||||
creation,
|
||||
fetchingByIncidentId,
|
||||
errorByIncidentId,
|
||||
fetchingByTicketId,
|
||||
errorByTicketId
|
||||
})
|
||||
|
||||
export default incidentReducer
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче