phobos_checkpoint_ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +81 -0
- data/Rakefile +12 -0
- data/assets/index-52cbf3063583f3c09a4b-0.css +2 -0
- data/assets/index-52cbf3063583f3c09a4b-0.css.map +1 -0
- data/assets/index-52cbf3063583f3c09a4b-1.css +2 -0
- data/assets/index-52cbf3063583f3c09a4b-1.css.map +1 -0
- data/assets/index-52cbf3063583f3c09a4b.js +49 -0
- data/assets/index-52cbf3063583f3c09a4b.js.map +1 -0
- data/assets/index.html +12 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/circle.yml +29 -0
- data/frontend/.babelrc +3 -0
- data/frontend/.editorconfig +8 -0
- data/frontend/.eslintignore +2 -0
- data/frontend/.eslintrc +3 -0
- data/frontend/.npmignore +8 -0
- data/frontend/package.json +45 -0
- data/frontend/sagui.config.js +52 -0
- data/frontend/src/actions/event-details.js +42 -0
- data/frontend/src/actions/event-details.spec.js +71 -0
- data/frontend/src/actions/event-overview.js +11 -0
- data/frontend/src/actions/event-overview.spec.js +20 -0
- data/frontend/src/actions/event-retry.js +58 -0
- data/frontend/src/actions/event-retry.spec.js +117 -0
- data/frontend/src/actions/events-search.js +75 -0
- data/frontend/src/actions/events-search.spec.js +197 -0
- data/frontend/src/actions/flash-messages.js +16 -0
- data/frontend/src/actions/flash-messages.spec.js +23 -0
- data/frontend/src/actions/index.js +24 -0
- data/frontend/src/actions/search-input-filter.js +14 -0
- data/frontend/src/actions/search-input-filter.spec.js +20 -0
- data/frontend/src/api.js +46 -0
- data/frontend/src/components/event/error-message.js +19 -0
- data/frontend/src/components/event/error-message.scss +8 -0
- data/frontend/src/components/event/event.scss +3 -0
- data/frontend/src/components/event/index.js +77 -0
- data/frontend/src/components/event/index.spec.js +89 -0
- data/frontend/src/components/event/loading.js +16 -0
- data/frontend/src/components/event/style.js +16 -0
- data/frontend/src/components/event-overview/attribute.js +24 -0
- data/frontend/src/components/event-overview/event-overview.scss +28 -0
- data/frontend/src/components/event-overview/index.js +47 -0
- data/frontend/src/components/event-overview/index.spec.js +67 -0
- data/frontend/src/components/event-overview-dialog/event-overview-dialog.scss +15 -0
- data/frontend/src/components/event-overview-dialog/index.js +85 -0
- data/frontend/src/components/event-retry-dialog/index.js +72 -0
- data/frontend/src/components/events-list/events-list.scss +49 -0
- data/frontend/src/components/events-list/index.js +62 -0
- data/frontend/src/components/events-list/index.spec.js +59 -0
- data/frontend/src/components/flash-message/flash-message.scss +40 -0
- data/frontend/src/components/flash-message/index.js +45 -0
- data/frontend/src/components/flash-message/index.spec.js +59 -0
- data/frontend/src/components/flash-message-list/index.js +34 -0
- data/frontend/src/components/header/header.scss +29 -0
- data/frontend/src/components/header/index.js +44 -0
- data/frontend/src/components/search-input/index.js +104 -0
- data/frontend/src/components/search-input/index.spec.js +56 -0
- data/frontend/src/components/search-input/search-input.scss +7 -0
- data/frontend/src/configs.js +15 -0
- data/frontend/src/helpers.spec.js +2 -0
- data/frontend/src/index.html +12 -0
- data/frontend/src/index.js +26 -0
- data/frontend/src/index.scss +31 -0
- data/frontend/src/reducers/event-details.js +32 -0
- data/frontend/src/reducers/event-details.spec.js +54 -0
- data/frontend/src/reducers/events-filters.js +17 -0
- data/frontend/src/reducers/events-filters.spec.js +34 -0
- data/frontend/src/reducers/events.js +48 -0
- data/frontend/src/reducers/events.spec.js +95 -0
- data/frontend/src/reducers/flash-messages.js +14 -0
- data/frontend/src/reducers/flash-messages.spec.js +34 -0
- data/frontend/src/reducers/index.js +18 -0
- data/frontend/src/reducers/index.spec.js +20 -0
- data/frontend/src/reducers/xhr-status.js +75 -0
- data/frontend/src/reducers/xhr-status.spec.js +94 -0
- data/frontend/src/routes.js +20 -0
- data/frontend/src/store.js +15 -0
- data/frontend/src/views/event-details.js +50 -0
- data/frontend/src/views/events-search.js +112 -0
- data/frontend/src/views/events-search.scss +24 -0
- data/frontend/src/views/events-search.spec.js +96 -0
- data/frontend/src/views/layout.js +24 -0
- data/frontend/src/views/layout.scss +3 -0
- data/lib/phobos_checkpoint_ui/app.rb +11 -0
- data/lib/phobos_checkpoint_ui/static_app.rb +19 -0
- data/lib/phobos_checkpoint_ui/tasks.rb +20 -0
- data/lib/phobos_checkpoint_ui/version.rb +3 -0
- data/lib/phobos_checkpoint_ui.rb +10 -0
- data/phobos_checkpoint_ui.gemspec +53 -0
- data/screenshot1.png +0 -0
- data/screenshot2.png +0 -0
- metadata +267 -0
data/assets/index.html
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>PhobosCheckpoint</title>
|
|
5
|
+
<meta charset="utf-8" />
|
|
6
|
+
<link href="/assets/index-52cbf3063583f3c09a4b-1.css" rel="stylesheet"><link href="/assets/index-52cbf3063583f3c09a4b-0.css" rel="stylesheet"></head>
|
|
7
|
+
<body>
|
|
8
|
+
<div id="root">
|
|
9
|
+
<div class='loading-boot'>Loading...</div>
|
|
10
|
+
</div>
|
|
11
|
+
<script type="text/javascript" src="/assets/index-52cbf3063583f3c09a4b.js"></script></body>
|
|
12
|
+
</html>
|
data/bin/console
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require "bundler/setup"
|
|
4
|
+
require "phobos_checkpoint_ui"
|
|
5
|
+
|
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
8
|
+
|
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
10
|
+
# require "pry"
|
|
11
|
+
# Pry.start
|
|
12
|
+
|
|
13
|
+
require "irb"
|
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/circle.yml
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
machine:
|
|
2
|
+
pre:
|
|
3
|
+
- curl -sSL https://s3.amazonaws.com/circle-downloads/install-circleci-docker.sh | bash -s -- 1.10.0
|
|
4
|
+
services:
|
|
5
|
+
- docker
|
|
6
|
+
environment:
|
|
7
|
+
LOG_LEVEL: DEBUG
|
|
8
|
+
CI: true
|
|
9
|
+
ruby:
|
|
10
|
+
version: 2.3.1
|
|
11
|
+
node:
|
|
12
|
+
version: 6.3.0
|
|
13
|
+
|
|
14
|
+
# Ignores circle ci default database setup
|
|
15
|
+
database:
|
|
16
|
+
override:
|
|
17
|
+
- echo "overrides circle CI commands"
|
|
18
|
+
|
|
19
|
+
dependencies:
|
|
20
|
+
pre:
|
|
21
|
+
- docker -v
|
|
22
|
+
- gem install bundler -v 1.9.5
|
|
23
|
+
- bundle install
|
|
24
|
+
- cd frontend; npm install
|
|
25
|
+
|
|
26
|
+
test:
|
|
27
|
+
override:
|
|
28
|
+
- bundle exec rspec -r rspec_junit_formatter --format RspecJunitFormatter -o $CIRCLE_TEST_REPORTS/rspec/unit.xml
|
|
29
|
+
- cd frontend; npm run test:unit
|
data/frontend/.babelrc
ADDED
data/frontend/.eslintrc
ADDED
data/frontend/.npmignore
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "phobos_checkpoint_ui",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Phobos Checkpoint UI is a GUI for phobos checkpoint API",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"private": true,
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">= 6.3.x"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "npm run test:lint && npm run test:unit",
|
|
12
|
+
"build": "sagui build",
|
|
13
|
+
"develop": "sagui develop --port 3000",
|
|
14
|
+
"dist": "cross-env NODE_ENV=production sagui build --optimize",
|
|
15
|
+
"start": "npm run develop",
|
|
16
|
+
"test:coverage": "npm run test:unit -- --coverage",
|
|
17
|
+
"test:lint": "sagui lint",
|
|
18
|
+
"test:unit": "cross-env NODE_ENV=test sagui test",
|
|
19
|
+
"test:unit:watch": "npm run test:unit -- --watch"
|
|
20
|
+
},
|
|
21
|
+
"author": "",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"babel-polyfill": "6.13.0",
|
|
25
|
+
"enzyme": "2.4.1",
|
|
26
|
+
"jasmine-enzyme": "1.2.0",
|
|
27
|
+
"karma-babel-preprocessor": "6.0.1",
|
|
28
|
+
"mappersmith": "0.13.3",
|
|
29
|
+
"material-ui": "0.15.4",
|
|
30
|
+
"moment": "2.15.1",
|
|
31
|
+
"react": "15.3.2",
|
|
32
|
+
"react-addons-test-utils": "15.3.2",
|
|
33
|
+
"react-dom": "15.3.2",
|
|
34
|
+
"react-json-pretty": "1.2.1",
|
|
35
|
+
"react-redux": "4.4.5",
|
|
36
|
+
"react-router": "2.8.1",
|
|
37
|
+
"react-router-redux": "4.0.6",
|
|
38
|
+
"react-tap-event-plugin": "1.0.0",
|
|
39
|
+
"redux": "3.6.0",
|
|
40
|
+
"redux-mock-store": "1.2.1",
|
|
41
|
+
"redux-thunk": "2.1.0",
|
|
42
|
+
"sagui": "6.6.1",
|
|
43
|
+
"webpack-inject-css-loader": "0.1.0"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sagui configuration object
|
|
3
|
+
* see: http://sagui.js.org/
|
|
4
|
+
*/
|
|
5
|
+
const { join } = require('path')
|
|
6
|
+
const env = process.env.NODE_ENV
|
|
7
|
+
const output = (env === 'production')
|
|
8
|
+
? { publicPath: '/assets/', path: join(__dirname, '../assets') }
|
|
9
|
+
: { publicPath: '/' }
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
pages: ['index'],
|
|
13
|
+
|
|
14
|
+
style: {
|
|
15
|
+
cssModules: false
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
webpack: {
|
|
19
|
+
output: output,
|
|
20
|
+
module: {
|
|
21
|
+
preLoaders: [
|
|
22
|
+
{
|
|
23
|
+
test: /src\/index\.scss/, // the main scss/css file
|
|
24
|
+
loader: 'webpack-inject-css-loader?appPath=./src&debug=false'
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
externals: {
|
|
29
|
+
'cheerio': 'window',
|
|
30
|
+
'react/addons': true,
|
|
31
|
+
'react/lib/ExecutionEnvironment': true,
|
|
32
|
+
'react/lib/ReactContext': true
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
develop: {
|
|
37
|
+
proxy: {
|
|
38
|
+
'/api/v1/*': {
|
|
39
|
+
target: 'http://localhost:9292',
|
|
40
|
+
secure: false
|
|
41
|
+
},
|
|
42
|
+
'/configs': {
|
|
43
|
+
target: 'http://localhost:9292',
|
|
44
|
+
secure: false
|
|
45
|
+
},
|
|
46
|
+
'/assets/*': {
|
|
47
|
+
target: 'http://localhost:9292',
|
|
48
|
+
secure: false
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import API, { parseResponseError } from 'api'
|
|
2
|
+
import { addFlashMessage } from 'actions/flash-messages'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
REQUEST_EVENT_DETAILS,
|
|
6
|
+
RECEIVE_EVENT_DETAILS,
|
|
7
|
+
REQUEST_EVENT_DETAILS_FAILED
|
|
8
|
+
} from 'actions'
|
|
9
|
+
|
|
10
|
+
const requestEventDetails = (event) => ({
|
|
11
|
+
type: REQUEST_EVENT_DETAILS,
|
|
12
|
+
event: event
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const receiveEventDetails = (data) => ({
|
|
16
|
+
type: RECEIVE_EVENT_DETAILS,
|
|
17
|
+
event: data
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const requestEventDetailsFailed = (event, error) => ({
|
|
21
|
+
type: REQUEST_EVENT_DETAILS_FAILED,
|
|
22
|
+
event: event,
|
|
23
|
+
error
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
export const fetchEventDetails = (event) => (dispatch, getState) => {
|
|
27
|
+
dispatch(requestEventDetails(event))
|
|
28
|
+
|
|
29
|
+
return API.Event
|
|
30
|
+
.findById({ id: event.id })
|
|
31
|
+
.then((response) => dispatch(receiveEventDetails(response.data)))
|
|
32
|
+
.catch((response) => {
|
|
33
|
+
const error = parseResponseError(response)
|
|
34
|
+
return Promise
|
|
35
|
+
.resolve()
|
|
36
|
+
.then(() => dispatch(requestEventDetailsFailed(event, error.message)))
|
|
37
|
+
.then(() => dispatch(addFlashMessage({
|
|
38
|
+
type: 'error',
|
|
39
|
+
text: error.message
|
|
40
|
+
})))
|
|
41
|
+
})
|
|
42
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import 'babel-polyfill'
|
|
2
|
+
import Mappersmith from 'mappersmith'
|
|
3
|
+
import 'mappersmith/fixtures'
|
|
4
|
+
import configureMockStore from 'redux-mock-store'
|
|
5
|
+
import thunk from 'redux-thunk'
|
|
6
|
+
|
|
7
|
+
const middlewares = [ thunk ]
|
|
8
|
+
const mockStore = configureMockStore(middlewares)
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
REQUEST_EVENT_DETAILS,
|
|
12
|
+
RECEIVE_EVENT_DETAILS,
|
|
13
|
+
REQUEST_EVENT_DETAILS_FAILED
|
|
14
|
+
} from 'actions'
|
|
15
|
+
|
|
16
|
+
import { fetchEventDetails } from 'actions/event-details'
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
Mappersmith.Env.Fixture.clear()
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
describe('actions/event-details', () => {
|
|
23
|
+
describe('#fetchEventDetails', () => {
|
|
24
|
+
describe('when it succeeds', () => {
|
|
25
|
+
let event, store
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
event = { id: 1 }
|
|
28
|
+
store = mockStore({})
|
|
29
|
+
Mappersmith.Env.Fixture
|
|
30
|
+
.define('get')
|
|
31
|
+
.matching({ url: `/api/v1/events/${event.id}` })
|
|
32
|
+
.response(event)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('creates REQUEST and RECEIVE actions', (done) => {
|
|
36
|
+
store.dispatch(fetchEventDetails(event)).then(() => {
|
|
37
|
+
const actions = store.getActions()
|
|
38
|
+
expect(actions[0]).toEqual({ type: REQUEST_EVENT_DETAILS, event })
|
|
39
|
+
expect(actions[1]).toEqual({ type: RECEIVE_EVENT_DETAILS, event })
|
|
40
|
+
done()
|
|
41
|
+
})
|
|
42
|
+
.catch((e) => done.fail(`test failed with promise error: ${e.message}`))
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
describe('when it fails', () => {
|
|
47
|
+
it('creates REQUEST and REQUEST_FAILED actions', (done) => {
|
|
48
|
+
const event = { id: 1 }
|
|
49
|
+
const store = mockStore({})
|
|
50
|
+
Mappersmith.Env.Fixture
|
|
51
|
+
.define('get')
|
|
52
|
+
.matching({ url: `/api/v1/events/${event.id}` })
|
|
53
|
+
.failure()
|
|
54
|
+
.response({
|
|
55
|
+
responseText: JSON.stringify({
|
|
56
|
+
error: true,
|
|
57
|
+
message: 'some error'
|
|
58
|
+
})
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
store.dispatch(fetchEventDetails(event)).then(() => {
|
|
62
|
+
const actions = store.getActions()
|
|
63
|
+
expect(actions[0]).toEqual({ type: REQUEST_EVENT_DETAILS, event })
|
|
64
|
+
expect(actions[1]).toEqual({ type: REQUEST_EVENT_DETAILS_FAILED, event, error: 'some error' })
|
|
65
|
+
done()
|
|
66
|
+
})
|
|
67
|
+
.catch((e) => done.fail(`test failed with promise error: ${e.message}`))
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
})
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EVENT_SHOW_OVERVIEW, EVENT_HIDE_OVERVIEW } from 'actions'
|
|
2
|
+
import { showEventOverview, hideEventOverview } from 'actions/event-overview'
|
|
3
|
+
|
|
4
|
+
describe('actions/event-overview', () => {
|
|
5
|
+
describe('#showEventOverview', () => {
|
|
6
|
+
it('creates an action to show event overview', () => {
|
|
7
|
+
const event = { id: 1 }
|
|
8
|
+
const expectedAction = { type: EVENT_SHOW_OVERVIEW, event: event }
|
|
9
|
+
expect(showEventOverview(event)).toEqual(expectedAction)
|
|
10
|
+
})
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
describe('#hideEventOverview', () => {
|
|
14
|
+
it('creates an action to hide event overview', () => {
|
|
15
|
+
const event = { id: 1 }
|
|
16
|
+
const expectedAction = { type: EVENT_HIDE_OVERVIEW, event: event }
|
|
17
|
+
expect(hideEventOverview(event)).toEqual(expectedAction)
|
|
18
|
+
})
|
|
19
|
+
})
|
|
20
|
+
})
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import API, { parseResponseError } from 'api'
|
|
2
|
+
import { addFlashMessage } from 'actions/flash-messages'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
EVENT_SHOW_RETRY,
|
|
6
|
+
EVENT_HIDE_RETRY,
|
|
7
|
+
REQUEST_EVENT_RETRY,
|
|
8
|
+
RECEIVE_EVENT_RETRY,
|
|
9
|
+
REQUEST_EVENT_RETRY_FAILED
|
|
10
|
+
} from 'actions'
|
|
11
|
+
|
|
12
|
+
export const showEventRetry = (event) => ({
|
|
13
|
+
type: EVENT_SHOW_RETRY,
|
|
14
|
+
event
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
export const hideEventRetry = (event) => ({
|
|
18
|
+
type: EVENT_HIDE_RETRY,
|
|
19
|
+
event
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const requestEventRetry = (event) => ({
|
|
23
|
+
type: REQUEST_EVENT_RETRY,
|
|
24
|
+
event: event
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const receiveEventRetry = (event, data) => ({
|
|
28
|
+
type: RECEIVE_EVENT_RETRY,
|
|
29
|
+
event: event,
|
|
30
|
+
acknowledged: data.acknowledged
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
const requestEventRetryFailed = (event, error) => ({
|
|
34
|
+
type: REQUEST_EVENT_RETRY_FAILED,
|
|
35
|
+
event: event,
|
|
36
|
+
error
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
export const performEventRetry = (event) => (dispatch, getState) => {
|
|
40
|
+
dispatch(requestEventRetry(event))
|
|
41
|
+
return API.Event
|
|
42
|
+
.retry({id: event.id})
|
|
43
|
+
.then((response) => {
|
|
44
|
+
return Promise
|
|
45
|
+
.resolve()
|
|
46
|
+
.then(() => dispatch(receiveEventRetry(event, response.data)))
|
|
47
|
+
.then(() => dispatch(hideEventRetry(event)))
|
|
48
|
+
.then(() => dispatch(addFlashMessage({
|
|
49
|
+
type: 'success',
|
|
50
|
+
text: `Event retried with success. Acknowledged: ${response.data.acknowledged}`,
|
|
51
|
+
autoClose: true
|
|
52
|
+
})))
|
|
53
|
+
})
|
|
54
|
+
.catch((response) => {
|
|
55
|
+
const error = parseResponseError(response)
|
|
56
|
+
dispatch(requestEventRetryFailed(event, error.message))
|
|
57
|
+
})
|
|
58
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import 'babel-polyfill'
|
|
2
|
+
import Mappersmith from 'mappersmith'
|
|
3
|
+
import 'mappersmith/fixtures'
|
|
4
|
+
import configureMockStore from 'redux-mock-store'
|
|
5
|
+
import thunk from 'redux-thunk'
|
|
6
|
+
|
|
7
|
+
const middlewares = [ thunk ]
|
|
8
|
+
const mockStore = configureMockStore(middlewares)
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
EVENT_SHOW_RETRY,
|
|
12
|
+
EVENT_HIDE_RETRY,
|
|
13
|
+
REQUEST_EVENT_RETRY,
|
|
14
|
+
RECEIVE_EVENT_RETRY,
|
|
15
|
+
ADD_FLASH_MESSAGE,
|
|
16
|
+
REQUEST_EVENT_RETRY_FAILED
|
|
17
|
+
} from 'actions'
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
showEventRetry,
|
|
21
|
+
hideEventRetry,
|
|
22
|
+
performEventRetry
|
|
23
|
+
} from 'actions/event-retry'
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
Mappersmith.Env.Fixture.clear()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
describe('actions/event-retry', () => {
|
|
30
|
+
describe('#showEventRetry', () => {
|
|
31
|
+
it('creates an action to show event retry', () => {
|
|
32
|
+
const event = { id: 1 }
|
|
33
|
+
const expectedAction = { type: EVENT_SHOW_RETRY, event }
|
|
34
|
+
expect(showEventRetry(event)).toEqual(expectedAction)
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
describe('#hideEventRetry', () => {
|
|
39
|
+
it('creates an action to hide event retry', () => {
|
|
40
|
+
const event = { id: 1 }
|
|
41
|
+
const expectedAction = { type: EVENT_HIDE_RETRY, event }
|
|
42
|
+
expect(hideEventRetry(event)).toEqual(expectedAction)
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
describe('#performEventRetry', () => {
|
|
47
|
+
describe('when it succeeds', () => {
|
|
48
|
+
let event, store
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
event = { id: 1 }
|
|
51
|
+
store = mockStore({})
|
|
52
|
+
Mappersmith.Env.Fixture
|
|
53
|
+
.define('post')
|
|
54
|
+
.matching({ url: `/api/v1/events/${event.id}/retry` })
|
|
55
|
+
.response({ acknowledged: true })
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('creates REQUEST and RECEIVE actions', (done) => {
|
|
59
|
+
store.dispatch(performEventRetry(event)).then(() => {
|
|
60
|
+
const actions = store.getActions()
|
|
61
|
+
expect(actions[0]).toEqual({ type: REQUEST_EVENT_RETRY, event })
|
|
62
|
+
expect(actions[1]).toEqual({ type: RECEIVE_EVENT_RETRY, event, acknowledged: true })
|
|
63
|
+
done()
|
|
64
|
+
})
|
|
65
|
+
.catch((e) => done.fail(`test failed with promise error: ${e.message}`))
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('creates an action to hide the event retry', (done) => {
|
|
69
|
+
store.dispatch(performEventRetry(event)).then(() => {
|
|
70
|
+
const actions = store.getActions()
|
|
71
|
+
expect(actions[2]).toEqual({ type: EVENT_HIDE_RETRY, event })
|
|
72
|
+
done()
|
|
73
|
+
})
|
|
74
|
+
.catch((e) => done.fail(`test failed with promise error: ${e.message}`))
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('create an action to add a success flash message', (done) => {
|
|
78
|
+
store.dispatch(performEventRetry(event)).then(() => {
|
|
79
|
+
const actions = store.getActions()
|
|
80
|
+
expect(actions[3]).toEqual({ type: ADD_FLASH_MESSAGE, message: {
|
|
81
|
+
id: jasmine.any(String),
|
|
82
|
+
type: 'success',
|
|
83
|
+
text: 'Event retried with success. Acknowledged: true',
|
|
84
|
+
autoClose: true
|
|
85
|
+
}})
|
|
86
|
+
done()
|
|
87
|
+
})
|
|
88
|
+
.catch((e) => done.fail(`test failed with promise error: ${e.message}`))
|
|
89
|
+
})
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
describe('when it fails', () => {
|
|
93
|
+
it('creates REQUEST and REQUEST_FAILED actions', (done) => {
|
|
94
|
+
const event = { id: 1 }
|
|
95
|
+
const store = mockStore({})
|
|
96
|
+
Mappersmith.Env.Fixture
|
|
97
|
+
.define('post')
|
|
98
|
+
.matching({ url: `/api/v1/events/${event.id}/retry` })
|
|
99
|
+
.failure()
|
|
100
|
+
.response({
|
|
101
|
+
responseText: JSON.stringify({
|
|
102
|
+
error: true,
|
|
103
|
+
message: 'some error'
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
store.dispatch(performEventRetry(event)).then(() => {
|
|
108
|
+
const actions = store.getActions()
|
|
109
|
+
expect(actions[0]).toEqual({ type: REQUEST_EVENT_RETRY, event })
|
|
110
|
+
expect(actions[1]).toEqual({ type: REQUEST_EVENT_RETRY_FAILED, event, error: 'some error' })
|
|
111
|
+
done()
|
|
112
|
+
})
|
|
113
|
+
.catch((e) => done.fail(`test failed with promise error: ${e.message}`))
|
|
114
|
+
})
|
|
115
|
+
})
|
|
116
|
+
})
|
|
117
|
+
})
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import API, { EVENTS_SEARCH_LIMIT, parseResponseError } from 'api'
|
|
2
|
+
import { addFlashMessage } from 'actions/flash-messages'
|
|
3
|
+
import { history } from 'routes'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
TRIGGER_SEARCH,
|
|
7
|
+
REQUEST_SEARCH_RESULTS,
|
|
8
|
+
RECEIVE_SEARCH_RESULTS,
|
|
9
|
+
REQUEST_SEARCH_RESULTS_FAILED,
|
|
10
|
+
LOAD_MORE_SEARCH_RESULTS
|
|
11
|
+
} from 'actions'
|
|
12
|
+
|
|
13
|
+
export const triggerSearch = () => (dispatch, getState) => {
|
|
14
|
+
const filters = getState().eventsFilters
|
|
15
|
+
return Promise
|
|
16
|
+
.resolve()
|
|
17
|
+
.then(() => history.push({ query: filters.value ? filters : {} }))
|
|
18
|
+
.then(() => dispatch({ type: TRIGGER_SEARCH }))
|
|
19
|
+
.then(() => dispatch(fetchSearchResults()))
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const requestSearchResults = () => ({
|
|
23
|
+
type: REQUEST_SEARCH_RESULTS
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const receiveSearchResults = (data, offset) => ({
|
|
27
|
+
type: RECEIVE_SEARCH_RESULTS,
|
|
28
|
+
events: data,
|
|
29
|
+
offset
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const requestSearchResultsFailed = (query, error) => ({
|
|
33
|
+
type: REQUEST_SEARCH_RESULTS_FAILED,
|
|
34
|
+
query,
|
|
35
|
+
error
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
export const fetchSearchResults = () => (dispatch, getState) => {
|
|
39
|
+
dispatch(requestSearchResults())
|
|
40
|
+
|
|
41
|
+
const filter = getState().eventsFilters
|
|
42
|
+
const currentOffset = getState().xhrStatus.currentEventsOffset
|
|
43
|
+
const query = filter.value
|
|
44
|
+
? {[filter.type]: filter.value}
|
|
45
|
+
: {}
|
|
46
|
+
|
|
47
|
+
Object.assign(query, { offset: currentOffset })
|
|
48
|
+
|
|
49
|
+
return API.Event
|
|
50
|
+
.search(query)
|
|
51
|
+
.then((response) => {
|
|
52
|
+
dispatch(receiveSearchResults(response.data, currentOffset))
|
|
53
|
+
})
|
|
54
|
+
.catch((response) => {
|
|
55
|
+
const error = parseResponseError(response)
|
|
56
|
+
return Promise
|
|
57
|
+
.resolve()
|
|
58
|
+
.then(() => dispatch(requestSearchResultsFailed(query, error.message)))
|
|
59
|
+
.then(() => dispatch(addFlashMessage({
|
|
60
|
+
type: 'error',
|
|
61
|
+
text: `Events search failed. "${error.message}"`
|
|
62
|
+
})))
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const loadMoreSearchResults = () => (dispatch, getState) => {
|
|
67
|
+
const currentOffset = getState().xhrStatus.currentEventsOffset
|
|
68
|
+
return Promise
|
|
69
|
+
.resolve()
|
|
70
|
+
.then(() => dispatch({
|
|
71
|
+
type: LOAD_MORE_SEARCH_RESULTS,
|
|
72
|
+
offset: currentOffset + EVENTS_SEARCH_LIMIT
|
|
73
|
+
}))
|
|
74
|
+
.then(() => dispatch(fetchSearchResults()))
|
|
75
|
+
}
|