flapjack 0.7.18 → 0.7.19

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 (100) hide show
  1. data/CHANGELOG.md +7 -0
  2. data/bin/flapjack +3 -0
  3. data/bin/flapjack-nagios-receiver +4 -1
  4. data/bin/flapjack-netsaint-parser +2 -1
  5. data/bin/flapjack-populator +6 -3
  6. data/bin/receive-events +3 -1
  7. data/bin/simulate-failed-check +2 -1
  8. data/etc/flapjack_config.yaml.example +20 -0
  9. data/features/events.feature +1 -1
  10. data/features/events_check_names.feature +1 -1
  11. data/features/notification_rules.feature +1 -1
  12. data/features/notifications.feature +1 -1
  13. data/features/steps/events_steps.rb +18 -17
  14. data/features/steps/flapjack-netsaint-parser_steps.rb +1 -2
  15. data/features/steps/notifications_steps.rb +14 -1
  16. data/features/support/env.rb +27 -10
  17. data/flapjack.gemspec +1 -3
  18. data/lib/flapjack/coordinator.rb +30 -20
  19. data/lib/flapjack/data/contact.rb +3 -2
  20. data/lib/flapjack/data/entity.rb +3 -3
  21. data/lib/flapjack/data/entity_check.rb +116 -43
  22. data/lib/flapjack/data/event.rb +10 -10
  23. data/lib/flapjack/data/message.rb +3 -6
  24. data/lib/flapjack/data/notification.rb +122 -57
  25. data/lib/flapjack/data/notification_rule.rb +11 -11
  26. data/lib/flapjack/filters/acknowledgement.rb +2 -2
  27. data/lib/flapjack/filters/ok.rb +1 -1
  28. data/lib/flapjack/gateways/api/entity_check_presenter.rb +1 -0
  29. data/lib/flapjack/gateways/api/entity_methods.rb +4 -6
  30. data/lib/flapjack/gateways/api/rack/json_params_parser.rb +1 -1
  31. data/lib/flapjack/gateways/email.rb +3 -5
  32. data/lib/flapjack/gateways/email/{alert.html.haml → alert.html.erb} +0 -0
  33. data/lib/flapjack/gateways/jabber.rb +66 -35
  34. data/lib/flapjack/gateways/oobetet.rb +5 -7
  35. data/lib/flapjack/gateways/pagerduty.rb +7 -7
  36. data/lib/flapjack/gateways/web.rb +101 -41
  37. data/lib/flapjack/gateways/web/public/css/flapjack.css +1 -1
  38. data/lib/flapjack/gateways/web/views/{_css.haml → _css.html.erb} +2 -1
  39. data/lib/flapjack/gateways/web/views/_foot.html.erb +3 -0
  40. data/lib/flapjack/gateways/web/views/_head.html.erb +4 -0
  41. data/lib/flapjack/gateways/web/views/_nav.html.erb +9 -0
  42. data/lib/flapjack/gateways/web/views/check.html.erb +204 -0
  43. data/lib/flapjack/gateways/web/views/checks.html.erb +77 -0
  44. data/lib/flapjack/gateways/web/views/contact.html.erb +114 -0
  45. data/lib/flapjack/gateways/web/views/contacts.html.erb +42 -0
  46. data/lib/flapjack/gateways/web/views/entities.html.erb +39 -0
  47. data/lib/flapjack/gateways/web/views/entity.html.erb +67 -0
  48. data/lib/flapjack/gateways/web/views/index.html.erb +27 -0
  49. data/lib/flapjack/gateways/web/views/self_stats.html.erb +97 -0
  50. data/lib/flapjack/logger.rb +71 -23
  51. data/lib/flapjack/notifier.rb +157 -0
  52. data/lib/flapjack/patches.rb +1 -41
  53. data/lib/flapjack/pikelet.rb +4 -2
  54. data/lib/flapjack/{executive.rb → processor.rb} +32 -145
  55. data/lib/flapjack/version.rb +1 -1
  56. data/spec/lib/flapjack/coordinator_spec.rb +134 -71
  57. data/spec/lib/flapjack/data/contact_spec.rb +1 -0
  58. data/spec/lib/flapjack/data/entity_check_spec.rb +146 -30
  59. data/spec/lib/flapjack/data/entity_spec.rb +4 -4
  60. data/spec/lib/flapjack/data/event_spec.rb +4 -4
  61. data/spec/lib/flapjack/data/message_spec.rb +2 -3
  62. data/spec/lib/flapjack/data/notification_spec.rb +13 -19
  63. data/spec/lib/flapjack/gateways/api/entity_methods_spec.rb +2 -2
  64. data/spec/lib/flapjack/gateways/jabber_spec.rb +34 -0
  65. data/spec/lib/flapjack/gateways/pagerduty_spec.rb +0 -2
  66. data/spec/lib/flapjack/gateways/web/views/{check.haml_spec.rb → check.html.erb_spec.rb} +2 -2
  67. data/spec/lib/flapjack/gateways/web/views/{contact.haml_spec.rb → contact.html.erb_spec.rb} +3 -3
  68. data/spec/lib/flapjack/gateways/web/views/index.html.erb_spec.rb +14 -0
  69. data/spec/lib/flapjack/gateways/web_spec.rb +20 -8
  70. data/spec/lib/flapjack/logger_spec.rb +30 -28
  71. data/spec/lib/flapjack/notifier_spec.rb +6 -0
  72. data/spec/lib/flapjack/pikelet_spec.rb +8 -8
  73. data/spec/lib/flapjack/{executive_spec.rb → processor_spec.rb} +4 -4
  74. data/spec/spec_helper.rb +1 -13
  75. data/spec/support/erb_view_helper.rb +23 -0
  76. data/tasks/profile.rake +1 -1
  77. data/tmp/acknowledge.rb +3 -1
  78. data/tmp/create_event_ok.rb +3 -1
  79. data/tmp/create_event_unknown.rb +3 -1
  80. data/tmp/create_events_failure.rb +3 -1
  81. data/tmp/create_events_ok.rb +3 -1
  82. data/tmp/create_events_ok_fail_ack_ok.rb +3 -1
  83. data/tmp/create_events_ok_failure.rb +3 -1
  84. data/tmp/create_events_ok_failure_ack.rb +3 -1
  85. data/tmp/test_json_post.rb +5 -3
  86. data/tmp/test_notification_rules_api.rb +5 -3
  87. metadata +32 -61
  88. data/lib/flapjack/gateways/web/views/_foot.haml +0 -8
  89. data/lib/flapjack/gateways/web/views/_head.haml +0 -10
  90. data/lib/flapjack/gateways/web/views/_nav.haml +0 -14
  91. data/lib/flapjack/gateways/web/views/check.haml +0 -191
  92. data/lib/flapjack/gateways/web/views/checks.haml +0 -49
  93. data/lib/flapjack/gateways/web/views/contact.haml +0 -85
  94. data/lib/flapjack/gateways/web/views/contacts.haml +0 -30
  95. data/lib/flapjack/gateways/web/views/entities.haml +0 -28
  96. data/lib/flapjack/gateways/web/views/entity.haml +0 -50
  97. data/lib/flapjack/gateways/web/views/index.haml +0 -32
  98. data/lib/flapjack/gateways/web/views/self_stats.haml +0 -70
  99. data/spec/lib/flapjack/gateways/web/views/index.haml_spec.rb +0 -13
  100. data/spec/support/haml_view_helper.rb +0 -15
