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.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -1
  3. data/frontend/.gitignore +4 -0
  4. data/frontend/src/actions/events-search.js +11 -11
  5. data/frontend/src/actions/events-search.spec.js +21 -21
  6. data/frontend/src/actions/failures/details.js +42 -0
  7. data/frontend/src/actions/failures/details.spec.js +71 -0
  8. data/frontend/src/actions/failures/overview.js +14 -0
  9. data/frontend/src/actions/failures/overview.spec.js +20 -0
  10. data/frontend/src/actions/failures/retry.js +58 -0
  11. data/frontend/src/actions/failures/retry.spec.js +117 -0
  12. data/frontend/src/actions/failures/search/index.js +76 -0
  13. data/frontend/src/actions/failures/search/index.spec.js +197 -0
  14. data/frontend/src/actions/index.js +24 -5
  15. data/frontend/src/actions/navigation/index.js +5 -0
  16. data/frontend/src/actions/navigation/index.spec.js +21 -0
  17. data/frontend/src/api.js +11 -0
  18. data/frontend/src/components/{event-overview/attribute.js → attribute/index.js} +0 -0
  19. data/frontend/src/components/empty-event/index.js +20 -0
  20. data/frontend/src/components/empty-event/index.spec.js +38 -0
  21. data/frontend/src/components/event-overview/index.js +1 -1
  22. data/frontend/src/components/event-retry-dialog/index.js +1 -1
  23. data/frontend/src/components/failure/error-message.js +19 -0
  24. data/frontend/src/components/failure/error-message.scss +8 -0
  25. data/frontend/src/components/failure/event.scss +3 -0
  26. data/frontend/src/components/failure/index.js +82 -0
  27. data/frontend/src/components/failure/index.spec.js +89 -0
  28. data/frontend/src/components/failure/loading.js +16 -0
  29. data/frontend/src/components/failure/overview/failure-overview.scss +28 -0
  30. data/frontend/src/components/failure/overview/index.js +60 -0
  31. data/frontend/src/components/failure/overview/index.spec.js +71 -0
  32. data/frontend/src/components/failure/overview-dialog/event-overview-dialog.scss +15 -0
  33. data/frontend/src/components/failure/overview-dialog/index.js +90 -0
  34. data/frontend/src/components/failure/retry-dialog/index.js +72 -0
  35. data/frontend/src/components/failure/style.js +16 -0
  36. data/frontend/src/components/failures-list/failures-list.scss +49 -0
  37. data/frontend/src/components/failures-list/index.js +62 -0
  38. data/frontend/src/components/failures-list/index.spec.js +59 -0
  39. data/frontend/src/components/header/index.js +36 -2
  40. data/frontend/src/components/load-more/index.js +22 -0
  41. data/frontend/src/components/load-more/index.spec.js +54 -0
  42. data/frontend/src/components/search-input/index.js +2 -5
  43. data/frontend/src/components/search-input/index.spec.js +6 -6
  44. data/frontend/src/reducers/events.js +2 -2
  45. data/frontend/src/reducers/events.spec.js +4 -4
  46. data/frontend/src/reducers/failures/details/index.js +32 -0
  47. data/frontend/src/reducers/failures/details/index.spec.js +54 -0
  48. data/frontend/src/reducers/failures/index.js +48 -0
  49. data/frontend/src/reducers/failures/index.spec.js +95 -0
  50. data/frontend/src/reducers/index.js +4 -1
  51. data/frontend/src/reducers/index.spec.js +2 -0
  52. data/frontend/src/reducers/xhr-status.js +25 -10
  53. data/frontend/src/reducers/xhr-status.spec.js +65 -15
  54. data/frontend/src/routes.js +6 -2
  55. data/frontend/src/store.js +7 -3
  56. data/frontend/src/views/{event-details.js → events/details/index.js} +0 -0
  57. data/frontend/src/views/{events-search.js → events/search/index.js} +37 -44
  58. data/frontend/src/views/{events-search.scss → events/search/index.scss} +0 -0
  59. data/frontend/src/views/{events-search.spec.js → events/search/index.spec.js} +35 -25
  60. data/frontend/src/views/failures/details/index.js +50 -0
  61. data/frontend/src/views/failures/search/index.js +113 -0
  62. data/frontend/src/views/failures/search/index.scss +24 -0
  63. data/frontend/src/views/failures/search/index.spec.js +106 -0
  64. data/lib/phobos_checkpoint_ui/version.rb +1 -1
  65. data/phobos_checkpoint_ui.gemspec +1 -1
  66. metadata +53 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 76b2e76b2861ed3abde048b5efeb27bc7bb134d8
