diff --git a/assets/js/src/help/cron_status.jsx b/assets/js/src/help/cron_status.jsx index 80b268ab74..73c6a15e44 100644 --- a/assets/js/src/help/cron_status.jsx +++ b/assets/js/src/help/cron_status.jsx @@ -13,7 +13,7 @@ function renderStatusTableRow(title, value) { const CronStatus = (props) => { const status = props.status_data; const activeStatusMapping = { - active: MailPoet.I18n.t('cronRunning'), + active: MailPoet.I18n.t('running'), inactive: MailPoet.I18n.t('cronWaiting'), }; return ( @@ -41,7 +41,7 @@ const CronStatus = (props) => { MailPoet.I18n.t('lastRunCompleted'), status.run_completed_at ? MailPoet.Date.full(status.run_completed_at * 1000) : MailPoet.I18n.t('unknown')) } - {renderStatusTableRow(MailPoet.I18n.t('lastSeenError'), status.last_error || '-')} + {renderStatusTableRow(MailPoet.I18n.t('lastSeenError'), status.last_error || MailPoet.I18n.t('none'))} diff --git a/assets/js/src/help/queue_status.jsx b/assets/js/src/help/queue_status.jsx new file mode 100644 index 0000000000..b0f0064f4d --- /dev/null +++ b/assets/js/src/help/queue_status.jsx @@ -0,0 +1,91 @@ +import MailPoet from 'mailpoet'; +import React from 'react'; + +function renderStatusTableRow(title, value) { + return ( + + { title }{ value } + + ); +} + +const QueueStatus = (props) => { + const status = props.status_data; + return ( +
+

{MailPoet.I18n.t('systemStatusQueueTitle')}

+ + + {renderStatusTableRow( + MailPoet.I18n.t('status'), + status.status === 'paused' ? MailPoet.I18n.t('paused') : MailPoet.I18n.t('running')) + } + {renderStatusTableRow( + MailPoet.I18n.t('startedAt'), + status.started ? MailPoet.Date.full(status.started * 1000) : MailPoet.I18n.t('unknown')) + } + {renderStatusTableRow( + MailPoet.I18n.t('sentEmails'), + status.sent || 0) + } + {renderStatusTableRow( + MailPoet.I18n.t('retryAttempts'), + status.retry_attempt || MailPoet.I18n.t('none')) + } + {renderStatusTableRow( + MailPoet.I18n.t('retryAt'), + status.retry_at ? MailPoet.Date.full(status.retry_at * 1000) : MailPoet.I18n.t('none')) + } + {renderStatusTableRow( + MailPoet.I18n.t('error'), + status.error || MailPoet.I18n.t('none')) + } + {renderStatusTableRow( + MailPoet.I18n.t('totalCompletedTasks'), + status.tasksStatusCounts.completed) + } + {renderStatusTableRow( + MailPoet.I18n.t('totalRunningTasks'), + status.tasksStatusCounts.running) + } + {renderStatusTableRow( + MailPoet.I18n.t('totalPausedTasks'), + status.tasksStatusCounts.paused) + } + {renderStatusTableRow( + MailPoet.I18n.t('totalScheduledTasks'), + status.tasksStatusCounts.scheduled) + } + +
+
+ ); +}; + +QueueStatus.propTypes = { + status_data: React.PropTypes.shape({ + status: React.PropTypes.string, + started: React.PropTypes.number, + sent: React.PropTypes.number, + retry_attempt: React.PropTypes.number, + retry_at: React.PropTypes.number, + tasksStatusCounts: React.PropTypes.shape({ + completed: React.PropTypes.number.isRequired, + running: React.PropTypes.number.isRequired, + paused: React.PropTypes.number.isRequired, + scheduled: React.PropTypes.number.isRequired, + }).isRequired, + }).isRequired, +}; + +QueueStatus.defaultProps = { + status_data: { + status: null, + started: null, + sent: null, + retry_attempt: null, + retry_at: null, + }, +}; + +module.exports = QueueStatus; diff --git a/assets/js/src/help/system_status.jsx b/assets/js/src/help/system_status.jsx index 7eb7f7b8cc..943c5009f1 100644 --- a/assets/js/src/help/system_status.jsx +++ b/assets/js/src/help/system_status.jsx @@ -2,6 +2,7 @@ import MailPoet from 'mailpoet'; import React from 'react'; import ReactStringReplace from 'react-string-replace'; import CronStatus from './cron_status.jsx'; +import QueueStatus from './queue_status.jsx'; import Tabs from './tabs.jsx'; function renderStatusMessage(status, error, link) { @@ -67,6 +68,7 @@ function SystemStatus() { {renderCronSection(systemStatusData)} {renderMSSSection(systemStatusData)} + ); } diff --git a/lib/Config/Menu.php b/lib/Config/Menu.php index 97f168d3f7..6892703c2e 100644 --- a/lib/Config/Menu.php +++ b/lib/Config/Menu.php @@ -9,8 +9,10 @@ use MailPoet\Form\Block; use MailPoet\Form\Renderer as FormRenderer; use MailPoet\Helpscout\Beacon; use MailPoet\Listing; +use MailPoet\Mailer\MailerLog; use MailPoet\Models\CustomField; use MailPoet\Models\Form; +use MailPoet\Models\ScheduledTask; use MailPoet\Models\Segment; use MailPoet\Models\Setting; use MailPoet\Models\Subscriber; @@ -20,6 +22,7 @@ use MailPoet\Services\Bridge; use MailPoet\Settings\Hosts; use MailPoet\Settings\Pages; use MailPoet\Subscribers\ImportExport\ImportExportFactory; +use MailPoet\Tasks\State; use MailPoet\Util\License\Features\Subscribers as SubscribersFeature; use MailPoet\Util\License\License; use MailPoet\WP\DateTime; @@ -447,6 +450,7 @@ class Menu { function help() { + $tasks_state = new State(); $system_info_data = Beacon::getData(); $system_status_data = [ 'cron' => [ @@ -459,8 +463,10 @@ class Menu { false ], 'cronStatus' => CronHelper::getDaemon(), + 'queueStatus' => MailerLog::getMailerLog(), ]; $system_status_data['cronStatus']['accessible'] = CronHelper::isDaemonAccessible(); + $system_status_data['queueStatus']['tasksStatusCounts'] = $tasks_state->getCountsPerStatus(); $this->displayPage( 'help.html', array( diff --git a/lib/Models/ScheduledTask.php b/lib/Models/ScheduledTask.php index 525f896ce1..9dbc38558e 100644 --- a/lib/Models/ScheduledTask.php +++ b/lib/Models/ScheduledTask.php @@ -11,6 +11,7 @@ class ScheduledTask extends Model { const STATUS_COMPLETED = 'completed'; const STATUS_SCHEDULED = 'scheduled'; const STATUS_PAUSED = 'paused'; + const VIRTUAL_STATUS_RUNNING = 'running'; // For historical reasons this is stored as null in DB const PRIORITY_HIGH = 1; const PRIORITY_MEDIUM = 5; const PRIORITY_LOW = 10; diff --git a/lib/Tasks/State.php b/lib/Tasks/State.php new file mode 100644 index 0000000000..fb0a2b14b2 --- /dev/null +++ b/lib/Tasks/State.php @@ -0,0 +1,35 @@ + 0, + ScheduledTask::STATUS_PAUSED => 0, + ScheduledTask::STATUS_SCHEDULED => 0, + ScheduledTask::VIRTUAL_STATUS_RUNNING => 0, + ]; + $counts = ScheduledTask::rawQuery( + "SELECT COUNT(*) as value, status + FROM `" . ScheduledTask::$_table . "` + WHERE deleted_at IS NULL AND `type` = 'sending' + GROUP BY status;" + )->findMany(); + foreach($counts as $count) { + if($count->status === null) { + $stats[ScheduledTask::VIRTUAL_STATUS_RUNNING] = (int)$count->value; + continue; + } + $stats[$count->status] = (int)$count->value; + } + return $stats; + } +} diff --git a/views/help.html b/views/help.html index 1d9c7b9f2f..cfc222bf49 100644 --- a/views/help.html +++ b/views/help.html @@ -34,6 +34,7 @@ 'systemInfoIntro': __('The information below is useful when you need to get in touch with our support. Just copy all the text below and paste it into a message to us.'), 'systemInfoDataError': __('Sorry, there was an error, please try again later.'), 'systemStatusCronStatusTitle': __('Cron'), + 'systemStatusQueueTitle': __('Sending Queue'), 'lastUpdated': __('Last updated'), 'lastRunStarted': __('Last run started'), 'lastRunCompleted': __('Last run completed'), @@ -43,8 +44,18 @@ 'status': __('Status'), 'yes': __('yes'), 'no': __('no'), - 'cronRunning': __('running'), + 'none': __('none'), + 'running': __('running'), 'cronWaiting': __('waiting for the next run'), + 'startedAt': __('Started at'), + 'sentEmails': __('Sent emails'), + 'retryAttempt': __('Retry attempt'), + 'retryAt': __('Retry at'), + 'error': __('Error'), + 'totalCompletedTasks': __('Total completed tasks'), + 'totalScheduledTasks': __('Total scheduled tasks'), + 'totalRunningTasks': __('Total running tasks'), + 'totalPausedTasks': __('Total paused tasks'), }) %> <% endblock %>