Merge branch 'master' into yizha/removeAlias

This commit is contained in:
yingzhao-1 2018-01-18 10:40:16 -08:00 коммит произвёл GitHub
Родитель 471a8e1e0f a35f656c84
Коммит e912bd4e1b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
156 изменённых файлов: 13456 добавлений и 14371 удалений

Просмотреть файл

@ -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"
}
}]
]
}

Просмотреть файл

@ -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"]
}
}

3
.gitignore поставляемый
Просмотреть файл

@ -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
Просмотреть файл

@ -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.

6507
dist/assets/app.js поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

2
dist/assets/app.js.map поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

2
dist/index.html поставляемый
Просмотреть файл

@ -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>

19
jsconfig.json Normal file
Просмотреть файл

@ -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' }
]
}
});
};
})
}

Просмотреть файл

11957
package-lock.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",

Просмотреть файл

@ -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>
&nbsp;
{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}` : ''}:
&nbsp;
<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}` : ''}:
&nbsp;
<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))

16
src/config/index.js Normal file
Просмотреть файл

@ -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

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше