phobos_checkpoint_ui 1.0.0.rc1 → 1.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -1
  3. data/frontend/src/actions/event-details.js +5 -7
  4. data/frontend/src/actions/event-retry.js +7 -9
  5. data/frontend/src/actions/events-search.js +5 -7
  6. data/frontend/src/actions/failures/details.js +5 -7
  7. data/frontend/src/actions/failures/details.spec.js +1 -1
  8. data/frontend/src/actions/failures/retry.js +34 -17
  9. data/frontend/src/actions/failures/retry.spec.js +52 -5
  10. data/frontend/src/actions/failures/search/index.js +5 -8
  11. data/frontend/src/actions/failures/search/index.spec.js +2 -2
  12. data/frontend/src/actions/index.js +3 -1
  13. data/frontend/src/components/empty-event/empty-event.scss +6 -0
  14. data/frontend/src/components/event/card-style.js +29 -0
  15. data/frontend/src/components/event/event.scss +12 -0
  16. data/frontend/src/components/event/index.js +12 -21
  17. data/frontend/src/components/event/index.spec.js +3 -2
  18. data/frontend/src/components/event-overview-dialog/index.js +1 -1
  19. data/frontend/src/components/event-retry-dialog/index.js +9 -1
  20. data/frontend/src/components/failure/empty/empty-failure.scss +6 -0
  21. data/frontend/src/components/failure/empty/index.js +20 -0
  22. data/frontend/src/components/failure/empty/index.spec.js +38 -0
  23. data/frontend/src/components/failure/index.js +11 -20
  24. data/frontend/src/components/failure/index.scss +15 -0
  25. data/frontend/src/components/failure/index.spec.js +19 -14
  26. data/frontend/src/components/{failures-list → failure/list}/failures-list.scss +1 -1
  27. data/frontend/src/components/{failures-list → failure/list}/index.spec.js +15 -11
  28. data/frontend/src/components/failure/overview-dialog/index.js +4 -4
  29. data/frontend/src/components/failure/retry-dialog/index.js +14 -9
  30. data/frontend/src/components/flash-message/flash-message.scss +0 -1
  31. data/frontend/src/components/header/header.scss +5 -0
  32. data/frontend/src/components/header/index.js +62 -22
  33. data/frontend/src/reducers/event-details.js +9 -8
  34. data/frontend/src/reducers/event-details.spec.js +12 -2
  35. data/frontend/src/reducers/failures/details/index.js +9 -8
  36. data/frontend/src/reducers/failures/details/index.spec.js +12 -2
  37. data/frontend/src/reducers/failures/index.js +6 -4
  38. data/frontend/src/reducers/failures/index.spec.js +5 -5
  39. data/frontend/src/reducers/xhr-status.js +4 -0
  40. data/frontend/src/reducers/xhr-status.spec.js +20 -0
  41. data/frontend/src/views/events/search/index.scss +0 -7
  42. data/frontend/src/views/failures/details/index.js +2 -2
  43. data/frontend/src/views/failures/search/index.js +5 -5
  44. data/frontend/src/views/failures/search/index.scss +1 -8
  45. data/frontend/src/views/failures/search/index.spec.js +4 -4
  46. data/frontend/src/views/layout.js +2 -2
  47. data/lib/phobos_checkpoint_ui/version.rb +1 -1
  48. metadata +12 -12
  49. data/frontend/src/components/event/style.js +0 -16
  50. data/frontend/src/components/failure/error-message.js +0 -19
  51. data/frontend/src/components/failure/error-message.scss +0 -8
  52. data/frontend/src/components/failure/event.scss +0 -3
  53. data/frontend/src/components/failure/loading.js +0 -16
  54. data/frontend/src/components/failure/style.js +0 -16
  55. /data/frontend/src/components/{failures-list → failure/list}/index.js +0 -0
  56. /data/frontend/src/components/failure/overview-dialog/{event-overview-dialog.scss → failure-overview-dialog.scss} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c06ac3b49f17bb1a0cfd0b99c381cbf472ea99c2
4
- data.tar.gz: 6a20e89e24e36288a4448c6e05d560613c7440b6
3
+ metadata.gz: eb5df88871389fe9876fae517e7ea256819fc778
4
+ data.tar.gz: 51534f08782de450550e91019322e2be8bf26681
5
5
  SHA512:
