opsask 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.yardoc/checksums +4 -0
  4. data/.yardoc/object_types +0 -0
  5. data/.yardoc/objects/root.dat +0 -0
  6. data/.yardoc/proxy_types +0 -0
  7. data/Gemfile +15 -0
  8. data/Gemfile.lock +75 -0
  9. data/LICENSE +13 -0
  10. data/Rakefile +30 -0
  11. data/Readme.md +3 -0
  12. data/VERSION +1 -0
  13. data/bin/opsask +4 -0
  14. data/lib/opsask/app.rb +540 -0
  15. data/lib/opsask/main.rb +54 -0
  16. data/lib/opsask/metadata.rb +29 -0
  17. data/lib/opsask.rb +3 -0
  18. data/opsask.gemspec +29 -0
  19. data/public/css/foundation.css +5068 -0
  20. data/public/css/foundation.min.css +1 -0
  21. data/public/css/normalize.css +410 -0
  22. data/public/css/style.css +152 -0
  23. data/public/favicon.ico +0 -0
  24. data/public/fonts/DINMittelschriftStd.woff +0 -0
  25. data/public/img/.gitkeep +1 -0
  26. data/public/js/foundation/foundation.abide.js +256 -0
  27. data/public/js/foundation/foundation.accordion.js +49 -0
  28. data/public/js/foundation/foundation.alert.js +37 -0
  29. data/public/js/foundation/foundation.clearing.js +485 -0
  30. data/public/js/foundation/foundation.dropdown.js +208 -0
  31. data/public/js/foundation/foundation.equalizer.js +64 -0
  32. data/public/js/foundation/foundation.interchange.js +326 -0
  33. data/public/js/foundation/foundation.joyride.js +848 -0
  34. data/public/js/foundation/foundation.js +587 -0
  35. data/public/js/foundation/foundation.magellan.js +171 -0
  36. data/public/js/foundation/foundation.offcanvas.js +39 -0
  37. data/public/js/foundation/foundation.orbit.js +464 -0
  38. data/public/js/foundation/foundation.reveal.js +399 -0
  39. data/public/js/foundation/foundation.tab.js +58 -0
  40. data/public/js/foundation/foundation.tooltip.js +215 -0
  41. data/public/js/foundation/foundation.topbar.js +387 -0
  42. data/public/js/foundation/jquery.cookie.js +8 -0
  43. data/public/js/foundation.min.js +10 -0
  44. data/public/js/opsask.js +19 -0
  45. data/public/js/vendor/fastclick.js +9 -0
  46. data/public/js/vendor/jquery.cookie.js +8 -0
  47. data/public/js/vendor/jquery.js +26 -0
  48. data/public/js/vendor/modernizr.js +8 -0
  49. data/public/js/vendor/placeholder.js +2 -0
  50. data/tasks/generate-email-summary.rb +73 -0
  51. data/tasks/send-email-summary.sh +13 -0
  52. data/views/_components.erb +6 -0
  53. data/views/_count.erb +11 -0
  54. data/views/_flash.erb +3 -0
  55. data/views/_form.erb +37 -0
  56. data/views/_queue.erb +16 -0
  57. data/views/agile.erb +6 -0
  58. data/views/glance.erb +19 -0
  59. data/views/index.erb +27 -0
  60. data/views/layout.erb +43 -0
  61. data/views/stragglers.erb +6 -0
  62. data/views/untracked.erb +6 -0
  63. metadata +217 -0
