phobos_checkpoint_ui 0.4.0 → 1.0.0.rc1
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 +4 -4
- data/CHANGELOG.md +5 -1
- data/frontend/.gitignore +4 -0
- data/frontend/src/actions/events-search.js +11 -11
- data/frontend/src/actions/events-search.spec.js +21 -21
- data/frontend/src/actions/failures/details.js +42 -0
- data/frontend/src/actions/failures/details.spec.js +71 -0
- data/frontend/src/actions/failures/overview.js +14 -0
- data/frontend/src/actions/failures/overview.spec.js +20 -0
- data/frontend/src/actions/failures/retry.js +58 -0
- data/frontend/src/actions/failures/retry.spec.js +117 -0
- data/frontend/src/actions/failures/search/index.js +76 -0
- data/frontend/src/actions/failures/search/index.spec.js +197 -0
- data/frontend/src/actions/index.js +24 -5
- data/frontend/src/actions/navigation/index.js +5 -0
- data/frontend/src/actions/navigation/index.spec.js +21 -0
- data/frontend/src/api.js +11 -0
- data/frontend/src/components/{event-overview/attribute.js → attribute/index.js} +0 -0
- data/frontend/src/components/empty-event/index.js +20 -0
- data/frontend/src/components/empty-event/index.spec.js +38 -0
- data/frontend/src/components/event-overview/index.js +1 -1
- data/frontend/src/components/event-retry-dialog/index.js +1 -1
- data/frontend/src/components/failure/error-message.js +19 -0
- data/frontend/src/components/failure/error-message.scss +8 -0
- data/frontend/src/components/failure/event.scss +3 -0
- data/frontend/src/components/failure/index.js +82 -0
- data/frontend/src/components/failure/index.spec.js +89 -0
- data/frontend/src/components/failure/loading.js +16 -0
- data/frontend/src/components/failure/overview/failure-overview.scss +28 -0
- data/frontend/src/components/failure/overview/index.js +60 -0
- data/frontend/src/components/failure/overview/index.spec.js +71 -0
- data/frontend/src/components/failure/overview-dialog/event-overview-dialog.scss +15 -0
- data/frontend/src/components/failure/overview-dialog/index.js +90 -0
- data/frontend/src/components/failure/retry-dialog/index.js +72 -0
- data/frontend/src/components/failure/style.js +16 -0
- data/frontend/src/components/failures-list/failures-list.scss +49 -0
- data/frontend/src/components/failures-list/index.js +62 -0
- data/frontend/src/components/failures-list/index.spec.js +59 -0
- data/frontend/src/components/header/index.js +36 -2
- data/frontend/src/components/load-more/index.js +22 -0
- data/frontend/src/components/load-more/index.spec.js +54 -0
- data/frontend/src/components/search-input/index.js +2 -5
- data/frontend/src/components/search-input/index.spec.js +6 -6
- data/frontend/src/reducers/events.js +2 -2
- data/frontend/src/reducers/events.spec.js +4 -4
- data/frontend/src/reducers/failures/details/index.js +32 -0
- data/frontend/src/reducers/failures/details/index.spec.js +54 -0
- data/frontend/src/reducers/failures/index.js +48 -0
- data/frontend/src/reducers/failures/index.spec.js +95 -0
- data/frontend/src/reducers/index.js +4 -1
- data/frontend/src/reducers/index.spec.js +2 -0
- data/frontend/src/reducers/xhr-status.js +25 -10
- data/frontend/src/reducers/xhr-status.spec.js +65 -15
- data/frontend/src/routes.js +6 -2
- data/frontend/src/store.js +7 -3
- data/frontend/src/views/{event-details.js → events/details/index.js} +0 -0
- data/frontend/src/views/{events-search.js → events/search/index.js} +37 -44
- data/frontend/src/views/{events-search.scss → events/search/index.scss} +0 -0
- data/frontend/src/views/{events-search.spec.js → events/search/index.spec.js} +35 -25
- data/frontend/src/views/failures/details/index.js +50 -0
- data/frontend/src/views/failures/search/index.js +113 -0
- data/frontend/src/views/failures/search/index.scss +24 -0
- data/frontend/src/views/failures/search/index.spec.js +106 -0
- data/lib/phobos_checkpoint_ui/version.rb +1 -1
- data/phobos_checkpoint_ui.gemspec +1 -1
- metadata +53 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c06ac3b49f17bb1a0cfd0b99c381cbf472ea99c2
|
4
|
+
data.tar.gz: 6a20e89e24e36288a4448c6e05d560613c7440b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c9ff42eee60f0ec01a4ce14b24f3f9903444a91a41a6bd140aae7eef2d427817275f2300ed768fa8b08bc2c5a04a4a9270681697d4116c991a3f86b04f1085a
|
7
|
+
data.tar.gz: 11524361e949b14a83a0404c6161581d08b0342b8628ea162e4a7432c660f32337077cb0c56e4e6e670c9b2aed9592bb7246bf4348c36aa7228a3b5c2e73a55f
|
data/CHANGELOG.md
CHANGED
@@ -4,13 +4,17 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
5
5
|
and this project adheres to [Semantic Versioning](http://semver.org/).
|
6
6
|
|
7
|
+
## 1.0.0.rc1 (2017-03-01)
|
8
|
+
|
9
|
+
- [feature] Add GUI interacting with PhobosDBCheckpoint failures
|
10
|
+
|
7
11
|
## 0.4.0 (2017-01-28)
|
8
12
|
|
9
13
|
- [enhancement] Add /ping endpoint
|
10
14
|
|
11
15
|
## 0.3.0 (2017-01-28)
|
12
16
|
|
13
|
-
- [bugfix] Gem should require
|
17
|
+
- [bugfix] Gem should require PhobosDBCheckpoint
|
14
18
|
|
15
19
|
## 0.2.0 (2016-10-10)
|
16
20
|
|
data/frontend/.gitignore
ADDED
@@ -3,34 +3,34 @@ import { addFlashMessage } from 'actions/flash-messages'
|
|
3
3
|
import { history } from 'routes'
|
4
4
|
|
5
5
|
import {
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
TRIGGER_EVENTS_SEARCH,
|
7
|
+
REQUEST_EVENTS_SEARCH_RESULTS,
|
8
|
+
RECEIVE_EVENTS_SEARCH_RESULTS,
|
9
|
+
REQUEST_EVENTS_SEARCH_RESULTS_FAILED,
|
10
|
+
LOAD_MORE_EVENTS_SEARCH_RESULTS
|
11
11
|
} from 'actions'
|
12
12
|
|
13
13
|
export const triggerSearch = () => (dispatch, getState) => {
|
14
14
|
const filters = getState().eventsFilters
|
15
15
|
return Promise
|
16
16
|
.resolve()
|
17
|
-
.then(() => history.push({ query: filters.value ? filters : {} }))
|
18
|
-
.then(() => dispatch({ type:
|
17
|
+
.then(() => history.push({ pathname: window.location.pathname, query: filters.value ? filters : {} }))
|
18
|
+
.then(() => dispatch({ type: TRIGGER_EVENTS_SEARCH }))
|
19
19
|
.then(() => dispatch(fetchSearchResults()))
|
20
20
|
}
|
21
21
|
|
22
22
|
const requestSearchResults = () => ({
|
23
|
-
type:
|
23
|
+
type: REQUEST_EVENTS_SEARCH_RESULTS
|
24
24
|
})
|
25
25
|
|
26
26
|
const receiveSearchResults = (data, offset) => ({
|
27
|
-
type:
|
27
|
+
type: RECEIVE_EVENTS_SEARCH_RESULTS,
|
28
28
|
events: data,
|
29
29
|
offset
|
30
30
|
})
|
31
31
|
|
32
32
|
const requestSearchResultsFailed = (query, error) => ({
|
33
|
-
type:
|
33
|
+
type: REQUEST_EVENTS_SEARCH_RESULTS_FAILED,
|
34
34
|
query,
|
35
35
|
error
|
36
36
|
})
|
@@ -68,7 +68,7 @@ export const loadMoreSearchResults = () => (dispatch, getState) => {
|
|
68
68
|
return Promise
|
69
69
|
.resolve()
|
70
70
|
.then(() => dispatch({
|
71
|
-
type:
|
71
|
+
type: LOAD_MORE_EVENTS_SEARCH_RESULTS,
|
72
72
|
offset: currentOffset + EVENTS_SEARCH_LIMIT
|
73
73
|
}))
|
74
74
|
.then(() => dispatch(fetchSearchResults()))
|
@@ -9,12 +9,12 @@ const middlewares = [ thunk ]
|
|
9
9
|
const mockStore = configureMockStore(middlewares)
|
10
10
|
|
11
11
|
import {
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
TRIGGER_EVENTS_SEARCH,
|
13
|
+
REQUEST_EVENTS_SEARCH_RESULTS,
|
14
|
+
RECEIVE_EVENTS_SEARCH_RESULTS,
|
15
|
+
REQUEST_EVENTS_SEARCH_RESULTS_FAILED,
|
16
16
|
ADD_FLASH_MESSAGE,
|
17
|
-
|
17
|
+
LOAD_MORE_EVENTS_SEARCH_RESULTS
|
18
18
|
} from 'actions'
|
19
19
|
|
20
20
|
import {
|
@@ -44,8 +44,8 @@ describe('actions/event-search', () => {
|
|
44
44
|
it('creates REQUEST and RECEIVE actions', (done) => {
|
45
45
|
store.dispatch(fetchSearchResults(event)).then(() => {
|
46
46
|
const actions = store.getActions()
|
47
|
-
expect(actions[0]).toEqual({ type:
|
48
|
-
expect(actions[1]).toEqual({ type:
|
47
|
+
expect(actions[0]).toEqual({ type: REQUEST_EVENTS_SEARCH_RESULTS })
|
48
|
+
expect(actions[1]).toEqual({ type: RECEIVE_EVENTS_SEARCH_RESULTS, events: [event], offset: 0 })
|
49
49
|
done()
|
50
50
|
})
|
51
51
|
.catch((e) => done.fail(`test failed with promise error: ${e.message}`))
|
@@ -70,8 +70,8 @@ describe('actions/event-search', () => {
|
|
70
70
|
it('creates REQUEST and RECEIVE actions using the filters', (done) => {
|
71
71
|
store.dispatch(fetchSearchResults(event)).then(() => {
|
72
72
|
const actions = store.getActions()
|
73
|
-
expect(actions[0]).toEqual({ type:
|
74
|
-
expect(actions[1]).toEqual({ type:
|
73
|
+
expect(actions[0]).toEqual({ type: REQUEST_EVENTS_SEARCH_RESULTS })
|
74
|
+
expect(actions[1]).toEqual({ type: RECEIVE_EVENTS_SEARCH_RESULTS, events: [event], offset: 0 })
|
75
75
|
done()
|
76
76
|
})
|
77
77
|
.catch((e) => done.fail(`test failed with promise error: ${e.message}`))
|
@@ -96,8 +96,8 @@ describe('actions/event-search', () => {
|
|
96
96
|
it('creates REQUEST and RECEIVE actions pointing to the correct offset', (done) => {
|
97
97
|
store.dispatch(fetchSearchResults(event)).then(() => {
|
98
98
|
const actions = store.getActions()
|
99
|
-
expect(actions[0]).toEqual({ type:
|
100
|
-
expect(actions[1]).toEqual({ type:
|
99
|
+
expect(actions[0]).toEqual({ type: REQUEST_EVENTS_SEARCH_RESULTS })
|
100
|
+
expect(actions[1]).toEqual({ type: RECEIVE_EVENTS_SEARCH_RESULTS, events: [event], offset: 4 })
|
101
101
|
done()
|
102
102
|
})
|
103
103
|
.catch((e) => done.fail(`test failed with promise error: ${e.message}`))
|
@@ -125,9 +125,9 @@ describe('actions/event-search', () => {
|
|
125
125
|
it('creates REQUEST and RECEIVE actions pointing to the correct offset', (done) => {
|
126
126
|
store.dispatch(fetchSearchResults(event)).then(() => {
|
127
127
|
const actions = store.getActions()
|
128
|
-
expect(actions[0]).toEqual({ type:
|
128
|
+
expect(actions[0]).toEqual({ type: REQUEST_EVENTS_SEARCH_RESULTS })
|
129
129
|
expect(actions[1]).toEqual({
|
130
|
-
type:
|
130
|
+
type: REQUEST_EVENTS_SEARCH_RESULTS_FAILED,
|
131
131
|
query: { offset: 0 }, error: 'some error'
|
132
132
|
})
|
133
133
|
expect(actions[2]).toEqual({
|
@@ -156,12 +156,12 @@ describe('actions/event-search', () => {
|
|
156
156
|
.response([event])
|
157
157
|
})
|
158
158
|
|
159
|
-
it('creates
|
159
|
+
it('creates TRIGGER_EVENTS_SEARCH and REQUEST actions', (done) => {
|
160
160
|
store.dispatch(triggerSearch()).then(() => {
|
161
161
|
const actions = store.getActions()
|
162
|
-
expect(actions[0]).toEqual({ type:
|
163
|
-
expect(actions[1]).toEqual({ type:
|
164
|
-
expect(actions[2]).toEqual({ type:
|
162
|
+
expect(actions[0]).toEqual({ type: TRIGGER_EVENTS_SEARCH })
|
163
|
+
expect(actions[1]).toEqual({ type: REQUEST_EVENTS_SEARCH_RESULTS })
|
164
|
+
expect(actions[2]).toEqual({ type: RECEIVE_EVENTS_SEARCH_RESULTS, events: [event], offset: 0 })
|
165
165
|
done()
|
166
166
|
})
|
167
167
|
.catch((e) => done.fail(`test failed with promise error: ${e.message}`))
|
@@ -183,12 +183,12 @@ describe('actions/event-search', () => {
|
|
183
183
|
.response([event])
|
184
184
|
})
|
185
185
|
|
186
|
-
it('creates
|
186
|
+
it('creates LOAD_MORE_EVENTS_SEARCH_RESULTS and REQUEST actions', (done) => {
|
187
187
|
store.dispatch(loadMoreSearchResults()).then(() => {
|
188
188
|
const actions = store.getActions()
|
189
|
-
expect(actions[0]).toEqual({ type:
|
190
|
-
expect(actions[1]).toEqual({ type:
|
191
|
-
expect(actions[2]).toEqual({ type:
|
189
|
+
expect(actions[0]).toEqual({ type: LOAD_MORE_EVENTS_SEARCH_RESULTS, offset: 4 + EVENTS_SEARCH_LIMIT })
|
190
|
+
expect(actions[1]).toEqual({ type: REQUEST_EVENTS_SEARCH_RESULTS })
|
191
|
+
expect(actions[2]).toEqual({ type: RECEIVE_EVENTS_SEARCH_RESULTS, events: [event], offset: 4 })
|
192
192
|
done()
|
193
193
|
})
|
194
194
|
.catch((e) => done.fail(`test failed with promise error: ${e.message}`))
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import API, { parseResponseError } from 'api'
|
2
|
+
import { addFlashMessage } from 'actions/flash-messages'
|
3
|
+
|
4
|
+
import {
|
5
|
+
REQUEST_FAILURE_DETAILS,
|
6
|
+
RECEIVE_FAILURE_DETAILS,
|
7
|
+
REQUEST_FAILURE_DETAILS_FAILED
|
8
|
+
} from 'actions'
|
9
|
+
|
10
|
+
const requestFailureDetails = (failure) => ({
|
11
|
+
type: REQUEST_FAILURE_DETAILS,
|
12
|
+
failure
|
13
|
+
})
|
14
|
+
|
15
|
+
const receiveFailureDetails = (failure) => ({
|
16
|
+
type: RECEIVE_FAILURE_DETAILS,
|
17
|
+
failure
|
18
|
+
})
|
19
|
+
|
20
|
+
const requestFailureDetailsFailed = (failure, error) => ({
|
21
|
+
type: REQUEST_FAILURE_DETAILS_FAILED,
|
22
|
+
failure,
|
23
|
+
error
|
24
|
+
})
|
25
|
+
|
26
|
+
export const fetchFailureDetails = (failure) => (dispatch, getState) => {
|
27
|
+
dispatch(requestFailureDetails(failure))
|
28
|
+
|
29
|
+
return API.Failure
|
30
|
+
.findById({ id: failure.id })
|
31
|
+
.then((response) => dispatch(receiveFailureDetails(response.data)))
|
32
|
+
.catch((response) => {
|
33
|
+
const error = parseResponseError(response)
|
34
|
+
return Promise
|
35
|
+
.resolve()
|
36
|
+
.then(() => dispatch(requestFailureDetailsFailed(failure, 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_FAILURE_DETAILS,
|
12
|
+
RECEIVE_FAILURE_DETAILS,
|
13
|
+
REQUEST_FAILURE_DETAILS_FAILED
|
14
|
+
} from 'actions'
|
15
|
+
|
16
|
+
import { fetchFailureDetails } from 'actions/failures/details'
|
17
|
+
|
18
|
+
beforeEach(() => {
|
19
|
+
Mappersmith.Env.Fixture.clear()
|
20
|
+
})
|
21
|
+
|
22
|
+
describe('actions/failure-details', () => {
|
23
|
+
describe('#fetchFailureDetails', () => {
|
24
|
+
describe('when it succeeds', () => {
|
25
|
+
let failure, store
|
26
|
+
beforeEach(() => {
|
27
|
+
failure = { id: 1 }
|
28
|
+
store = mockStore({})
|
29
|
+
Mappersmith.Env.Fixture
|
30
|
+
.define('get')
|
31
|
+
.matching({ url: `/api/v1/failures/${failure.id}` })
|
32
|
+
.response(failure)
|
33
|
+
})
|
34
|
+
|
35
|
+
it('creates REQUEST and RECEIVE actions', (done) => {
|
36
|
+
store.dispatch(fetchFailureDetails(failure)).then(() => {
|
37
|
+
const actions = store.getActions()
|
38
|
+
expect(actions[0]).toEqual({ type: REQUEST_FAILURE_DETAILS, failure })
|
39
|
+
expect(actions[1]).toEqual({ type: RECEIVE_FAILURE_DETAILS, failure })
|
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 failure = { id: 1 }
|
49
|
+
const store = mockStore({})
|
50
|
+
Mappersmith.Env.Fixture
|
51
|
+
.define('get')
|
52
|
+
.matching({ url: `/api/v1/failures/${failure.id}` })
|
53
|
+
.failure()
|
54
|
+
.response({
|
55
|
+
responseText: JSON.stringify({
|
56
|
+
error: true,
|
57
|
+
message: 'some error'
|
58
|
+
})
|
59
|
+
})
|
60
|
+
|
61
|
+
store.dispatch(fetchFailureDetails(failure)).then(() => {
|
62
|
+
const actions = store.getActions()
|
63
|
+
expect(actions[0]).toEqual({ type: REQUEST_FAILURE_DETAILS, failure })
|
64
|
+
expect(actions[1]).toEqual({ type: REQUEST_FAILURE_DETAILS_FAILED, failure, 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,14 @@
|
|
1
|
+
import {
|
2
|
+
FAILURE_SHOW_OVERVIEW,
|
3
|
+
FAILURE_HIDE_OVERVIEW
|
4
|
+
} from 'actions'
|
5
|
+
|
6
|
+
export const showFailureOverview = (failure) => ({
|
7
|
+
type: FAILURE_SHOW_OVERVIEW,
|
8
|
+
failure
|
9
|
+
})
|
10
|
+
|
11
|
+
export const hideFailureOverview = (failure) => ({
|
12
|
+
type: FAILURE_HIDE_OVERVIEW,
|
13
|
+
failure
|
14
|
+
})
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { FAILURE_SHOW_OVERVIEW, FAILURE_HIDE_OVERVIEW } from 'actions'
|
2
|
+
import { showFailureOverview, hideFailureOverview } from 'actions/failures/overview'
|
3
|
+
|
4
|
+
describe('actions/failures/overview', () => {
|
5
|
+
describe('#showFailureOverview', () => {
|
6
|
+
it('creates an action to show failure overview', () => {
|
7
|
+
const failure = { id: 1 }
|
8
|
+
const expectedAction = { type: FAILURE_SHOW_OVERVIEW, failure: failure }
|
9
|
+
expect(showFailureOverview(failure)).toEqual(expectedAction)
|
10
|
+
})
|
11
|
+
})
|
12
|
+
|
13
|
+
describe('#hideFailureOverview', () => {
|
14
|
+
it('creates an action to hide failure overview', () => {
|
15
|
+
const failure = { id: 1 }
|
16
|
+
const expectedAction = { type: FAILURE_HIDE_OVERVIEW, failure: failure }
|
17
|
+
expect(hideFailureOverview(failure)).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
|
+
FAILURE_SHOW_RETRY,
|
6
|
+
FAILURE_HIDE_RETRY,
|
7
|
+
REQUEST_FAILURE_RETRY,
|
8
|
+
RECEIVE_FAILURE_RETRY,
|
9
|
+
REQUEST_FAILURE_RETRY_FAILED
|
10
|
+
} from 'actions'
|
11
|
+
|
12
|
+
export const showFailureRetry = (failure) => ({
|
13
|
+
type: FAILURE_SHOW_RETRY,
|
14
|
+
failure
|
15
|
+
})
|
16
|
+
|
17
|
+
export const hideFailureRetry = (failure) => ({
|
18
|
+
type: FAILURE_HIDE_RETRY,
|
19
|
+
failure
|
20
|
+
})
|
21
|
+
|
22
|
+
const requestFailureRetry = (failure) => ({
|
23
|
+
type: REQUEST_FAILURE_RETRY,
|
24
|
+
failure: failure
|
25
|
+
})
|
26
|
+
|
27
|
+
const receiveFailureRetry = (failure, data) => ({
|
28
|
+
type: RECEIVE_FAILURE_RETRY,
|
29
|
+
failure: failure,
|
30
|
+
acknowledged: data.acknowledged
|
31
|
+
})
|
32
|
+
|
33
|
+
const requestFailureRetryFailed = (failure, error) => ({
|
34
|
+
type: REQUEST_FAILURE_RETRY_FAILED,
|
35
|
+
failure: failure,
|
36
|
+
error
|
37
|
+
})
|
38
|
+
|
39
|
+
export const performFailureRetry = (failure) => (dispatch, getState) => {
|
40
|
+
dispatch(requestFailureRetry(failure))
|
41
|
+
return API.Failure
|
42
|
+
.retry({id: failure.id})
|
43
|
+
.then((response) => {
|
44
|
+
return Promise
|
45
|
+
.resolve()
|
46
|
+
.then(() => dispatch(receiveFailureRetry(failure, response.data)))
|
47
|
+
.then(() => dispatch(hideFailureRetry(failure)))
|
48
|
+
.then(() => dispatch(addFlashMessage({
|
49
|
+
type: 'success',
|
50
|
+
text: `Failure retried with success. Acknowledged: ${response.data.acknowledged}`,
|
51
|
+
autoClose: true
|
52
|
+
})))
|
53
|
+
})
|
54
|
+
.catch((response) => {
|
55
|
+
const error = parseResponseError(response)
|
56
|
+
dispatch(requestFailureRetryFailed(failure, 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
|
+
FAILURE_SHOW_RETRY,
|
12
|
+
FAILURE_HIDE_RETRY,
|
13
|
+
REQUEST_FAILURE_RETRY,
|
14
|
+
RECEIVE_FAILURE_RETRY,
|
15
|
+
ADD_FLASH_MESSAGE,
|
16
|
+
REQUEST_FAILURE_RETRY_FAILED
|
17
|
+
} from 'actions'
|
18
|
+
|
19
|
+
import {
|
20
|
+
showFailureRetry,
|
21
|
+
hideFailureRetry,
|
22
|
+
performFailureRetry
|
23
|
+
} from 'actions/failures/retry'
|
24
|
+
|
25
|
+
beforeEach(() => {
|
26
|
+
Mappersmith.Env.Fixture.clear()
|
27
|
+
})
|
28
|
+
|
29
|
+
describe('actions/failures/retry', () => {
|
30
|
+
describe('#showFailureRetry', () => {
|
31
|
+
it('creates an action to show failure retry', () => {
|
32
|
+
const failure = { id: 1 }
|
33
|
+
const expectedAction = { type: FAILURE_SHOW_RETRY, failure }
|
34
|
+
expect(showFailureRetry(failure)).toEqual(expectedAction)
|
35
|
+
})
|
36
|
+
})
|
37
|
+
|
38
|
+
describe('#hideFailureRetry', () => {
|
39
|
+
it('creates an action to hide failure retry', () => {
|
40
|
+
const failure = { id: 1 }
|
41
|
+
const expectedAction = { type: FAILURE_HIDE_RETRY, failure }
|
42
|
+
expect(hideFailureRetry(failure)).toEqual(expectedAction)
|
43
|
+
})
|
44
|
+
})
|
45
|
+
|
46
|
+
describe('#performFailureRetry', () => {
|
47
|
+
describe('when it succeeds', () => {
|
48
|
+
let failure, store
|
49
|
+
beforeEach(() => {
|
50
|
+
failure = { id: 1 }
|
51
|
+
store = mockStore({})
|
52
|
+
Mappersmith.Env.Fixture
|
53
|
+
.define('post')
|
54
|
+
.matching({ url: `/api/v1/failures/${failure.id}/retry` })
|
55
|
+
.response({ acknowledged: true })
|
56
|
+
})
|
57
|
+
|
58
|
+
it('creates REQUEST and RECEIVE actions', (done) => {
|
59
|
+
store.dispatch(performFailureRetry(failure)).then(() => {
|
60
|
+
const actions = store.getActions()
|
61
|
+
expect(actions[0]).toEqual({ type: REQUEST_FAILURE_RETRY, failure })
|
62
|
+
expect(actions[1]).toEqual({ type: RECEIVE_FAILURE_RETRY, failure, 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 failure retry', (done) => {
|
69
|
+
store.dispatch(performFailureRetry(failure)).then(() => {
|
70
|
+
const actions = store.getActions()
|
71
|
+
expect(actions[2]).toEqual({ type: FAILURE_HIDE_RETRY, failure })
|
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(performFailureRetry(failure)).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: 'Failure 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 failure = { id: 1 }
|
95
|
+
const store = mockStore({})
|
96
|
+
Mappersmith.Env.Fixture
|
97
|
+
.define('post')
|
98
|
+
.matching({ url: `/api/v1/failures/${failure.id}/retry` })
|
99
|
+
.failure()
|
100
|
+
.response({
|
101
|
+
responseText: JSON.stringify({
|
102
|
+
error: true,
|
103
|
+
message: 'some error'
|
104
|
+
})
|
105
|
+
})
|
106
|
+
|
107
|
+
store.dispatch(performFailureRetry(failure)).then(() => {
|
108
|
+
const actions = store.getActions()
|
109
|
+
expect(actions[0]).toEqual({ type: REQUEST_FAILURE_RETRY, failure })
|
110
|
+
expect(actions[1]).toEqual({ type: REQUEST_FAILURE_RETRY_FAILED, failure, 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,76 @@
|
|
1
|
+
|
2
|
+
import API, { EVENTS_SEARCH_LIMIT, parseResponseError } from 'api'
|
3
|
+
import { addFlashMessage } from 'actions/flash-messages'
|
4
|
+
import { history } from 'routes'
|
5
|
+
|
6
|
+
import {
|
7
|
+
TRIGGER_FAILURES_SEARCH,
|
8
|
+
REQUEST_FAILURES_SEARCH_RESULTS,
|
9
|
+
RECEIVE_FAILURES_SEARCH_RESULTS,
|
10
|
+
REQUEST_FAILURES_SEARCH_RESULTS_FAILED,
|
11
|
+
LOAD_MORE_FAILURES_SEARCH_RESULTS
|
12
|
+
} from 'actions'
|
13
|
+
|
14
|
+
export const triggerSearch = () => (dispatch, getState) => {
|
15
|
+
const filters = getState().eventsFilters
|
16
|
+
return Promise
|
17
|
+
.resolve()
|
18
|
+
.then(() => history.push({ pathname: window.location.pathname, query: filters.value ? filters : {} }))
|
19
|
+
.then(() => dispatch({ type: TRIGGER_FAILURES_SEARCH }))
|
20
|
+
.then(() => dispatch(fetchSearchResults()))
|
21
|
+
}
|
22
|
+
|
23
|
+
const requestSearchResults = () => ({
|
24
|
+
type: REQUEST_FAILURES_SEARCH_RESULTS
|
25
|
+
})
|
26
|
+
|
27
|
+
const receiveSearchResults = (data, offset) => ({
|
28
|
+
type: RECEIVE_FAILURES_SEARCH_RESULTS,
|
29
|
+
failures: data,
|
30
|
+
offset
|
31
|
+
})
|
32
|
+
|
33
|
+
const requestSearchResultsFailed = (query, error) => ({
|
34
|
+
type: REQUEST_FAILURES_SEARCH_RESULTS_FAILED,
|
35
|
+
query,
|
36
|
+
error
|
37
|
+
})
|
38
|
+
|
39
|
+
export const fetchSearchResults = () => (dispatch, getState) => {
|
40
|
+
dispatch(requestSearchResults())
|
41
|
+
|
42
|
+
const filter = getState().eventsFilters
|
43
|
+
const currentOffset = getState().xhrStatus.currentEventsOffset
|
44
|
+
const query = filter.value
|
45
|
+
? {[filter.type]: filter.value}
|
46
|
+
: {}
|
47
|
+
|
48
|
+
Object.assign(query, { offset: currentOffset })
|
49
|
+
|
50
|
+
return API.Failure
|
51
|
+
.search(query)
|
52
|
+
.then((response) => {
|
53
|
+
dispatch(receiveSearchResults(response.data, currentOffset))
|
54
|
+
})
|
55
|
+
.catch((response) => {
|
56
|
+
const error = parseResponseError(response)
|
57
|
+
return Promise
|
58
|
+
.resolve()
|
59
|
+
.then(() => dispatch(requestSearchResultsFailed(query, error.message)))
|
60
|
+
.then(() => dispatch(addFlashMessage({
|
61
|
+
type: 'error',
|
62
|
+
text: `Failures search failed. "${error.message}"`
|
63
|
+
})))
|
64
|
+
})
|
65
|
+
}
|
66
|
+
|
67
|
+
export const loadMoreSearchResults = () => (dispatch, getState) => {
|
68
|
+
const currentOffset = getState().xhrStatus.currentEventsOffset
|
69
|
+
return Promise
|
70
|
+
.resolve()
|
71
|
+
.then(() => dispatch({
|
72
|
+
type: LOAD_MORE_FAILURES_SEARCH_RESULTS,
|
73
|
+
offset: currentOffset + EVENTS_SEARCH_LIMIT
|
74
|
+
}))
|
75
|
+
.then(() => dispatch(fetchSearchResults()))
|
76
|
+
}
|