6
- metadata.gz: 9c9ff42eee60f0ec01a4ce14b24f3f9903444a91a41a6bd140aae7eef2d427817275f2300ed768fa8b08bc2c5a04a4a9270681697d4116c991a3f86b04f1085a
7
- data.tar.gz: 11524361e949b14a83a0404c6161581d08b0342b8628ea162e4a7432c660f32337077cb0c56e4e6e670c9b2aed9592bb7246bf4348c36aa7228a3b5c2e73a55f
6
+ metadata.gz: 5c9ffd04210a079c88c49096d0dd45fb8828b04c3d54a3203af1334c63c185aee87c8a73efeecffd4d288a1874c57a75132f461a6ee0dda8864c7e4a3ab2a97d
7
+ data.tar.gz: 9e1865a07414149eeaaf201b2b3def89a217669ba8469f9d749db4cbb1d648e73c18badabfa5a420b19c6d019ff2af3387cf17129bdee6046a4594066d42f901
data/CHANGELOG.md CHANGED
@@ -4,7 +4,7 @@ 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)
7
+ ## 1.0.0.rc2 (2017-03-01)
8
8
 
9
9
  - [feature] Add GUI interacting with PhobosDBCheckpoint failures
10
10
 
@@ -31,12 +31,10 @@ export const fetchEventDetails = (event) => (dispatch, getState) => {
31
31
  .then((response) => dispatch(receiveEventDetails(response.data)))
32
32
  .catch((response) => {
33
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
- })))
34
+ dispatch(requestEventDetailsFailed(event, error.message))
35
+ dispatch(addFlashMessage({
36
+ type: 'error',
37
+ text: error.message
38
+ }))
41
39
  })
42
40
  }
@@ -41,15 +41,13 @@ export const performEventRetry = (event) => (dispatch, getState) => {
41
41
  return API.Event
42
42
  .retry({id: event.id})
43
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
- })))
44
+ dispatch(receiveEventRetry(event, response.data))
45
+ dispatch(hideEventRetry(event))
46
+ dispatch(addFlashMessage({
47
+ type: 'success',
48
+ text: `Event retried with success. Acknowledged: ${response.data.acknowledged}`,
49
+ autoClose: true
50
+ }))
53
51
  })
54
52
  .catch((response) => {
55
53
  const error = parseResponseError(response)
@@ -53,13 +53,11 @@ export const fetchSearchResults = () => (dispatch, getState) => {
53
53
  })
54
54
  .catch((response) => {
55
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
- })))
56
+ dispatch(requestSearchResultsFailed(query, error.message))
57
+ dispatch(addFlashMessage({
58
+ type: 'error',
59
+ text: `Events search failed. "${error.message}"`
60
+ }))
63
61
  })
64
62
  }
65
63
 
@@ -31,12 +31,10 @@ export const fetchFailureDetails = (failure) => (dispatch, getState) => {
31
31
  .then((response) => dispatch(receiveFailureDetails(response.data)))
32
32
  .catch((response) => {
33
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
- })))
34
+ dispatch(requestFailureDetailsFailed(failure, error.message))
35
+ dispatch(addFlashMessage({
36
+ type: 'error',
37
+ text: error.message
38
+ }))
41
39
  })
42
40
  }
@@ -19,7 +19,7 @@ beforeEach(() => {
19
19
  Mappersmith.Env.Fixture.clear()
20
20
  })
21
21
 