@@ -0,0 +1,152 @@
1
+ @font-face{
2
+ font-family: "DIN 1451 Mittelschrift";
3
+ src:url('../fonts/DINMittelschriftStd.woff') format('woff');
4
+ }
5
+
6
+ body {
7
+ color: #ccc;
8
+ background-color: #000;
9
+ }
10
+
11
+ body, h1, h2, h3, h4, h5, h6 {
12
+ font-family: "Din 1451 Mittelschrift" !important;
13
+ }
14
+
15
+ h1, h2, h3, h4, h5, h6 {
16
+ font-weight: bold;
17
+ /*text-transform: uppercase;*/
18
+ }
19
+
20
+ h2 { color: #ddd; }
21
+
22
+ .ops-queue { margin-bottom: 5em; }
23
+
24
+ .button { margin-bottom: 0; }
25
+
26
+ .submit { float: right; }
27
+
28
+ .queue, .jira {
29
+ margin: 0;
30
+ margin-left: 0 !important;
31
+ padding: 0;
32
+ }
33
+
34
+ .jira { list-style-type: none; }
35
+
36
+ .jira .label { float: right; margin-left: 1em; }
37
+
38
+ .jira p {
39
+ color: #333;
40
+ margin-bottom: 0;
41
+ }
42
+
43
+ .jira.open.denimcores p,
44
+ .jira.open p {
45
+ color: #ccc;
46
+ }
47
+
48
+ .jira + .jira {
49
+ margin-top: 1.5em;
50
+ }
51
+
52
+ a, a:visited, .jira.open.denimcores a h3 {
53
+ color: #ffaa00;
54
+ border-color: #ffaa00;
55
+ }
56
+
57
+ .jira.open a, .jira.open a h3 {
58
+ color: #ff005c;
59
+ border-color: #ff005c;
60
+ }
61
+
62
+ .jira.open.denimcores a:hover, .jira.open.denimcores a:hover h3,
63
+ .jira.open a:hover, .jira.open a:hover h3 {
64
+ color: #00ffff;
65
+ border-color: #00ffff;
66
+ }
67
+
68
+ .jira a:active, .jira a:active h3 {
69
+ color: #999 !important;
70
+ border-color: #999 !important;
71
+ }
72
+
73
+ .jira a {
74
+ display: block;
75
+ padding: 1em;
76
+ background-color: #111;
77
+ border-left: 2px solid #333;
78
+ }
79
+
80
+ .jira.open.denimcores a {
81
+ background-color: #1a1a1a;
82
+ border-color: #ffaa00;
83
+ }
84
+
85
+ .jira a h3 {
86
+ color: #333;
87
+ }
88
+
89
+ .jira .label {
90
+ color: #555;
91
+ background-color: #222;
92
+ }
93
+
94
+ .jira.open.denimcores .label,
95
+ .jira.open .label {
96
+ color: #fff;
97
+ background-color: #5da423;
98
+ }
99
+
100
+ fieldset {
101
+ background-color: #1a1a1a;
102
+ border: none;
103
+ margin: 0;
104
+ }
105
+
106
+ input[type=text], input[type=text]:focus,
107
+ textarea, textarea:focus {
108
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
109
+ color: #fff;
110
+ background-color: #222;
111
+ border-color: #292929;
112
+ }
113
+
114
+ select, select:hover {
115
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
116
+ font-size: 0.75em;
117
+ color: #ccc;
118
+ border-color: #292929;
119
+ background-color: #222;
120
+ }
121
+
122
+ textarea { height: 100px; }
123
+
124
+ h3.empty { color: #666; }
125
+
126
+ .count.label {
127
+ float: right;
128
+ margin-top: 1em;
129
+ }
130
+
131
+ #indicators {
132
+ position: fixed;
133
+ right: 15px;
134
+ bottom: 15px;
135
+ }
136
+
137
+ .label a, .label a:visited { color: #fff; }
138
+
139
+ h3.need-to-login-to-jira,
140
+ h3.ops-queues-are-full {
141
+ color: #c60f13;
142
+ }
143
+
144
+ p.ops-queues-are-full {
145
+ font-size: 1.1em;
146
+ color: #ccc;
147
+ }
148
+
149
+ input[type="checkbox"] + label {
150
+ color: #bbb;
151
+ margin-left: 0.2em;
152
+ }
Binary file
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,256 @@
1
+ ;(function ($, window, document, undefined) {
2
+ 'use strict';
3
+
4
+ Foundation.libs.abide = {
5
+ name : 'abide',
6
+
7
+ version : '5.1.1',
8
+
9
+ settings : {
10
+ live_validate : true,
11
+ focus_on_invalid : true,
12
+ error_labels: true, // labels with a for="inputId" will recieve an `error` class
13
+ timeout : 1000,
14
+ patterns : {
15
+ alpha: /^[a-zA-Z]+$/,
16
+ alpha_numeric : /^[a-zA-Z0-9]+$/,
17
+ integer: /^\d+$/,
18
+ number: /-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?/,
19
+
20
+ // generic password: upper-case, lower-case, number/special character, and min 8 characters
21
+ password : /(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$/,
22
+
23
+ // amex, visa, diners
24
+ card : /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/,
25
+ cvv : /^([0-9]){3,4}$/,
26
+
27
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#valid-e-mail-address
28
+ email : /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/,
29
+
30
+ url: /(https?|ftp|file|ssh):\/\/(((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-zA-Z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-zA-Z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?/,
31
+ // abc.de
32
+ domain: /^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,6}$/,
33
+
34
+ datetime: /([0-2][0-9]{3})\-([0-1][0-9])\-([0-3][0-9])T([0-5][0-9])\:([0-5][0-9])\:([0-5][0-9])(Z|([\-\+]([0-1][0-9])\:00))/,
35
+ // YYYY-MM-DD
36
+ date: /(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))/,
37
+ // HH:MM:SS
38
+ time : /(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9]){2}/,
39
+ dateISO: /\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/,
40
+ // MM/DD/YYYY
41
+ month_day_year : /(0[1-9]|1[012])[- \/.](0[1-9]|[12][0-9]|3[01])[- \/.](19|20)\d\d/,
42
+
43
+ // #FFF or #FFFFFF
44
+ color: /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/
45
+ }
46
+ },
47
+
48
+ timer : null,
49
+
50
+ init : function (scope, method, options) {
51
+ this.bindings(method, options);
52
+ },
53
+
54
+ events : function (scope) {
55
+ var self = this,
56
+ form = self.S(scope).attr('novalidate', 'novalidate'),
57
+ settings = form.data(this.attr_name(true) + '-init');
58
+
59
+ this.invalid_attr = this.add_namespace('data-invalid');
60
+
61
+ form
62
+ .off('.abide')
63
+ .on('submit.fndtn.abide validate.fndtn.abide', function (e) {
64
+ var is_ajax = /ajax/i.test(self.S(this).attr(self.attr_name()));
65
+ return self.validate(self.S(this).find('input, textarea, select').get(), e, is_ajax);
66
+ })
67
+ .on('reset', function() {
68
+ return self.reset($(this));
69
+ })
70
+ .find('input, textarea, select')
71
+ .off('.abide')
72
+ .on('blur.fndtn.abide change.fndtn.abide', function (e) {
73
+ self.validate([this], e);
74
+ })
75
+ .on('keydown.fndtn.abide', function (e) {
76
+ var settings = $(this).closest('form').data('abide-init');
77
+ if (settings.live_validate === true) {
78
+ clearTimeout(self.timer);
79
+ self.timer = setTimeout(function () {
80
+ self.validate([this], e);
81
+ }.bind(this), settings.timeout);
82
+ }
83
+ });
84
+ },
85
+
86
+ reset : function (form) {
87
+ form.removeAttr(this.invalid_attr);
88
+ $(this.invalid_attr, form).removeAttr(this.invalid_attr);
89
+ $('.error', form).not('small').removeClass('error');
90
+ },
91
+
92
+ validate : function (els, e, is_ajax) {
93
+ var validations = this.parse_patterns(els),
94
+ validation_count = validations.length,
95
+ form = this.S(els[0]).closest('form'),
96
+ submit_event = /submit/.test(e.type);
97
+
98
+ // Has to count up to make sure the focus gets applied to the top error
99
+ for (var i=0; i < validation_count; i++) {
100
+ if (!validations[i] && (submit_event || is_ajax)) {
101
+ if (this.settings.focus_on_invalid) els[i].focus();
102
+ form.trigger('invalid');
103
+ this.S(els[i]).closest('form').attr(this.invalid_attr, '');
104
+ return false;
105
+ }
106
+ }
107
+
108
+ if (submit_event || is_ajax) {
109
+ form.trigger('valid');
110
+ }
111
+
112
+ form.removeAttr(this.invalid_attr);
113
+
114
+ if (is_ajax) return false;
115
+
116
+ return true;
117
+ },
118
+
119
+ parse_patterns : function (els) {
120
+ var i = els.length,
121
+ el_patterns = [];
122
+
123
+ while (i--) {
124
+ el_patterns.push(this.pattern(els[i]));
125
+ }
126
+
127
+ return this.check_validation_and_apply_styles(el_patterns);
128
+ },
129
+
130
+ pattern : function (el) {
131
+ var type = el.getAttribute('type'),
132
+ required = typeof el.getAttribute('required') === 'string';
133
+
134
+ var pattern = el.getAttribute('pattern') || '';
135
+
136
+ if (this.settings.patterns.hasOwnProperty(pattern) && pattern.length > 0) {
137
+ return [el, this.settings.patterns[pattern], required];
138
+ } else if (pattern.length > 0) {
139
+ return [el, new RegExp(pattern), required];
140
+ }
141
+
142
+ if (this.settings.patterns.hasOwnProperty(type)) {
143
+ return [el, this.settings.patterns[type], required];
144
+ }
145
+
146
+ pattern = /.*/;
147
+
148
+ return [el, pattern, required];
149
+ },
150
+
151
+ check_validation_and_apply_styles : function (el_patterns) {
152
+ var i = el_patterns.length,
153
+ validations = [];
154
+
155
+ while (i--) {
156
+ var el = el_patterns[i][0],
157
+ required = el_patterns[i][2],
158
+ value = el.value,
159
+ direct_parent = this.S(el).parent(),
160
+ is_equal = el.getAttribute(this.add_namespace('data-equalto')),
161
+ is_radio = el.type === "radio",
162
+ is_checkbox = el.type === "checkbox",
163
+ label = this.S('label[for="' + el.getAttribute('id') + '"]'),
164
+ valid_length = (required) ? (el.value.length > 0) : true;
165
+
166
+ var parent;
167
+
168
+ if (!direct_parent.is('label')) {
169
+ parent = direct_parent;
170
+ } else {
171
+ parent = direct_parent.parent();
172
+ }
173
+
174
+ if (is_radio && required) {
175
+ validations.push(this.valid_radio(el, required));
176
+ } else if (is_checkbox && required) {
177
+ validations.push(this.valid_checkbox(el, required));
178
+ } else if (is_equal && required) {
179
+ validations.push(this.valid_equal(el, required, parent));
180
+ } else {
181
+
182
+ if (el_patterns[i][1].test(value) && valid_length ||
183
+ !required && el.value.length < 1) {
184
+ this.S(el).removeAttr(this.invalid_attr);
185
+ parent.removeClass('error');
186
+ if (label.length > 0 && this.settings.error_labels) label.removeClass('error');
187
+
188
+ validations.push(true);
189
+ $(el).triggerHandler('valid');
190
+ } else {
191
+ this.S(el).attr(this.invalid_attr, '');
192
+ parent.addClass('error');
193
+ if (label.length > 0 && this.settings.error_labels) label.addClass('error');
194
+
195
+ validations.push(false);
196
+ $(el).triggerHandler('invalid');
197
+ }
198
+ }
199
+ }
200
+
201
+ return validations;
202
+ },
203
+
204
+ valid_checkbox : function(el, required) {
205
+ var el = this.S(el),
206
+ valid = (el.is(':checked') || !required);
207
+
208
+ if (valid) {
209
+ el.removeAttr(this.invalid_attr).parent().removeClass('error');
210
+ } else {
211
+ el.attr(this.invalid_attr, '').parent().addClass('error');
212
+ }
213
+
214
+ return valid;
215
+ },
216
+
217
+ valid_radio : function (el, required) {
218
+ var name = el.getAttribute('name'),
219
+ group = document.getElementsByName(name),
220
+ count = group.length,
221
+ valid = false;
222
+
223
+ // Has to count up to make sure the focus gets applied to the top error
224
+ for (var i=0; i < count; i++) {
225
+ if (group[i].checked) valid = true;
226
+ }
227
+
228
+ // Has to count up to make sure the focus gets applied to the top error
229
+ for (var i=0; i < count; i++) {
230
+ if (valid) {
231
+ this.S(group[i]).removeAttr(this.invalid_attr).parent().removeClass('error');
232
+ } else {
233
+ this.S(group[i]).attr(this.invalid_attr, '').parent().addClass('error');
234
+ }
235
+ }
236
+
237
+ return valid;
238
+ },
239
+
240
+ valid_equal: function(el, required, parent) {
241
+ var from = document.getElementById(el.getAttribute(this.add_namespace('data-equalto'))).value,
242
+ to = el.value,
243
+ valid = (from === to);
244
+
245
+ if (valid) {
246
+ this.S(el).removeAttr(this.invalid_attr);
247
+ parent.removeClass('error');
248
+ } else {
249
+ this.S(el).attr(this.invalid_attr, '');
250
+ parent.addClass('error');
251
+ }
252
+
253
+ return valid;
254
+ }
255
+ };
256
+ }(jQuery, this, this.document));
@@ -0,0 +1,49 @@
1
+ ;(function ($, window, document, undefined) {
2
+ 'use strict';
3
+
4
+ Foundation.libs.accordion = {
5
+ name : 'accordion',
6
+
7
+ version : '5.1.1',
8
+
9
+ settings : {
10
+ active_class: 'active',
11
+ toggleable: true
12
+ },
13
+
14
+ init : function (scope, method, options) {
15
+ this.bindings(method, options);
16
+ },
17
+
18
+ events : function () {
19
+ var self = this;
20
+ var S = this.S;
21
+ S(this.scope)
22
+ .off('.fndtn.accordion')
23
+ .on('click.fndtn.accordion', '[' + this.attr_name() + '] > dd > a', function (e) {
24
+ var accordion = S(this).closest('[' + self.attr_name() + ']'),
25
+ target = S('#' + this.href.split('#')[1]),
26
+ siblings = S('dd > .content', accordion),
27
+ aunts = $('> dd', accordion),
28
+ settings = accordion.data(self.attr_name(true) + '-init'),
29
+ active_content = S('dd > .content.' + settings.active_class, accordion),
30
+ active_parent = S('dd.' + settings.active_class, accordion);
31
+
32
+ e.preventDefault();
33
+
34
+ if (active_content[0] == target[0] && settings.toggleable) {
35
+ active_parent.toggleClass(settings.active_class, false);
36
+ return target.toggleClass(settings.active_class, false);
37
+ }
38
+
39
+ siblings.removeClass(settings.active_class);
40
+ aunts.removeClass(settings.active_class);
41
+ target.addClass(settings.active_class).parent().addClass(settings.active_class);
42
+ });
43
+ },
44
+
45
+ off : function () {},
46
+
47
+ reflow : function () {}
48
+ };
49
+ }(jQuery, this, this.document));
@@ -0,0 +1,37 @@
1
+ ;(function ($, window, document, undefined) {
2
+ 'use strict';
3
+
4
+ Foundation.libs.alert = {
5
+ name : 'alert',
6
+
7
+ version : '5.1.1',
8
+
9
+ settings : {
10
+ animation: 'fadeOut',
11
+ speed: 300, // fade out speed
12
+ callback: function (){}
13
+ },
14
+
15
+ init : function (scope, method, options) {
16
+ this.bindings(method, options);
17
+ },
18
+
19
+ events : function () {
20
+ var self = this,
21
+ S = this.S;
22
+
23
+ $(this.scope).off('.alert').on('click.fndtn.alert', '[' + this.attr_name() + '] a.close', function (e) {
24
+ var alertBox = S(this).closest('[' + self.attr_name() + ']'),
25
+ settings = alertBox.data(self.attr_name(true) + '-init') || self.settings;
26
+
27
+ e.preventDefault();
28
+ alertBox[settings.animation](settings.speed, function () {
29
+ S(this).trigger('closed').remove();
30
+ settings.callback();
31
+ });
32
+ });
33
+ },
34
+
35
+ reflow : function () {}
36
+ };
37
+ }(jQuery, this, this.document));