4
- data.tar.gz: 2660845c932a00a035ffb4e53ac1e86c0ea45534
3
+ metadata.gz: c06ac3b49f17bb1a0cfd0b99c381cbf472ea99c2
4
+ data.tar.gz: 6a20e89e24e36288a4448c6e05d560613c7440b6
5
5
  SHA512:
6
- metadata.gz: f16f45cb5b6c95c99b56852fd7c99595c0ccc683b82af1d0ac7009c0bfa2b4d8787c7d010f9ca8c9f587c6e54f60dd2d629fcf1bf5e678af942aa48a81ef042d
7
- data.tar.gz: 0acd74e372d733671487de76a87dfd00d3245981348aeacf37f2417acfdb75075667b2002117d7bac37468060725da6bad34aa3c1bb541ea9c247c5b34550d0a
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 phobos db checkpoint and its events api
17
+ - [bugfix] Gem should require PhobosDBCheckpoint
14
18
 
15
19
  ## 0.2.0 (2016-10-10)
16
20
 
@@ -0,0 +1,4 @@
1
+ coverage
2
+ node_modules
3
+ npm-debug.log
4
+ dist
@@ -3,34 +3,34 @@ import { addFlashMessage } from 'actions/flash-messages'
3
3
  import { history } from 'routes'
4
4
 
5
5
  import {
6
- TRIGGER_SEARCH,
7
- REQUEST_SEARCH_RESULTS,
8
- RECEIVE_SEARCH_RESULTS,
9
- REQUEST_SEARCH_RESULTS_FAILED,
10
- LOAD_MORE_SEARCH_RESULTS
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: TRIGGER_SEARCH }))
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: REQUEST_SEARCH_RESULTS
23
+ type: REQUEST_EVENTS_SEARCH_RESULTS
24
24
  })
25
25
 
26
26
  const receiveSearchResults = (data, offset) => ({
27
- type: RECEIVE_SEARCH_RESULTS,
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: REQUEST_SEARCH_RESULTS_FAILED,
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: LOAD_MORE_SEARCH_RESULTS,
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
- TRIGGER_SEARCH,
13
- REQUEST_SEARCH_RESULTS,
14
- RECEIVE_SEARCH_RESULTS,
15
- REQUEST_SEARCH_RESULTS_FAILED,
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
- LOAD_MORE_SEARCH_RESULTS
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: REQUEST_SEARCH_RESULTS })
48
- expect(actions[1]).toEqual({ type: RECEIVE_SEARCH_RESULTS, events: [event], offset: 0 })
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: REQUEST_SEARCH_RESULTS })
74
- expect(actions[1]).toEqual({ type: RECEIVE_SEARCH_RESULTS, events: [event], offset: 0 })
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: REQUEST_SEARCH_RESULTS })
100
- expect(actions[1]).toEqual({ type: RECEIVE_SEARCH_RESULTS, events: [event], offset: 4 })
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: REQUEST_SEARCH_RESULTS })
128
+ expect(actions[0]).toEqual({ type: REQUEST_EVENTS_SEARCH_RESULTS })
129
129
  expect(actions[1]).toEqual({
130
- type: REQUEST_SEARCH_RESULTS_FAILED,
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 TRIGGER_SEARCH and REQUEST actions', (done) => {
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: TRIGGER_SEARCH })
163
- expect(actions[1]).toEqual({ type: REQUEST_SEARCH_RESULTS })
164
- expect(actions[2]).toEqual({ type: RECEIVE_SEARCH_RESULTS, events: [event], offset: 0 })
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 LOAD_MORE_SEARCH_RESULTS and REQUEST actions', (done) => {
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: LOAD_MORE_SEARCH_RESULTS, offset: 4 + EVENTS_SEARCH_LIMIT })
190
- expect(actions[1]).toEqual({ type: REQUEST_SEARCH_RESULTS })
191
- expect(actions[2]).toEqual({ type: RECEIVE_SEARCH_RESULTS, events: [event], offset: 4 })
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
+ }