22
- describe('actions/failure-details', () => {
22
+ describe('actions/failures/details', () => {
23
23
  describe('#fetchFailureDetails', () => {
24
24
  describe('when it succeeds', () => {
25
25
  let failure, store
@@ -6,7 +6,9 @@ import {
6
6
  FAILURE_HIDE_RETRY,
7
7
  REQUEST_FAILURE_RETRY,
8
8
  RECEIVE_FAILURE_RETRY,
9
- REQUEST_FAILURE_RETRY_FAILED
9
+ REQUEST_FAILURE_RETRY_FAILED,
10
+ FAILURE_HIDE_OVERVIEW,
11
+ DELETE_FAILURE
10
12
  } from 'actions'
11
13
 
12
14
  export const showFailureRetry = (failure) => ({
@@ -21,19 +23,28 @@ export const hideFailureRetry = (failure) => ({
21
23
 
22
24
  const requestFailureRetry = (failure) => ({
23
25
  type: REQUEST_FAILURE_RETRY,
24
- failure: failure
26
+ failure
25
27
  })
26
28
 
27
29
  const receiveFailureRetry = (failure, data) => ({
28
30
  type: RECEIVE_FAILURE_RETRY,
29
- failure: failure,
30
- acknowledged: data.acknowledged
31
+ acknowledged: data.acknowledged,
32
+ failure
33
+ })
34
+
35
+ const hideFailureOverview = (failure) => ({
36
+ type: FAILURE_HIDE_OVERVIEW,
37
+ failure
31
38
  })
32
39
 
33
- const requestFailureRetryFailed = (failure, error) => ({
40
+ const deleteFailure = (failure) => ({
41
+ type: DELETE_FAILURE,
42
+ failure
43
+ })
44
+
45
+ const requestFailureRetryFailed = (failure) => ({
34
46
  type: REQUEST_FAILURE_RETRY_FAILED,
35
- failure: failure,
36
- error
47
+ failure
37
48
  })
38
49
 
39
50
  export const performFailureRetry = (failure) => (dispatch, getState) => {
@@ -41,18 +52,24 @@ export const performFailureRetry = (failure) => (dispatch, getState) => {
41
52
  return API.Failure
42
53
  .retry({id: failure.id})
43
54
  .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
- })))
55
+ dispatch(receiveFailureRetry(failure, response.data))
56
+ dispatch(hideFailureRetry(failure))
57
+ dispatch(addFlashMessage({
58
+ type: 'success',
59
+ text: `Failure retried with success. Acknowledged: ${response.data.acknowledged}`,
60
+ autoClose: true
61
+ }))
62
+ dispatch(hideFailureOverview(failure))
63
+ dispatch(deleteFailure(failure))
53
64
  })
54
65
  .catch((response) => {
55
66
  const error = parseResponseError(response)
56
- dispatch(requestFailureRetryFailed(failure, error.message))
67
+ dispatch(hideFailureRetry(failure))
68
+ dispatch(addFlashMessage({
69
+ type: 'error',
70
+ text: `Failure retried with error: ${error.message}`,
71
+ autoClose: false
72
+ }))
73
+ dispatch(requestFailureRetryFailed(failure))
57
74
  })
58
75
  }
@@ -12,8 +12,10 @@ import {
12
12
  FAILURE_HIDE_RETRY,
13
13
  REQUEST_FAILURE_RETRY,
14
14
  RECEIVE_FAILURE_RETRY,
15
+ REQUEST_FAILURE_RETRY_FAILED,
15
16
  ADD_FLASH_MESSAGE,
16
- REQUEST_FAILURE_RETRY_FAILED
17
+ FAILURE_HIDE_OVERVIEW,
18
+ DELETE_FAILURE
17
19
  } from 'actions'
18
20
 
19
21
  import {
@@ -87,12 +89,32 @@ describe('actions/failures/retry', () => {
87
89
  })
88
90
  .catch((e) => done.fail(`test failed with promise error: ${e.message}`))
89
91
  })
92
+
93
+ it('creates an action to hide the failure overview', (done) => {
94
+ store.dispatch(performFailureRetry(failure)).then(() => {
95
+ const actions = store.getActions()
96
+ expect(actions[4]).toEqual({ type: FAILURE_HIDE_OVERVIEW, failure: failure })
97
+ done()
98
+ })
99
+ .catch((e) => done.fail(`test failed with promise error: ${e.message}`))
100
+ })
101
+
102
+ it('creates an action to delete the failure from state', (done) => {
103
+ store.dispatch(performFailureRetry(failure)).then(() => {
104
+ const actions = store.getActions()
105
+ expect(actions[5]).toEqual({ type: DELETE_FAILURE, failure: failure })
106
+ done()
107
+ })
108
+ .catch((e) => done.fail(`test failed with promise error: ${e.message}`))
109
+ })
90
110
  })
91
111
 
92
112
  describe('when it fails', () => {
93
- it('creates REQUEST and REQUEST_FAILED actions', (done) => {
94
- const failure = { id: 1 }
95
- const store = mockStore({})
113
+ let store, failure
114
+
115
+ beforeEach(() => {
116
+ failure = { id: 1 }
117
+ store = mockStore({})
96
118
  Mappersmith.Env.Fixture
97
119
  .define('post')
98
120
  .matching({ url: `/api/v1/failures/${failure.id}/retry` })
@@ -103,11 +125,36 @@ describe('actions/failures/retry', () => {
103
125
  message: 'some error'
104
126
  })
105
127
  })
128
+ })
106
129
 
130
+ it('creates REQUEST and REQUEST_FAILED actions', (done) => {
107
131
  store.dispatch(performFailureRetry(failure)).then(() => {
108
132
  const actions = store.getActions()
109
133
  expect(actions[0]).toEqual({ type: REQUEST_FAILURE_RETRY, failure })
110
- expect(actions[1]).toEqual({ type: REQUEST_FAILURE_RETRY_FAILED, failure, error: 'some error' })
134
+ expect(actions[1]).toEqual({ type: FAILURE_HIDE_RETRY, failure })
135
+ done()
136
+ })
137
+ .catch((e) => done.fail(`test failed with promise error: ${e.message}`))
138
+ })
139
+
140
+ it('creates an action to add an error flash message', (done) => {
141
+ store.dispatch(performFailureRetry(failure)).then(() => {
142
+ const actions = store.getActions()
143
+ expect(actions[2]).toEqual({ type: ADD_FLASH_MESSAGE, message: {
144
+ id: jasmine.any(String),
145
+ type: 'error',
146
+ text: 'Failure retried with error: some error',
147
+ autoClose: false
148
+ }})
149
+ done()
150
+ })
151
+ .catch((e) => done.fail(`test failed with promise error: ${e.message}`))
152
+ })
153
+
154
+ it('creates an action to clear the loading status', (done) => {
155
+ store.dispatch(performFailureRetry(failure)).then(() => {
156
+ const actions = store.getActions()
157
+ expect(actions[3]).toEqual({ type: REQUEST_FAILURE_RETRY_FAILED, failure })
111
158
  done()
112
159
  })
113
160
  .catch((e) => done.fail(`test failed with promise error: ${e.message}`))
@@ -1,4 +1,3 @@
1
-
2
1
  import API, { EVENTS_SEARCH_LIMIT, parseResponseError } from 'api'
3
2
  import { addFlashMessage } from 'actions/flash-messages'
4
3
  import { history } from 'routes'
@@ -54,13 +53,11 @@ export const fetchSearchResults = () => (dispatch, getState) => {
54
53
  })
55
54
  .catch((response) => {
56
55
  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
- })))
56
+ dispatch(requestSearchResultsFailed(query, error.message))
57
+ dispatch(addFlashMessage({
58
+ type: 'error',
59
+ text: `Failures search failed. "${error.message}"`
60
+ }))
64
61
  })
65
62
  }
66
63
 
@@ -145,14 +145,14 @@ describe('actions/failures/search', () => {
145
145
  let failure, initialState, store
146
146
  beforeEach(() => {
147
147
  initialState = {
148
- eventsFilters: {},
148
+ eventsFilters: { type: 'event_type', value: 'new' },
149
149
  xhrStatus: { currentEventsOffset: 0 }
150
150
  }
151
151
  store = mockStore(initialState)
152
152
  failure = { id: 1 }
153
153
  Mappersmith.Env.Fixture
154
154
  .define('get')
155
- .matching({ url: `/api/v1/failures?limit=${EVENTS_SEARCH_LIMIT}&offset=0` })
155
+ .matching({ url: `/api/v1/failures?limit=${EVENTS_SEARCH_LIMIT}&event_type=new&offset=0` })
156
156
  .response([failure])
157
157
  })
158
158
 
@@ -13,8 +13,8 @@ export const REQUEST_EVENT_RETRY_FAILED = 'REQUEST_EVENT_RETRY_FAILED'
13
13
  export const FAILURE_SHOW_RETRY = 'FAILURE_SHOW_RETRY'
14
14
  export const FAILURE_HIDE_RETRY = 'FAILURE_HIDE_RETRY'
15
15
  export const REQUEST_FAILURE_RETRY = 'REQUEST_FAILURE_RETRY'
16
- export const RECEIVE_FAILURE_RETRY = 'RECEIVE_FAILURE_RETRY'
17
16
  export const REQUEST_FAILURE_RETRY_FAILED = 'REQUEST_FAILURE_RETRY_FAILED'
17
+ export const RECEIVE_FAILURE_RETRY = 'RECEIVE_FAILURE_RETRY'
18
18
 
19
19
  export const SEARCH_INPUT_CHANGE_FILTER_TYPE = 'SEARCH_INPUT_CHANGE_FILTER_TYPE'
20
20
  export const SEARCH_INPUT_CHANGE_FILTER_VALUE = 'SEARCH_INPUT_CHANGE_FILTER_VALUE'
@@ -41,3 +41,5 @@ export const REQUEST_EVENT_DETAILS_FAILED = 'REQUEST_EVENT_DETAILS_FAILED'
41
41
  export const REQUEST_FAILURE_DETAILS = 'REQUEST_FAILURE_DETAILS'
42
42
  export const RECEIVE_FAILURE_DETAILS = 'RECEIVE_FAILURE_DETAILS'
43
43
  export const REQUEST_FAILURE_DETAILS_FAILED = 'REQUEST_FAILURE_DETAILS_FAILED'
44
+
45
+ export const DELETE_FAILURE = 'DELETE_FAILURE'
@@ -0,0 +1,6 @@
1
+ .empty-event {
2
+ margin: 50px 15px 0;
3
+ font-size: 30px;
4
+ font-weight: lighter;
5
+ font-family: Roboto;
6
+ }
@@ -0,0 +1,29 @@
1
+ import moment from 'moment'
2
+ const TIME_FORMAT = 'h:mm:ss a'
3
+ const EMPTY_TYPE = '<no type>'
4
+
5
+ export function formatTime (time) {
6
+ if (!time) return null
7
+ const timeDate = new Date(time)
8
+ return moment(timeDate).format(TIME_FORMAT)
9
+ }
10
+
11
+ export function formattedEventType (eventType) {
12
+ return eventType || EMPTY_TYPE
13
+ }
14
+
15
+ export default {
16
+ card: {
17
+ width: '490px',
18
+ overflow: 'hidden'
19
+ },
20
+ cardHeader: {
21
+ title: {
22
+ fontWeight: 'lighter'
23
+ }
24
+ },
25
+ cardTitle: {
26
+ fontSize: '38px',
27
+ fontWeight: 'lighter'
28
+ }
29
+ }
@@ -1,3 +1,15 @@
1
1
  .event {
2
2
  cursor: pointer;
3
+
4
+ .event-header {
5
+ display: flex;
6
+ justify-content: space-between;
7
+ }
8
+
9
+ .event-icon {
10
+ order: 2;
11
+ width: 35px !important;
12
+ height: 35px !important;
13
+ margin-right: 0 !important;
14
+ }
3
15
  }
@@ -1,22 +1,17 @@
1
1
  import React, { Component, PropTypes } from 'react'
2
2
  import { connect } from 'react-redux'
3
- import moment from 'moment'
4
3
 
5
4
  import { showEventOverview } from 'actions/event-overview'
6
- import style from 'components/event/style'
5
+ import cardStyle, {
6
+ formatTime,
7
+ formattedEventType
8
+ } from 'components/event/card-style'
7
9
 
8
10
  import {Card, CardHeader, CardTitle} from 'material-ui/Card'
11
+ import EventsIcon from 'material-ui/svg-icons/communication/call-received'
9
12
  import EventOverviewDialog from 'components/event-overview-dialog'
10
13
  import EventRetryDialog from 'components/event-retry-dialog'
11
-
12
- const EVENT_TIME_FORMAT = 'h:mm:ss a'
13
- const EMPTY_EVENT_TYPE = '<no type>'
14
-
15
- export function formatEventTime (eventTime) {
16
- if (!eventTime) return null
17
- const eventTimeDate = new Date(eventTime)
18
- return moment(eventTimeDate).format(EVENT_TIME_FORMAT)
19
- }
14
+ import { green200 } from 'material-ui/styles/colors'
20
15
 
21
16
  export class Event extends Component {
22
17
  static get propTypes () {
@@ -46,17 +41,17 @@ export class Event extends Component {
46
41
  return (
47
42
  <Card
48
43
  className='event'
49
- style={style.card}
44
+ style={cardStyle.card}
50
45
  onClick={() => this.showOverview()}>
51
46
  <CardHeader
52
47
  className='event-header'
53
- titleStyle={style.cardHeader.title}
54
- subtitleStyle={style.cardHeader.subtitle}
55
- title={formatEventTime(this.props.event.event_time)}
48
+ avatar={<EventsIcon className='event-icon' color={green200} />}
49
+ titleStyle={cardStyle.cardHeader.title}
50
+ title={formatTime(this.props.event.event_time)}
56
51
  subtitle={this.props.event.topic}/>
57
52
  <CardTitle
58
- titleStyle={style.cardTitle}
59
- title={this.formatedEventType()}/>
53
+ titleStyle={cardStyle.cardTitle}
54
+ title={formattedEventType(this.props.event.event_type)}/>
60
55
  <EventOverviewDialog event={this.props.event} />
61
56
  <EventRetryDialog event={this.props.event} />
62
57
  </Card>
@@ -66,10 +61,6 @@ export class Event extends Component {
66
61
  showOverview () {
67
62
  this.props.onShowOverview(this.props.event)
68
63
  }
69
-
70
- formatedEventType () {
71
- return this.props.event.event_type || EMPTY_EVENT_TYPE
72
- }
73
64
  }
74
65
 
75
66
  export default connect((state, ownProps) => ownProps, {
@@ -1,7 +1,8 @@
1
1
  import React from 'react'
2
2
  import jasmineEnzyme from 'jasmine-enzyme'
3
3
  import { mount } from 'enzyme'
4
- import { Event, formatEventTime } from 'components/event'
4
+ import { Event } from 'components/event'
5
+ import { formatTime } from 'components/event/card-style'
5
6
  import getMuiTheme from 'material-ui/styles/getMuiTheme'
6
7
  import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
7
8
  import { Provider } from 'react-redux'
@@ -51,7 +52,7 @@ describe('<Event />', () => {
51
52
  })
52
53
 
53
54
  it('displays event_time formatted', () => {
54
- expect(component.text()).toMatch(formatEventTime(props.event.event_time))
55
+ expect(component.text()).toMatch(formatTime(props.event.event_time))
55
56
  })
56
57
 
57
58
  it('displays topic', () => {
@@ -49,7 +49,7 @@ class OverviewDialog extends Component {
49
49
  bodyStyle={{maxWidth: '1024px'}}
50
50
  actions={[
51
51
  <RaisedButton
52
- secondary
52
+ primary
53
53
  label='Retry'
54
54
  onClick={() => this.showRetry()}/>
55
55
  ]}>
@@ -32,7 +32,7 @@ class RetryDialog extends Component {
32
32
  return (
33
33
  <Dialog
34
34
  modal={!!this.props.isRetryingEvent}
35
- title='Are you sure?'
35
+ title={this.renderTitle()}
36
36
  open={!!this.props.event.retryVisible}
37
37
  bodyStyle={{maxWidth: '300px'}}
38
38
  contentStyle={{maxWidth: '300px'}}
@@ -41,6 +41,7 @@ class RetryDialog extends Component {
41
41
  <RaisedButton
42
42
  primary
43
43
  label='Retry'
44
+ disabled={this.props.isRetryingEvent}
44
45
  onClick={() => this.performRetry()}/>
45
46
  ]}>
46
47
  <div style={{textAlign: 'center'}}>
@@ -51,6 +52,13 @@ class RetryDialog extends Component {
51
52
  )
52
53
  }
53
54
 
55
+ renderTitle () {
56
+ if (this.props.isRetryingEvent) {
57
+ return 'Retrying event...'
58
+ }
59
+ return 'Are you sure?'
60
+ }
61
+
54
62
  hide () {
55
63
  this.props.onHideRetry(this.props.event)
56
64
  }
@@ -0,0 +1,6 @@
1
+ .empty-failure {
2
+ margin: 50px 15px 0;
3
+ font-size: 30px;
4
+ font-weight: lighter;
5
+ font-family: Roboto;
6
+ }
@@ -0,0 +1,20 @@
1
+ import React, { Component, PropTypes } from 'react'
2
+
3
+ export default class EmptyFailure extends Component {
4
+ static get propTypes () {
5
+ return {
6
+ failures: PropTypes.array.isRequired,
7
+ isFetchingEvents: PropTypes.bool.isRequired
8
+ }
9
+ }
10
+
11
+ render () {
12
+ return (
13
+ this.props.failures.length === 0 &&
14
+ !this.props.isFetchingEvents &&
15
+ <div className='empty-failure'>
16
+ No failures found
17
+ </div>
18
+ )
19
+ }
20
+ }
@@ -0,0 +1,38 @@
1
+ import React from 'react'
2
+ import jasmineEnzyme from 'jasmine-enzyme'
3
+ import { shallow } from 'enzyme'
4
+
5
+ import EmptyFailure from 'components/failure/empty'
6
+
7
+ describe('<EmptyFailure />', () => {
8
+ let props, wrapper
9
+
10
+ beforeEach(() => {
11
+ jasmineEnzyme()
12
+ props = {
13
+ failures: [{ id: 1 }, { id: 2 }],
14
+ isFetchingEvents: false
15
+ }
16
+ wrapper = shallow(<EmptyFailure {...props} />)
17
+ })
18
+
19
+ describe('with events', () => {
20
+ it('does not render <EmptyFailure />', () => {
21
+ expect(wrapper.find('.empty-failure').length).toEqual(0)
22
+ })
23
+ })
24
+
25
+ describe('without events', () => {
26
+ beforeEach(() => {
27
+ props = {
28
+ ...props,
29
+ failures: []
30
+ }
31
+ wrapper = shallow(<EmptyFailure {...props} />)
32
+ })
33
+
34
+ it('renders <EmptyFailure />', () => {
35
+ expect(wrapper.find('.empty-failure').length).toEqual(1)
36
+ })
37
+ })
38
+ })
@@ -1,22 +1,17 @@
1
1
  import React, { Component, PropTypes } from 'react'
2
2
  import { connect } from 'react-redux'
3
- import moment from 'moment'
4
3
 
5
4
  import { showFailureOverview } from 'actions/failures/overview'
6
- import style from 'components/event/style'
5
+ import cardStyle, {
6
+ formatTime,
7
+ formattedEventType
8
+ } from 'components/event/card-style'
7
9
 
8
10
  import { Card, CardHeader, CardTitle } from 'material-ui/Card'
11
+ import FailuresIcon from 'material-ui/svg-icons/communication/call-missed'
9
12
  import FailureOverviewDialog from 'components/failure/overview-dialog'
10
13
  import FailureRetryDialog from 'components/failure/retry-dialog'
11
-
12
- const TIME_FORMAT = 'h:mm:ss a'
13
- const EMPTY_TYPE = '<no type>'
14
-
15
- export function formatTime (time) {
16
- if (!time) return null
17
- const timeDate = new Date(time)
18
- return moment(timeDate).format(TIME_FORMAT)
19
- }
14
+ import { red500 } from 'material-ui/styles/colors'
20
15
 
21
16
  export class Failure extends Component {
22
17
  static get propTypes () {
@@ -51,17 +46,17 @@ export class Failure extends Component {
51
46
  return (
52
47
  <Card
53
48
  className='failure'
54
- style={style.card}
49
+ style={cardStyle.card}
55
50
  onClick={() => this.showOverview()}>
56
51
  <CardHeader
57
52
  className='failure-header'
58
- titleStyle={style.cardHeader.title}
59
- subtitleStyle={style.cardHeader.subtitle}
53
+ avatar={<FailuresIcon className='failure-icon' color={red500} />}
54
+ titleStyle={cardStyle.cardHeader.title}
60
55
  title={formatTime(this.props.failure.event_time)}
61
56
  subtitle={this.props.failure.topic}/>
62
57
  <CardTitle
63
- titleStyle={style.cardTitle}
64
- title={this.formattedEventType()}/>
58
+ titleStyle={cardStyle.cardTitle}
59
+ title={formattedEventType(this.props.failure.event_type)}/>
65
60
  <FailureOverviewDialog failure={this.props.failure} />
66
61
  <FailureRetryDialog failure={this.props.failure} />
67
62
  </Card>
@@ -71,10 +66,6 @@ export class Failure extends Component {
71
66
  showOverview () {
72
67
  this.props.onShowOverview(this.props.failure)
73
68
  }
74
-
75
- formattedEventType () {
76
- return this.props.failure.event_type || EMPTY_TYPE
77
- }
78
69
  }
79
70
 
80
71
  export default connect((state, ownProps) => ownProps, {