/*jslint browser: true */ /*global $, WebSocket, jQuery */ var flower = (function () { "use strict"; var alertContainer = document.getElementById('alert-container'); function show_alert(message, type) { var wrapper = document.createElement('div'); wrapper.innerHTML = ` `; alertContainer.appendChild(wrapper); } function url_prefix() { var prefix = $('#url_prefix').val(); if (prefix) { prefix = prefix.replace(/\/+$/, ''); if (prefix.startsWith('/')) { return prefix; } else { return '/' + prefix; } } return ''; } //https://github.com/DataTables/DataTables/blob/1.10.11/media/js/jquery.dataTables.js#L14882 function htmlEscapeEntities(d) { return typeof d === 'string' ? d.replace(//g, '>').replace(/"/g, '"') : d; } function active_page(name) { var pathname = $(location).attr('pathname'); if (name === '/') { return pathname === (url_prefix() + name); } else { return pathname.startsWith(url_prefix() + name); } } $('#worker-refresh').on('click', function (event) { event.preventDefault(); event.stopPropagation(); $('.dropdown-toggle').dropdown('hide'); var workername = $('#workername').text(); $.ajax({ type: 'GET', url: url_prefix() + '/api/workers', dataType: 'json', data: { workername: unescape(workername), refresh: 1 }, success: function (data) { show_alert(data.message || 'Successfully refreshed', 'success'); }, error: function (data) { show_alert(data.responseText, "danger"); } }); }); $('#worker-refresh-all').on('click', function (event) { event.preventDefault(); event.stopPropagation(); $('.dropdown-toggle').dropdown('hide'); $.ajax({ type: 'GET', url: url_prefix() + '/api/workers', dataType: 'json', data: { refresh: 1 }, success: function (data) { show_alert(data.message || 'Refreshed All Workers', 'success'); }, error: function (data) { show_alert(data.responseText, "danger"); } }); }); $('#worker-pool-restart').on('click', function (event) { event.preventDefault(); event.stopPropagation(); $('.dropdown-toggle').dropdown('hide'); var workername = $('#workername').text(); $.ajax({ type: 'POST', url: url_prefix() + '/api/worker/pool/restart/' + workername, dataType: 'json', data: { workername: workername }, success: function (data) { show_alert(data.message, "success"); }, error: function (data) { show_alert(data.responseText, "danger"); } }); }); $('#worker-shutdown').on('click', function (event) { event.preventDefault(); event.stopPropagation(); $('.dropdown-toggle').dropdown('hide'); var workername = $('#workername').text(); $.ajax({ type: 'POST', url: url_prefix() + '/api/worker/shutdown/' + workername, dataType: 'json', data: { workername: workername }, success: function (data) { show_alert(data.message, "success"); }, error: function (data) { show_alert(data.responseText, "danger"); } }); }); $('#worker-pool-grow').on('click', function (event) { event.preventDefault(); event.stopPropagation(); var workername = $('#workername').text(), grow_size = $('#pool-size option:selected').html(); $.ajax({ type: 'POST', url: url_prefix() + '/api/worker/pool/grow/' + workername, dataType: 'json', data: { 'workername': workername, 'n': grow_size, }, success: function (data) { show_alert(data.message, "success"); }, error: function (data) { show_alert(data.responseText, "danger"); } }); }); $('#worker-pool-shrink').on('click', function (event) { event.preventDefault(); event.stopPropagation(); var workername = $('#workername').text(), shrink_size = $('#pool-size option:selected').html(); $.ajax({ type: 'POST', url: url_prefix() + '/api/worker/pool/shrink/' + workername, dataType: 'json', data: { 'workername': workername, 'n': shrink_size, }, success: function (data) { show_alert(data.message, "success"); }, error: function (data) { show_alert(data.responseText, "danger"); } }); }); $('#worker-pool-autoscale').on('click', function (event) { event.preventDefault(); event.stopPropagation(); var workername = $('#workername').text(), min = $('#min-autoscale').val(), max = $('#max-autoscale').val(); $.ajax({ type: 'POST', url: url_prefix() + '/api/worker/pool/autoscale/' + workername, dataType: 'json', data: { 'workername': workername, 'min': min, 'max': max, }, success: function (data) { show_alert(data.message, "success"); }, error: function (data) { show_alert(data.responseText, "danger"); } }); }); $('#worker-add-consumer').on('click', function (event) { event.preventDefault(); event.stopPropagation(); var workername = $('#workername').text(), queue = $('#add-consumer-name').val(); $.ajax({ type: 'POST', url: url_prefix() + '/api/worker/queue/add-consumer/' + workername, dataType: 'json', data: { 'workername': workername, 'queue': queue, }, success: function (data) { show_alert(data.message, "success"); }, error: function (data) { show_alert(data.responseText, "danger"); } }); }); $('#worker-queues').on('click', function (event) { event.preventDefault(); event.stopPropagation(); if (!event.target.id.startsWith("worker-cancel-consumer")) { return; } var workername = $('#workername').text(), queue = $(event.target).closest("tr").children("td:eq(0)").text(); $.ajax({ type: 'POST', url: url_prefix() + '/api/worker/queue/cancel-consumer/' + workername, dataType: 'json', data: { 'workername': workername, 'queue': queue, }, success: function (data) { show_alert(data.message, "success"); }, error: function (data) { show_alert(data.responseText, "danger"); } }); }); $('#limits-table').on('click', function (event) { if (event.target.id.startsWith("task-timeout-")) { var timeout = parseInt($(event.target).siblings().closest("input").val()), type = $(event.target).text().toLowerCase(), taskname = $(event.target).closest("tr").children("td:eq(0)").text(), post_data = {'workername': $('#workername').text()}; taskname = taskname.split(' ')[0]; // removes [rate_limit=xxx] post_data[type] = timeout; if (!Number.isInteger(timeout)) { show_alert("Invalid timeout value", "danger"); return; } $.ajax({ type: 'POST', url: url_prefix() + '/api/task/timeout/' + taskname, dataType: 'json', data: post_data, success: function (data) { show_alert(data.message, "success"); }, error: function (data) { show_alert($(data.responseText).text(), "danger"); } }); } else if (event.target.id.startsWith("task-rate-limit-")) { var taskname = $(event.target).closest("tr").children("td:eq(0)").text(), workername = $('#workername').text(), ratelimit = parseInt($(event.target).prev().val()); taskname = taskname.split(' ')[0]; // removes [rate_limit=xxx] $.ajax({ type: 'POST', url: url_prefix() + '/api/task/rate-limit/' + taskname, dataType: 'json', data: { 'workername': workername, 'ratelimit': ratelimit, }, success: function (data) { show_alert(data.message, "success"); }, error: function (data) { show_alert(data.responseText, "danger"); } }); } }); $('#task-revoke').on('click', function (event) { event.preventDefault(); event.stopPropagation(); var taskid = $('#taskid').text(); $.ajax({ type: 'POST', url: url_prefix() + '/api/task/revoke/' + taskid, dataType: 'json', data: { 'terminate': false, }, success: function (data) { show_alert(data.message, "success"); document.getElementById("task-revoke").disabled = true; setTimeout(function() {location.reload();}, 5000); }, error: function (data) { show_alert(data.responseText, "danger"); } }); }); $('#task-terminate').on('click', function (event) { event.preventDefault(); event.stopPropagation(); var taskid = $('#taskid').text(); $.ajax({ type: 'POST', url: url_prefix() + '/api/task/revoke/' + taskid, dataType: 'json', data: { 'terminate': true, }, success: function (data) { show_alert(data.message, "success"); document.getElementById("task-terminate").disabled = true; setTimeout(function() {location.reload();}, 5000); }, error: function (data) { show_alert(data.responseText, "danger"); } }); }); function sum(a, b) { return parseInt(a, 10) + parseInt(b, 10); } function format_time(timestamp) { var time = $('#time').val(), prefix = time.startsWith('natural-time') ? 'natural-time' : 'time', tz = time.substr(prefix.length + 1) || 'UTC'; if (prefix === 'natural-time') { return moment.unix(timestamp).tz(tz).fromNow(); } return moment.unix(timestamp).tz(tz).format('YYYY-MM-DD HH:mm:ss.SSS'); } function isColumnVisible(name) { var columns = $('#columns').val(); if (columns === "all") return true; if (columns) { columns = columns.split(',').map(function (e) { return e.trim(); }); return columns.indexOf(name) !== -1; } return true; } $.urlParam = function (name) { var results = new RegExp('[\\?&]' + name + '=([^&#]*)').exec(window.location.href); return (results && results[1]) || 0; }; $(document).ready(function () { //https://github.com/twitter/bootstrap/issues/1768 var shiftWindow = function () { scrollBy(0, -50); }; if (location.hash) { shiftWindow(); } window.addEventListener("hashchange", shiftWindow); // Make bootstrap tabs persistent $(document).ready(function () { if (location.hash !== '') { $('a[href="' + location.hash + '"]').tab('show'); } // Listen for tab shown events and update the URL hash fragment accordingly $('.nav-tabs a[data-bs-toggle="tab"]').on('shown.bs.tab', function (event) { const tabPaneId = $(event.target).attr('href').substr(1); if (tabPaneId) { window.location.hash = tabPaneId; } }); }); }); $(document).ready(function () { if (!active_page('/') && !active_page('/workers')) { return; } $('#workers-table').DataTable({ rowId: 'name', searching: true, select: false, paging: true, scrollCollapse: true, lengthMenu: [15, 30, 50, 100], pageLength: 15, language: { lengthMenu: 'Show _MENU_ workers', info: 'Showing _START_ to _END_ of _TOTAL_ workers', infoFiltered: '(filtered from _MAX_ total workers)' }, ajax: url_prefix() + '/workers?json=1', order: [ [1, "des"] ], footerCallback: function( tfoot, data, start, end, display ) { var api = this.api(); var columns = {2:"STARTED", 3:"", 4:"FAILURE", 5:"SUCCESS", 6:"RETRY"}; for (const [column, state] of Object.entries(columns)) { var total = api.column(column).data().reduce(sum, 0); var footer = total; if (total !== 0) { let queryParams = (state !== '' ? `?state=${state}` : ''); footer = '' + total + ''; } $(api.column(column).footer()).html(footer); } }, columnDefs: [{ targets: 0, data: 'hostname', type: 'natural', render: function (data, type, full, meta) { return '' + data + ''; } }, { targets: 1, data: 'status', className: "text-center", width: "10%", render: function (data, type, full, meta) { if (data) { return 'Online'; } else { return 'Offline'; } } }, { targets: 2, data: 'active', className: "text-center", width: "10%", defaultContent: 0 }, { targets: 3, data: 'task-received', className: "text-center", width: "10%", defaultContent: 0 }, { targets: 4, data: 'task-failed', className: "text-center", width: "10%", defaultContent: 0 }, { targets: 5, data: 'task-succeeded', className: "text-center", width: "10%", defaultContent: 0 }, { targets: 6, data: 'task-retried', className: "text-center", width: "10%", defaultContent: 0 }, { targets: 7, data: 'loadavg', width: "10%", className: "text-center text-nowrap", render: function (data, type, full, meta) { if (!full.status) { return 'N/A'; } if (Array.isArray(data)) { return data.join(', '); } return data; } }, ], }); var autorefresh_interval = $.urlParam('autorefresh') || 1; if (autorefresh !== 0) { setInterval( function () { $('#workers-table').DataTable().ajax.reload(null, false); }, autorefresh_interval * 1000); } }); $(document).ready(function () { if (!active_page('/tasks')) { return; } $('#tasks-table').DataTable({ rowId: 'uuid', searching: true, scrollX: true, scrollCollapse: true, processing: true, serverSide: true, colReorder: true, lengthMenu: [15, 30, 50, 100], pageLength: 15, language: { lengthMenu: 'Show _MENU_ tasks', info: 'Showing _START_ to _END_ of _TOTAL_ tasks', infoFiltered: '(filtered from _MAX_ total tasks)' }, ajax: { type: 'POST', url: url_prefix() + '/tasks/datatable' }, order: [ [7, "desc"] ], oSearch: { "sSearch": $.urlParam('state') ? 'state:' + $.urlParam('state') : '' }, columnDefs: [{ targets: 0, data: 'name', visible: isColumnVisible('name'), render: function (data, type, full, meta) { return data; } }, { targets: 1, data: 'uuid', visible: isColumnVisible('uuid'), orderable: false, className: "text-nowrap", render: function (data, type, full, meta) { return '' + data + ''; } }, { targets: 2, data: 'state', visible: isColumnVisible('state'), className: "text-center", render: function (data, type, full, meta) { switch (data) { case 'SUCCESS': return '' + data + ''; case 'FAILURE': return '' + data + ''; default: return '' + data + ''; } } }, { targets: 3, data: 'args', className: "text-nowrap overflow-auto", visible: isColumnVisible('args'), render: htmlEscapeEntities }, { targets: 4, data: 'kwargs', className: "text-nowrap overflow-auto", visible: isColumnVisible('kwargs'), render: htmlEscapeEntities }, { targets: 5, data: 'result', visible: isColumnVisible('result'), className: "text-nowrap overflow-auto", render: htmlEscapeEntities }, { targets: 6, data: 'received', className: "text-nowrap", visible: isColumnVisible('received'), render: function (data, type, full, meta) { if (data) { return format_time(data); } return data; } }, { targets: 7, data: 'started', className: "text-nowrap", visible: isColumnVisible('started'), render: function (data, type, full, meta) { if (data) { return format_time(data); } return data; } }, { targets: 8, data: 'runtime', className: "text-center", visible: isColumnVisible('runtime'), render: function (data, type, full, meta) { return data ? data.toFixed(2) : data; } }, { targets: 9, data: 'worker', visible: isColumnVisible('worker'), render: function (data, type, full, meta) { return '' + data + ''; } }, { targets: 10, data: 'exchange', visible: isColumnVisible('exchange') }, { targets: 11, data: 'routing_key', visible: isColumnVisible('routing_key') }, { targets: 12, data: 'retries', className: "text-center", visible: isColumnVisible('retries') }, { targets: 13, data: 'revoked', className: "text-nowrap", visible: isColumnVisible('revoked'), render: function (data, type, full, meta) { if (data) { return format_time(data); } return data; } }, { targets: 14, data: 'exception', className: "text-nowrap", visible: isColumnVisible('exception') }, { targets: 15, data: 'expires', visible: isColumnVisible('expires') }, { targets: 16, data: 'eta', visible: isColumnVisible('eta') }, ], }); }); }(jQuery));