You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

357 lines
11 KiB

10 years ago
10 years ago
9 years ago
10 years ago
  1. $(function () {
  2. $(".my-checks-name").click(function() {
  3. $("#update-name-form").attr("action", this.dataset.url);
  4. $("#update-name-input").val(this.dataset.name);
  5. $("#update-tags-input").val(this.dataset.tags);
  6. $('#update-name-modal').modal("show");
  7. $("#update-name-input").focus();
  8. return false;
  9. });
  10. var MINUTE = {name: "minute", nsecs: 60};
  11. var HOUR = {name: "hour", nsecs: MINUTE.nsecs * 60};
  12. var DAY = {name: "day", nsecs: HOUR.nsecs * 24};
  13. var WEEK = {name: "week", nsecs: DAY.nsecs * 7};
  14. var UNITS = [WEEK, DAY, HOUR, MINUTE];
  15. var secsToText = function(total) {
  16. var remainingSeconds = Math.floor(total);
  17. var result = "";
  18. for (var i=0, unit; unit=UNITS[i]; i++) {
  19. if (unit === WEEK && remainingSeconds % unit.nsecs != 0) {
  20. // Say "8 days" instead of "1 week 1 day"
  21. continue
  22. }
  23. var count = Math.floor(remainingSeconds / unit.nsecs);
  24. remainingSeconds = remainingSeconds % unit.nsecs;
  25. if (count == 1) {
  26. result += "1 " + unit.name + " ";
  27. }
  28. if (count > 1) {
  29. result += count + " " + unit.name + "s ";
  30. }
  31. }
  32. return result;
  33. }
  34. var periodSlider = document.getElementById("period-slider");
  35. noUiSlider.create(periodSlider, {
  36. start: [20],
  37. connect: "lower",
  38. range: {
  39. 'min': [60, 60],
  40. '33%': [3600, 3600],
  41. '66%': [86400, 86400],
  42. '83%': [604800, 604800],
  43. 'max': 2592000,
  44. },
  45. pips: {
  46. mode: 'values',
  47. values: [60, 1800, 3600, 43200, 86400, 604800, 2592000],
  48. density: 4,
  49. format: {
  50. to: secsToText,
  51. from: function() {}
  52. }
  53. }
  54. });
  55. periodSlider.noUiSlider.on("update", function(a, b, value) {
  56. var rounded = Math.round(value);
  57. $("#period-slider-value").text(secsToText(rounded));
  58. $("#update-timeout-timeout").val(rounded);
  59. });
  60. var graceSlider = document.getElementById("grace-slider");
  61. noUiSlider.create(graceSlider, {
  62. start: [20],
  63. connect: "lower",
  64. range: {
  65. 'min': [60, 60],
  66. '33%': [3600, 3600],
  67. '66%': [86400, 86400],
  68. '83%': [604800, 604800],
  69. 'max': 2592000,
  70. },
  71. pips: {
  72. mode: 'values',
  73. values: [60, 1800, 3600, 43200, 86400, 604800, 2592000],
  74. density: 4,
  75. format: {
  76. to: secsToText,
  77. from: function() {}
  78. }
  79. }
  80. });
  81. graceSlider.noUiSlider.on("update", function(a, b, value) {
  82. var rounded = Math.round(value);
  83. $("#grace-slider-value").text(secsToText(rounded));
  84. $("#update-timeout-grace").val(rounded);
  85. });
  86. function showSimple() {
  87. $("#update-timeout-form").show();
  88. $("#update-cron-form").hide();
  89. }
  90. function showCron() {
  91. $("#update-timeout-form").hide();
  92. $("#update-cron-form").show();
  93. }
  94. var currentPreviewHash = "";
  95. function updateCronPreview() {
  96. var schedule = $("#schedule").val();
  97. var tz = $("#tz").val();
  98. var hash = schedule + tz;
  99. // Don't try preview with empty values, or if values have not changed
  100. if (!schedule || !tz || hash == currentPreviewHash)
  101. return;
  102. // OK, we're good
  103. currentPreviewHash = hash;
  104. $("#cron-preview-title").text("Updating...");
  105. var token = $('input[name=csrfmiddlewaretoken]').val();
  106. $.ajax({
  107. url: "/checks/cron_preview/",
  108. type: "post",
  109. headers: {"X-CSRFToken": token},
  110. data: {schedule: schedule, tz: tz},
  111. success: function(data) {
  112. if (hash != currentPreviewHash) {
  113. return; // ignore stale results
  114. }
  115. $("#cron-preview" ).html(data);
  116. var haveError = $("#invalid-arguments").size() > 0;
  117. $("#update-cron-submit").prop("disabled", haveError);
  118. }
  119. });
  120. }
  121. $(".timeout-grace").click(function() {
  122. $("#update-timeout-form").attr("action", this.dataset.url);
  123. $("#update-cron-form").attr("action", this.dataset.url);
  124. // Simple
  125. periodSlider.noUiSlider.set(this.dataset.timeout);
  126. graceSlider.noUiSlider.set(this.dataset.grace);
  127. // Cron
  128. currentPreviewHash = "";
  129. $("#cron-preview").html("<p>Updating...</p>");
  130. $("#schedule").val(this.dataset.schedule);
  131. document.getElementById("tz").selectize.setValue(this.dataset.tz);
  132. var minutes = parseInt(this.dataset.grace / 60);
  133. $("#update-timeout-grace-cron").val(minutes);
  134. updateCronPreview();
  135. this.dataset.kind == "simple" ? showSimple() : showCron();
  136. $('#update-timeout-modal').modal({"show":true, "backdrop":"static"});
  137. return false;
  138. });
  139. // Wire up events for Timeout/Cron forms
  140. $(".kind-simple").click(showSimple);
  141. $(".kind-cron").click(showCron);
  142. $("#schedule").on("keyup", updateCronPreview);
  143. $("#tz").selectize({onChange: updateCronPreview});
  144. $(".check-menu-remove").click(function() {
  145. $("#remove-check-form").attr("action", this.dataset.url);
  146. $(".remove-check-name").text(this.dataset.name);
  147. $('#remove-check-modal').modal("show");
  148. return false;
  149. });
  150. $(".last-ping-cell").on("click", ".last-ping", function() {
  151. $("#ping-details-body").text("Updating...");
  152. $('#ping-details-modal').modal("show");
  153. var token = $('input[name=csrfmiddlewaretoken]').val();
  154. $.ajax({
  155. url: this.dataset.url,
  156. type: "post",
  157. headers: {"X-CSRFToken": token},
  158. success: function(data) {
  159. $("#ping-details-body" ).html(data);
  160. }
  161. });
  162. return false;
  163. });
  164. $("#my-checks-tags button").click(function() {
  165. // .active has not been updated yet by bootstrap code,
  166. // so cannot use it
  167. $(this).toggleClass('checked');
  168. // Make a list of currently checked tags:
  169. var checked = [];
  170. $("#my-checks-tags button.checked").each(function(index, el) {
  171. checked.push(el.textContent);
  172. });
  173. // No checked tags: show all
  174. if (checked.length == 0) {
  175. $("#checks-table tr.checks-row").show();
  176. $("#checks-list > li").show();
  177. return;
  178. }
  179. function applyFilters(index, element) {
  180. // use attr(), as data() tries converting strings to JS types:
  181. // (e.g., "123" -> 123)
  182. var tags = $(".my-checks-name", element).attr("data-tags").split(" ");
  183. for (var i=0, tag; tag=checked[i]; i++) {
  184. if (tags.indexOf(tag) == -1) {
  185. $(element).hide();
  186. return;
  187. }
  188. }
  189. $(element).show();
  190. }
  191. // Desktop: for each row, see if it needs to be shown or hidden
  192. $("#checks-table tr.checks-row").each(applyFilters);
  193. // Mobile: for each list item, see if it needs to be shown or hidden
  194. $("#checks-list > li").each(applyFilters);
  195. });
  196. $(".pause-check").click(function(e) {
  197. var url = e.target.getAttribute("data-url");
  198. $("#pause-form").attr("action", url).submit();
  199. return false;
  200. });
  201. $('[data-toggle="tooltip"]').tooltip({
  202. title: function() {
  203. var cssClasses = this.getAttribute("class");
  204. if (cssClasses.indexOf("icon-new") > -1)
  205. return "New. Has never received a ping.";
  206. if (cssClasses.indexOf("icon-paused") > -1)
  207. return "Monitoring paused. Ping to resume.";
  208. }
  209. });
  210. $(".usage-examples").click(function(e) {
  211. var a = e.target;
  212. var url = a.getAttribute("data-url");
  213. var email = a.getAttribute("data-email");
  214. $(".ex", "#show-usage-modal").text(url);
  215. $(".em", "#show-usage-modal").text(email);
  216. $("#show-usage-modal").modal("show");
  217. return false;
  218. });
  219. // Auto-refresh
  220. var lastStatus = {};
  221. var lastPing = {};
  222. function refresh() {
  223. $.ajax({
  224. url: "/checks/status/",
  225. dataType: "json",
  226. timeout: 2000,
  227. success: function(data) {
  228. for(var i=0, el; el=data.details[i]; i++) {
  229. if (lastStatus[el.code] != el.status) {
  230. lastStatus[el.code] = el.status;
  231. $("#si-" + el.code).attr("class", "status icon-" + el.status);
  232. $("#sl-" + el.code).attr("class", "label label-" + el.status).text(el.status);
  233. $("#pause-li-" + el.code).toggleClass("disabled", el.status == "paused");
  234. }
  235. if (lastPing[el.code] != el.last_ping) {
  236. lastPing[el.code] = el.last_ping;
  237. $("#lpd-" + el.code).html(el.last_ping);
  238. $("#lpm-" + el.code).html(el.last_ping);
  239. }
  240. }
  241. $("#my-checks-tags button").each(function(a) {
  242. var status = data.tags[this.innerText];
  243. if (status) {
  244. this.setAttribute("class", "btn btn-xs " + status);
  245. }
  246. });
  247. }
  248. });
  249. }
  250. // unconditionally refresh every minute
  251. setInterval(refresh, 60000);
  252. // scheduleRefresh() keeps calling refresh() and decreasing quota
  253. // every 3 seconds, until quota runs out.
  254. var quota = 0;
  255. var scheduledId = null;
  256. function scheduleRefresh() {
  257. if (quota > 0) {
  258. quota -= 1;
  259. clearTimeout(scheduledId);
  260. scheduledId = setTimeout(scheduleRefresh, 3000);
  261. refresh();
  262. }
  263. }
  264. document.addEventListener("visibilitychange", function() {
  265. if (document.visibilityState == "visible") {
  266. // tab becomes visible: reset quota
  267. if (quota == 0) {
  268. quota = 20;
  269. scheduleRefresh();
  270. } else {
  271. quota = 20;
  272. }
  273. } else {
  274. // lost visibility, clear quota
  275. quota = 0;
  276. }
  277. });
  278. // user moves mouse: reset quota
  279. document.addEventListener("mousemove", function() {
  280. if (quota == 0) {
  281. quota = 20;
  282. scheduleRefresh();
  283. } else {
  284. quota = 20;
  285. }
  286. });
  287. // Copy to clipboard
  288. var clipboard = new Clipboard('button.copy-link');
  289. $("button.copy-link").mouseout(function(e) {
  290. setTimeout(function() {
  291. e.target.textContent = "copy";
  292. }, 300);
  293. })
  294. clipboard.on('success', function(e) {
  295. e.trigger.textContent = "copied!";
  296. e.clearSelection();
  297. });
  298. clipboard.on('error', function(e) {
  299. var text = e.trigger.getAttribute("data-clipboard-text");
  300. prompt("Press Ctrl+C to select:", text)
  301. });
  302. });