@@ -43,7 +43,7 @@
43
43
 
44
44
  .container {
45
45
  width: auto;
46
- max-width: 900px;
46
+ max-width: 1900px;
47
47
  }
48
48
  .container .credit {
49
49
  margin: 10px 0;
@@ -1,4 +1,4 @@
1
- :css
1
+ <style type="text/css">
2
2
  * { margin: 0; padding: 0; }
3
3
  html { font-size: 62.5%; }
4
4
  body { font-size: 16px; }
@@ -39,3 +39,4 @@
39
39
  table td.up {
40
40
  background-color: #B2DF8A;
41
41
  }
42
+ </style>
@@ -0,0 +1,3 @@
1
+ <div class="container">
2
+ <p class="muted credit">Flapjack version <%= ::Flapjack::VERSION %> | <a href="http://flapjack-project.com">Flapjack Project</a> | <a href="https://github.com/flpjck/flapjack">Flapjack on Github</a></p>
3
+ </div>
@@ -0,0 +1,4 @@
1
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
2
+ <link rel="stylesheet" href="/css/bootstrap.min.css" media="screen">
3
+ <link rel="stylesheet" href="/css/flapjack.css" media="screen">
4
+ <link rel="stylesheet" href="/css/bootstrap-responsive.min.css" media="screen">
@@ -0,0 +1,9 @@
1
+ <p>
2
+ <a title="" href="/">Summary</a> |
3
+ <a title="" href="/entities_all">All Entities</a> |
4
+ <a title="" href="/entities_failing">Failing Entities</a> |
5
+ <a title="" href="/checks_all">All Checks</a> |
6
+ <a title="" href="/checks_failing">Failing Checks</a> |
7
+ <a title="" href="/contacts">Contacts</a> |
8
+ <a title="" href="/self_stats">Internal Statistics</a>
9
+ </p>
@@ -0,0 +1,204 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <% nav = render_erb('_nav.html.erb', binding) %>
5
+ <% head = render_erb('_head.html.erb', binding) %>
6
+ <% foot = render_erb('_foot.html.erb', binding) %>
7
+ <% check_path_escaped = u(@entity) << '/' << u(@check) %>
8
+ <% current_time = Time.now %>
9
+ <title>Flapjack - Check: <%= h @entity %>:<%= h @check %></title>
10
+ <%= head %>
11
+ </head>
12
+ <body>
13
+ <div id="wrap">
14
+ <div class="container">
15
+ <div class="page-header">
16
+ <%= nav %>
17
+ <% entity_link = "/entity/" + u(@entity) %>
18
+ <h2><%= h @check %> on <a href="<%= entity_link %>" title="entity summary"><%= h @entity %></a></h2>
19
+ </div>
20
+ <% state_qualifier = @check_enabled ? '' : "DISABLED. Last " %>
21
+ <h3><%= state_qualifier %>State: <%= @check_state ? h(@check_state.upcase) : '' %></h3>
22
+ <% if (['warning', 'critical', 'unknown'].include?(@check_state) and !@current_scheduled_maintenance) %>
23
+ <form action="/acknowledgements/<%= check_path_escaped %>" method="post" class="form-inline">
24
+ <input type="hidden" name="acknowledgement_id" value="<%= @acknowledgement_id %>">
25
+ <input type="submit" value="<%= @current_unscheduled_maintenance ? 'Replace acknowledgment' : 'Acknowledge' %>" class="button">
26
+ with
27
+ <label>summary:</label>
28
+ <input type="text" name="summary" value="">
29
+ <label>duration:</label>
30
+ <input type="text" name="duration" value="">
31
+ e.g. "5 hours"
32
+ </form>
33
+ <% end %>
34
+ <% if @current_unscheduled_maintenance %>
35
+ <h3>(Acknowledged - <%= h @current_unscheduled_maintenance[:summary] %>)</h3>
36
+ <% start = Time.at(@current_unscheduled_maintenance[:start_time]) %>
37
+ <% finish = Time.at(@current_unscheduled_maintenance[:start_time] + @current_unscheduled_maintenance[:duration]) %>
38
+ <% remain = time_period_in_words( (finish - current_time).ceil ) %>
39
+ <p><%= h start.to_s %> -&gt; <%= h finish.to_s %> (<%= h remain %> remaining)</p>
40
+ <form action="/end_unscheduled_maintenance/<%= check_path_escaped %>" method="post">
41
+ <input type="submit" value="End Unscheduled Maintenance (Unacknowledge)" class="button">
42
+ </form>
43
+ <% end %>
44
+ <% if @current_scheduled_maintenance %>
45
+ <h4>(Scheduled Maintenance - <%= h @current_scheduled_maintenance[:summary] %></h4>
46
+ <% start = Time.at(@current_scheduled_maintenance[:start_time]) %>
47
+ <% finish = Time.at(@current_scheduled_maintenance[:start_time] + @current_scheduled_maintenance[:duration]) %>
48
+ <% remain = time_period_in_words( (finish - current_time).ceil ) %>
49
+ <p><%= h start.to_s %> -&gt; <%= h finish.to_s %> (<%= h remain %> remaining)</p>
50
+ <% end %>
51
+ <h3>Output: <%= h @check_summary %></h3>
52
+ <p><%= h @check_details %></p>
53
+ <table class="table table-hover table-condensed">
54
+ <tr>
55
+ <td>Last state change:</td>
56
+ <td><%= h relative_time_ago(Time.at(@check_last_change.to_i)) %> ago</td>
57
+ <td><%= h Time.at(@check_last_change.to_i).to_s %></td>
58
+ <td>&nbsp;</td>
59
+ </tr>
60
+ <tr>
61
+ <td>Last update:</td>
62
+ <td><%= h relative_time_ago(Time.at(@check_last_update.to_i)) %> ago</td>
63
+ <td><%= h Time.at(@check_last_update.to_i).to_s %></td>
64
+ <td>&nbsp;</td>
65
+ </tr>
66
+ <% [:critical, :warning, :unknown, :recovery, :acknowledgement].each do |type| %>
67
+ <tr>
68
+ <td>Last <%= h type.to_s %> notification:</td>
69
+ <td><%= @last_notifications[type] ? h(@last_notifications[type][:relative]) : 'never' %></td>
70
+ <td><%= @last_notifications[type] ? h(@last_notifications[type][:time].to_s) : '&nbsp;' %></td>
71
+ <td><%= @last_notifications[type] ? h(@last_notifications[type][:summary]) : '&nbsp;' %></td>
72
+ </tr>
73
+ <% end %>
74
+ </table>
75
+
76
+ <div id="currency">
77
+ <% if @check_enabled %>
78
+ Enabled ...
79
+ <form action="/checks/<%= check_path_escaped %>" method="post" style="display:inline-block">
80
+ <input type='hidden' name='_method' value='delete'>
81
+ <input type='submit' value="Disable" class='button'>
82
+ </form>
83
+ <% else %>
84
+ Disabled
85
+ <% end %>
86
+
87
+ <h3>Scheduled Maintenance Periods</h3>
88
+ <% if @scheduled_maintenances && !@scheduled_maintenances.empty? %>
89
+ <table class="table table-bordered table-hover table-condensed">
90
+ <tr>
91
+ <th>Start</th>
92
+ <th>End</th>
93
+ <th>Duration</th>
94
+ <th>Summary</th>
95
+ <th>Actions</th>
96
+ </tr>
97
+
98
+ <% @scheduled_maintenances.sort_by {|s| s[:start_time]}.each do |scheduled_maintenance| %>
99
+ <% start_time = scheduled_maintenance[:start_time]
100
+ end_time = scheduled_maintenance[:end_time]
101
+ duration = scheduled_maintenance[:duration]
102
+ summary = scheduled_maintenance[:summary]
103
+ %>
104
+ <tr>
105
+ <td><%= h Time.at(start_time).to_s %></td>
106
+ <td><%= h Time.at(end_time).to_s %></td>
107
+ <td><%= h ChronicDuration.output(duration) %></td>
108
+ <td><%= h summary %></td>
109
+ <td>
110
+ <% if end_time > current_time.to_i %>
111
+ <% label = (start_time > current_time.to_i) ? 'Delete' : 'End Now' %>
112
+ <form action="/scheduled_maintenances/<%= check_path_escaped %>" method="post">
113
+ <input type="hidden" name="_method" value="delete">
114
+ <input type="hidden" name="start_time" value="<%= start_time %>">
115
+ <input type="submit" value="<%= label %>" class="button">
116
+ </form>
117
+ <% else %>
118
+ &nbsp;
119
+ <% end %>
120
+ </td>
121
+ </tr>
122
+ <% end %>
123
+
124
+ </table>
125
+ <% else %>
126
+ <p>No maintenance is scheduled</p>
127
+ <% end %>
128
+ <h4>Add Scheduled Maintenance</h4>
129
+ <form action="/scheduled_maintenances/<%= check_path_escaped %>" method="post" class="form-horizontal">
130
+ <div class="control-group">
131
+ <label class="control-label" for="start_time">Start time:</label>
132
+ <div class="controls">
133
+ <input type="text" name="start_time" class="text" size="20" maxlength="80" value="">
134
+ e.g. "today 4pm", "two hours hence", "friday 2pm", "2012-01-28 13:00"
135
+ </div>
136
+ </div>
137
+ <div class="control-group">
138
+ <label class="control-label" for="duration">Duration:</label>
139
+ <div class="controls">
140
+ <input type="text" name="duration" class="text" size="20" maxlength="80" value="">
141
+ e.g. "1 hour", "2:30:00", "three days", etc
142
+ </div>
143
+ </div>
144
+ <div class="control-group">
145
+ <label class="control-label" for="summary">Summary:</label>
146
+ <div class="controls">
147
+ <input type="text" name="summary" class="text" size="80" maxlength="160" value="">
148
+ </div>
149
+ </div>
150
+ <div class="control-group">
151
+ <div class="controls">
152
+ <input type="submit" value="Save" class="button">
153
+ </div>
154
+ </div>
155
+ </form>
156
+ <p>Times given will be interpreted in the local timezone of <%= h local_timezone %></p>
157
+ <% if @state_changes && !@state_changes.empty? %>
158
+ <h3>Recent state changes</h3>
159
+ <table class="table table-bordered table-hover table-condensed">
160
+ <tr>
161
+ <th>Timestamp</th>
162
+ <th>State</th>
163
+ <th>Summary</th>
164
+ </tr>
165
+ <% @state_changes.each do |state_change| %>
166
+ <tr>
167
+ <td><%= h Time.at(state_change[:timestamp]).to_s %></td>
168
+ <td><%= h state_change[:state] %></td>
169
+ <td><%= h state_change[:summary] %></td>
170
+ </tr>
171
+ <% end %>
172
+ </table>
173
+ <% end %>
174
+ <h3>Contacts</h3>
175
+ <% if @contacts && !@contacts.empty? %>
176
+ <table class="table table-bordered table-hover table-condensed">
177
+ <tr>
178
+ <th>Name</th>
179
+ <th>Media</th>
180
+ </tr>
181
+ <% @contacts.sort_by {|c| [c.first_name, c.last_name] }.each do |contact| %>
182
+ <tr>
183
+ <td><a href="/contacts/<% contact.id %>" title="contact details"><%= h contact.name %></a></td>
184
+ <td>
185
+ <% if contact.media && !contact.media.empty? %>
186
+ <p><%= h contact.media.keys.collect(&:capitalize).join(", ") %></p>
187
+ <% else %>
188
+ <p>No media</p>
189
+ <% end %>
190
+ </td>
191
+ </tr>
192
+ <% end %>
193
+ </table>
194
+ <% else %>
195
+ <p>No contacts</p>
196
+ <% end %>
197
+ </div>
198
+ <div id="push"></div>
199
+ </div>
200
+ <div id="footer">
201
+ <%= foot %>
202
+ </div>
203
+ </body>
204
+ </html>
@@ -0,0 +1,77 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <% nav = render_erb('_nav.html.erb', binding) %>
5
+ <% head = render_erb('_head.html.erb', binding) %>
6
+ <% foot = render_erb('_foot.html.erb', binding) %>
7
+ <title>Flapjack - <%= @adjective.capitalize %> Checks</title>
8
+ <%= head %>
9
+ </head>
10
+ <body>
11
+ <div id="wrap">
12
+ <div class="container">
13
+ <div class="page-header">
14
+ <%= nav %>
15
+ <h2><%= @adjective.capitalize %> Checks</h2>
16
+ </div>
17
+
18
+ <p><%= h @count_failing_checks %> failing out of <%= h @count_all_checks %></p>
19
+
20
+ <table class="table table-bordered table-hover table-condensed">
21
+ <tr>
22
+ <th>Entity</th>
23
+ <th>Check</th>
24
+ <th>State</th>
25
+ <th>Summary</th>
26
+ <th>Last State Change</th>
27
+ <th>Last Update</th>
28
+ <th>Last Notification</th>
29
+ </tr>
30
+ <% @entities_sorted.each do |entity| %>
31
+ <% row_entity = nil %>
32
+ <% entity_link = "/entity/" << u(entity) %>
33
+ <% @states[entity].each do |check, status, summary, changed, updated, in_unscheduled_outage, in_scheduled_outage, notified| %>
34
+ <%
35
+ row_colour = case status
36
+ when 'critical', 'unknown'
37
+ 'error'
38
+ when 'ok', 'up'
39
+ 'success'
40
+ else
41
+ status
42
+ end
43
+
44
+ check_link = "/check?entity=" << u(entity) << "&amp;check=" << u(check)
45
+
46
+ %>
47
+ <tr class="<%= row_colour %>">
48
+ <% unless row_entity && entity == row_entity %>
49
+ <td rowspan=<%= @states[entity].length %>>
50
+ <a href="<%= entity_link %>"><%= h entity %></a>
51
+ </td>
52
+ <% row_entity = entity %>
53
+ <% end %>
54
+ <td><a href="<%= check_link %>" title="check detail"><%= h check %></a></td>
55
+ <td class="<%= status %>">
56
+ <%= h status.upcase %>
57
+ <% if in_unscheduled_outage%> (Ack'd)<% end %>
58
+ <% if in_scheduled_outage %> (Sched)<% end %>
59
+ </td>
60
+ <td><%= h summary %></td>
61
+ <td><%= h changed %></td>
62
+ <td><%= h updated %></td>
63
+ <td><%= h notified %></td>
64
+ </tr>
65
+
66
+ <% end %>
67
+ <% end %>
68
+ </table>
69
+
70
+ </div>
71
+ <div id="push"></div>
72
+ </div>
73
+ <div id="footer">
74
+ <%= foot %>
75
+ </div>
76
+ </body>
77
+ </html>
@@ -0,0 +1,114 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <% nav = render_erb('_nav.html.erb', binding) %>
5
+ <% head = render_erb('_head.html.erb', binding) %>
6
+ <% foot = render_erb('_foot.html.erb', binding) %>
7
+ <title>Flapjack - <%= h @contact.name %> (contact)</title>
8
+ <%= head %>
9
+ </head>
10
+ <body>
11
+ <div id="wrap">
12
+ <div class="container">
13
+ <div class="page-header">
14
+ <%= nav %>
15
+ <h2><%= h @contact.name %></h2>
16
+ </div>
17
+
18
+ <h3>Contact Media</h3>
19
+ <% if !@contact.media || @contact.media.empty? %>
20
+ <p>No media</p>
21
+ <% else %>
22
+ <table class="table table-bordered table-hover table-condensed">
23
+ <tr>
24
+ <th>Media</th>
25
+ <th>Address</th>
26
+ <th>Interval</th>
27
+ </tr>
28
+ <% @contact.media.each_pair do |mk, mv| %>
29
+ <tr>
30
+ <% if 'pagerduty'.eql?(mk) %>
31
+ <td>PagerDuty</td>
32
+ <td>
33
+ <% @pagerduty_credentials.each_pair do |pk, pv| %>
34
+ <p><%= 'password'.eql?(pk) ? h("#{pk}: ...") : h("#{pk}: #{pv}") %></p>
35
+ <% end %>
36
+ </td>
37
+ <td>-</td>
38
+ <% else %>
39
+ <td><%= h mk.capitalize %></td>
40
+ <td><%= h mv %></td>
41
+ <td>
42
+ <% if @contact.media_intervals[mk] %>
43
+ <%= h @contact.media_intervals[mk] %> seconds
44
+ <% else %>
45
+ no custom interval
46
+ <% end %>
47
+ </td>
48
+ <% end %>
49
+ </tr>
50
+ <% end %>
51
+ </table>
52
+ <% end %>
53
+
54
+ <h3>Entities and Checks</h3>
55
+ <% if !@entities_and_checks || @entities_and_checks.empty? %>
56
+ <p>No entities</p>
57
+ <% else %>
58
+ <table class="table table-bordered table-hover table-condensed">
59
+ <tr>
60
+ <th>Entity</th>
61
+ <th>Checks</th>
62
+ </tr>
63
+ <% @entities_and_checks.each do |ec| %>
64
+ <%
65
+ entity = ec[:entity]
66
+ checks = ec[:checks]
67
+ %>
68
+ <tr>
69
+ <td><a href="/entity/<%= u(entity.name) %>" title="entity status"><%= h entity.name %></a></td>
70
+ <td>
71
+ <% checks.each do |check| %>
72
+ <a href="/check?entity=<%= u(entity.name) %>&amp;check=<%= u(check) %>" title="check status"><%= h check %></a>
73
+ <% end %>
74
+ </td>
75
+ </tr>
76
+ <% end %>
77
+ </table>
78
+ <% end %>
79
+
80
+ <h3>Notification Rules</h3>
81
+ <% rules = @contact.notification_rules %>
82
+ <% if !rules || rules.empty? %>
83
+ <p>No notification rules</p>
84
+ <% else %>
85
+ <table class="table table-bordered table-hover table-condensed">
86
+ <tr>
87
+ <th>ID</th>
88
+ <th>Entities</th>
89
+ <th>Entity Tags</th>
90
+ <th>Warning Media</th>
91
+ <th>Critical Media</th>
92
+ <th>Time Restrictions</th>
93
+ </tr>
94
+ <% rules.each do |rule| %>
95
+ <tr>
96
+ <td><%= h rule.id %></td>
97
+ <td><%= h( (rule.entities && !rule.entities.empty?) ? rule.entities.join(', ') : '-') %></td>
98
+ <td><%= h( (rule.entity_tags && !rule.entity_tags.empty?) ? rule.entity_tags.join(', ') : '-') %></td>
99
+ <td><%= h( (rule.warning_media && !rule.warning_media.empty?) ? rule.warning_media.join(', ') : '-')%></td>
100
+ <td><%= h( (rule.critical_media && !rule.critical_media.empty?) ? rule.critical_media.join(', ') : '-') %></td>
101
+ <td><%= h(rule.time_restrictions) %></td>
102
+ </tr>
103
+ <% end %>
104
+ </table>
105
+ <% end %>
106
+
107
+ </div>
108
+ <div id="push"></div>
109
+ </div>
110
+ <div id="footer">
111
+ <%= foot %>
112
+ </div>
113
+ </body>
114
+ </html>
@@ -0,0 +1,42 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <% nav = render_erb('_nav.html.erb', binding) %>
5
+ <% head = render_erb('_head.html.erb', binding) %>
6
+ <% foot = render_erb('_foot.html.erb', binding) %>
7
+ <title>Flapjack - Contacts</title>
8
+ <%= head %>
9
+ </head>
10
+ <body>
11
+ <div id="wrap">
12
+ <div class="container">
13
+ <div class="page-header">
14
+ <%= nav %>
15
+ <h2>Contacts</h2>
16
+ </div>
17
+
18
+ <% if !@contacts || @contacts.empty? %>
19
+ <p>No contacts</p>
20
+ <% else %>
21
+ <table class="table table-bordered table-hover table-condensed">
22
+ <tr>
23
+ <th>Name</th>
24
+ <th>Email</th>
25
+ </tr>
26
+ <% @contacts.sort_by {|c| [c.last_name, c.first_name] }.each do |contact| %>
27
+ <tr>
28
+ <td><a href="/contacts/<%= contact.id %>" title="contact details"><%= h contact.name %></a></td>
29
+ <td><%= h contact.email %></td>
30
+ </tr>
31
+ <% end %>
32
+ </table>
33
+ <% end %>
34
+
35
+ </div>
36
+ <div id="push"></div>
37
+ </div>
38
+ <div id="footer">
39
+ <%= foot %>
40
+ </div>
41
+ </body>
42
+ </html>