371 lines
14 KiB
PHTML
371 lines
14 KiB
PHTML
<?php
|
|
|
|
use MintyPHP\Session;
|
|
|
|
$job = is_array($job ?? null) ? $job : [];
|
|
$form = is_array($form ?? null) ? $form : [];
|
|
$canManage = (bool) ($canManage ?? false);
|
|
$canRunNow = (bool) ($canRunNow ?? false);
|
|
$jobId = (int) ($job['id'] ?? 0);
|
|
$readonlyAttr = $canManage ? '' : 'readonly';
|
|
$disabledAttr = $canManage ? '' : 'disabled';
|
|
$selectedWeekdays = array_map('intval', (array) ($form['schedule_weekdays'] ?? []));
|
|
$weekdayOptions = [
|
|
1 => t('Mon'),
|
|
2 => t('Tue'),
|
|
3 => t('Wed'),
|
|
4 => t('Thu'),
|
|
5 => t('Fri'),
|
|
6 => t('Sat'),
|
|
7 => t('Sun'),
|
|
];
|
|
$status = strtolower(trim((string) ($job['last_run_status'] ?? '')));
|
|
$scheduleSummary = (string) ($scheduleSummary ?? '-');
|
|
$statusVariant = 'neutral';
|
|
if ($status === 'success') {
|
|
$statusVariant = 'success';
|
|
} elseif ($status === 'failed') {
|
|
$statusVariant = 'danger';
|
|
} elseif ($status === 'running') {
|
|
$statusVariant = 'info';
|
|
} elseif ($status === 'skipped') {
|
|
$statusVariant = 'warning';
|
|
}
|
|
$asideActions = [];
|
|
if ($canRunNow) {
|
|
$asideActions[] = [
|
|
'type' => 'form',
|
|
'method' => 'post',
|
|
'action' => 'admin/scheduled-jobs/run/' . $jobId,
|
|
'label' => t('Run now'),
|
|
];
|
|
}
|
|
?>
|
|
|
|
<div class="app-details-container">
|
|
<section>
|
|
<?php
|
|
$breadcrumbs = [
|
|
['label' => t('Home'), 'path' => 'admin'],
|
|
['label' => t('Scheduled jobs'), 'path' => 'admin/scheduled-jobs'],
|
|
['label' => t('Edit')],
|
|
];
|
|
require templatePath('partials/app-breadcrumb.phtml');
|
|
|
|
$titlebar = [
|
|
'title' => t('Edit scheduled job'),
|
|
'backHref' => 'admin/scheduled-jobs',
|
|
'backTitle' => t('Back'),
|
|
'actions' => $canManage ? [
|
|
[
|
|
'form' => 'scheduled-job-form',
|
|
'name' => 'action',
|
|
'value' => 'save',
|
|
'class' => 'primary',
|
|
'label' => t('Save'),
|
|
],
|
|
] : [],
|
|
];
|
|
require templatePath('partials/app-details-titlebar.phtml');
|
|
?>
|
|
|
|
<div class="app-details-content">
|
|
<form method="post" id="scheduled-job-form" data-details-storage="scheduled-job-edit-v1">
|
|
<details open data-details-always-open>
|
|
<summary><?php e(t('Master data')); ?></summary>
|
|
<hr>
|
|
<div class="grid">
|
|
<label class="app-field">
|
|
<span><?php e(t('Enabled')); ?></span>
|
|
<select name="enabled" <?php e($disabledAttr); ?>>
|
|
<option value="1" <?php e(((int) ($form['enabled'] ?? 0) === 1) ? 'selected' : ''); ?>><?php e(t('Enabled')); ?></option>
|
|
<option value="0" <?php e(((int) ($form['enabled'] ?? 0) !== 1) ? 'selected' : ''); ?>><?php e(t('Disabled')); ?></option>
|
|
</select>
|
|
</label>
|
|
<label class="app-field">
|
|
<span><?php e(t('Timezone')); ?></span>
|
|
<input type="text" name="timezone" value="<?php e((string) ($form['timezone'] ?? '')); ?>" placeholder="<?php e((string) (defined('APP_TIMEZONE') ? APP_TIMEZONE : 'UTC')); ?>" <?php e($readonlyAttr); ?>>
|
|
</label>
|
|
</div>
|
|
</details>
|
|
|
|
<hr>
|
|
<details open>
|
|
<summary><?php e(t('Schedule')); ?></summary>
|
|
<hr>
|
|
<div class="grid">
|
|
<label class="app-field">
|
|
<span><?php e(t('Schedule type')); ?></span>
|
|
<select name="schedule_type" id="scheduled-job-schedule-type" <?php e($disabledAttr); ?>>
|
|
<option value="hourly" <?php e(((string) ($form['schedule_type'] ?? '') === 'hourly') ? 'selected' : ''); ?>><?php e(t('Hourly')); ?></option>
|
|
<option value="daily" <?php e(((string) ($form['schedule_type'] ?? '') === 'daily') ? 'selected' : ''); ?>><?php e(t('Daily')); ?></option>
|
|
<option value="weekly" <?php e(((string) ($form['schedule_type'] ?? '') === 'weekly') ? 'selected' : ''); ?>><?php e(t('Weekly')); ?></option>
|
|
</select>
|
|
</label>
|
|
<label class="app-field">
|
|
<span><?php e(t('Schedule interval')); ?></span>
|
|
<input type="number" min="1" max="365" name="schedule_interval" value="<?php e((string) ((int) ($form['schedule_interval'] ?? 1))); ?>" <?php e($readonlyAttr); ?>>
|
|
</label>
|
|
</div>
|
|
|
|
<label class="app-field" data-schedule-time-wrap>
|
|
<span><?php e(t('Schedule time')); ?></span>
|
|
<input type="time" name="schedule_time" value="<?php e((string) ($form['schedule_time'] ?? '')); ?>" <?php e($readonlyAttr); ?>>
|
|
</label>
|
|
|
|
<fieldset data-schedule-weekdays-wrap>
|
|
<legend><small><?php e(t('Weekdays')); ?></small></legend>
|
|
<div class="grid">
|
|
<?php foreach ($weekdayOptions as $weekdayValue => $weekdayLabel): ?>
|
|
<label class="app-field app-checkbox">
|
|
<input
|
|
type="checkbox"
|
|
name="schedule_weekdays[]"
|
|
value="<?php e((string) $weekdayValue); ?>"
|
|
<?php if (in_array((int) $weekdayValue, $selectedWeekdays, true)) { ?>checked<?php } ?>
|
|
<?php e($disabledAttr); ?>>
|
|
<span><?php e($weekdayLabel); ?></span>
|
|
</label>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</fieldset>
|
|
|
|
<label class="app-field app-checkbox">
|
|
<input type="checkbox" name="catchup_once" value="1" <?php if ((int) ($form['catchup_once'] ?? 0) === 1) { ?>checked<?php } ?> <?php e($disabledAttr); ?>>
|
|
<span><?php e(t('Catch up once')); ?></span>
|
|
</label>
|
|
</details>
|
|
|
|
<?php Session::getCsrfInput(); ?>
|
|
</form>
|
|
|
|
<hr>
|
|
<details>
|
|
<summary><?php e(t('Run history')); ?></summary>
|
|
<hr>
|
|
<div class="app-list-toolbar">
|
|
<label class="app-field">
|
|
<span><?php e(t('Search')); ?></span>
|
|
<input type="search" id="scheduled-job-runs-search" placeholder="<?php e(t('Search...')); ?>">
|
|
</label>
|
|
<label class="app-field">
|
|
<span><?php e(t('Status')); ?></span>
|
|
<select id="scheduled-job-runs-status-filter">
|
|
<option value=""><?php e(t('All statuses')); ?></option>
|
|
<option value="success"><?php e(t('Success')); ?></option>
|
|
<option value="failed"><?php e(t('Failed')); ?></option>
|
|
<option value="skipped"><?php e(t('Skipped')); ?></option>
|
|
</select>
|
|
</label>
|
|
<label class="app-field">
|
|
<span><?php e(t('Trigger')); ?></span>
|
|
<select id="scheduled-job-runs-trigger-filter">
|
|
<option value=""><?php e(t('All triggers')); ?></option>
|
|
<option value="scheduler"><?php e(t('Scheduler')); ?></option>
|
|
<option value="manual"><?php e(t('Manual')); ?></option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
<div class="app-list-table">
|
|
<div id="scheduled-job-runs-grid"></div>
|
|
</div>
|
|
</details>
|
|
</div>
|
|
</section>
|
|
|
|
<aside id="app-details-aside-section">
|
|
<div class="app-details-aside-section">
|
|
<hgroup>
|
|
<h2><?php e((string) ($job['label'] ?? $job['job_key'] ?? '')); ?></h2>
|
|
<p><?php e(t('Scheduled jobs')); ?></p>
|
|
</hgroup>
|
|
<div class="badge-list">
|
|
<span class="badge" data-variant="<?php e($statusVariant); ?>"><?php e($status !== '' ? t(ucfirst($status)) : '-'); ?></span>
|
|
</div>
|
|
<hr>
|
|
<?php
|
|
if ($asideActions) {
|
|
require templatePath('partials/app-details-aside-actions.phtml');
|
|
}
|
|
?>
|
|
<details name="scheduled-job-ids">
|
|
<summary><?php e(t('IDs')); ?></summary>
|
|
<hr>
|
|
<div>
|
|
<small><?php e(t('ID')); ?></small>
|
|
<p>
|
|
<span class="badge" data-variant="neutral" data-copy="true" data-copy-value="<?php e((string) ($job['id'] ?? '')); ?>">
|
|
<?php e((string) ($job['id'] ?? '-')); ?>
|
|
</span>
|
|
</p>
|
|
</div>
|
|
<div>
|
|
<small><?php e(t('Job key')); ?></small>
|
|
<p>
|
|
<span class="badge" data-variant="neutral" data-copy="true" data-copy-value="<?php e((string) ($job['job_key'] ?? '')); ?>">
|
|
<?php e((string) ($job['job_key'] ?? '-')); ?>
|
|
</span>
|
|
</p>
|
|
</div>
|
|
</details>
|
|
<hr>
|
|
<details name="scheduled-job-meta" open>
|
|
<summary><?php e(t('Status & meta')); ?></summary>
|
|
<hr>
|
|
<p><small><?php e(t('Description')); ?></small><br><?php e((string) ($job['description'] ?? '') !== '' ? (string) $job['description'] : '-'); ?></p>
|
|
<p><small><?php e(t('Schedule')); ?></small><br><?php e($scheduleSummary !== '' ? $scheduleSummary : '-'); ?></p>
|
|
<p><small><?php e(t('Timezone')); ?></small><br><?php e((string) ($job['timezone'] ?? '') !== '' ? (string) $job['timezone'] : '-'); ?></p>
|
|
<div>
|
|
<small><?php e(t('Status')); ?></small>
|
|
<p><?php e($status !== '' ? t(ucfirst($status)) : '-'); ?></p>
|
|
</div>
|
|
<p><small><?php e(t('Next run')); ?></small><br><?php e(dt((string) ($job['next_run_at'] ?? '')) ?: '-'); ?></p>
|
|
<p><small><?php e(t('Last run')); ?></small><br><?php e(dt((string) ($job['last_run_finished_at'] ?? '')) ?: '-'); ?></p>
|
|
<div>
|
|
<small><?php e(t('Last error')); ?></small>
|
|
<p><?php e(trim((string) ($job['last_error_code'] ?? '')) !== '' ? (string) $job['last_error_code'] : ((string) ($job['last_error_message'] ?? '') !== '' ? (string) $job['last_error_message'] : '-')); ?></p>
|
|
</div>
|
|
</details>
|
|
<hr>
|
|
<details name="scheduled-job-audit">
|
|
<summary><?php e(t('Audit')); ?></summary>
|
|
<hr>
|
|
<p><small><?php e(t('Created')); ?></small><br><?php e(dt((string) ($job['created_at'] ?? '')) ?: '-'); ?></p>
|
|
<p><small><?php e(t('Modified')); ?></small><br><?php e(dt((string) ($job['updated_at'] ?? '')) ?: '-'); ?></p>
|
|
</details>
|
|
</div>
|
|
</aside>
|
|
</div>
|
|
|
|
<script src="<?php e(asset('vendor/gridjs/gridjs.umd.js')); ?>"></script>
|
|
<script type="module">
|
|
import {
|
|
createServerGrid
|
|
} from "<?php e(assetVersion('js/core/app-grid-factory.js')); ?>";
|
|
import {
|
|
getAppBase
|
|
} from "<?php e(asset('js/pages/app-list-utils.js')); ?>";
|
|
|
|
const appBase = getAppBase();
|
|
const scheduleTypeInput = document.querySelector('#scheduled-job-schedule-type');
|
|
const scheduleTimeWrap = document.querySelector('[data-schedule-time-wrap]');
|
|
const scheduleWeekdaysWrap = document.querySelector('[data-schedule-weekdays-wrap]');
|
|
|
|
const updateScheduleVisibility = () => {
|
|
const type = (scheduleTypeInput?.value || 'daily').toLowerCase();
|
|
const showTime = type === 'daily' || type === 'weekly';
|
|
const showWeekdays = type === 'weekly';
|
|
if (scheduleTimeWrap) {
|
|
scheduleTimeWrap.hidden = !showTime;
|
|
}
|
|
if (scheduleWeekdaysWrap) {
|
|
scheduleWeekdaysWrap.hidden = !showWeekdays;
|
|
}
|
|
};
|
|
if (scheduleTypeInput) {
|
|
scheduleTypeInput.addEventListener('change', updateScheduleVisibility);
|
|
updateScheduleVisibility();
|
|
}
|
|
|
|
const statusLabel = (value) => {
|
|
const key = String(value || '').toLowerCase();
|
|
if (key === 'success') {
|
|
return "<?php e(t('Success')); ?>";
|
|
}
|
|
if (key === 'failed') {
|
|
return "<?php e(t('Failed')); ?>";
|
|
}
|
|
if (key === 'skipped') {
|
|
return "<?php e(t('Skipped')); ?>";
|
|
}
|
|
return key || '-';
|
|
};
|
|
const triggerLabel = (value) => {
|
|
const key = String(value || '').toLowerCase();
|
|
if (key === 'scheduler') {
|
|
return "<?php e(t('Scheduler')); ?>";
|
|
}
|
|
if (key === 'manual') {
|
|
return "<?php e(t('Manual')); ?>";
|
|
}
|
|
return key || '-';
|
|
};
|
|
|
|
createServerGrid({
|
|
gridjs: window.gridjs,
|
|
container: '#scheduled-job-runs-grid',
|
|
dataUrl: `admin/scheduled-jobs/runs-data/<?php e((string) $jobId); ?>`,
|
|
appBase,
|
|
columns: [{
|
|
name: "<?php e(t('Started')); ?>",
|
|
sort: true
|
|
},
|
|
{
|
|
name: "<?php e(t('Status')); ?>",
|
|
sort: true,
|
|
formatter: (cell) => {
|
|
if (!cell || typeof cell !== 'object') {
|
|
return gridjs.html('-');
|
|
}
|
|
return gridjs.html(`<span class="badge" data-variant="${cell.variant || 'neutral'}">${statusLabel(cell.label || '')}</span>`);
|
|
}
|
|
},
|
|
{
|
|
name: "<?php e(t('Trigger')); ?>",
|
|
sort: true,
|
|
formatter: (cell) => triggerLabel(cell)
|
|
},
|
|
{
|
|
name: "<?php e(t('Duration (ms)')); ?>",
|
|
sort: true,
|
|
formatter: (cell) => (Number(cell) > 0 ? `${cell}` : '-')
|
|
},
|
|
{
|
|
name: "<?php e(t('Error code')); ?>",
|
|
sort: false
|
|
},
|
|
{
|
|
name: "<?php e(t('User')); ?>",
|
|
sort: false
|
|
},
|
|
{
|
|
name: "<?php e(t('Run UUID')); ?>",
|
|
sort: false
|
|
}
|
|
],
|
|
sortColumns: ['started_at', 'status', 'trigger_type', 'duration_ms', null, null, null],
|
|
paginationLimit: 10,
|
|
language: <?php MintyPHP\Buffer::get('grid_lang'); ?>,
|
|
mapData: (data) => data.data.map((row) => [
|
|
row.started_at || '-',
|
|
{
|
|
variant: row.status_badge,
|
|
label: row.status || ''
|
|
},
|
|
row.trigger_type || '',
|
|
row.duration_ms || 0,
|
|
row.error_code || '-',
|
|
row.actor_label || '-',
|
|
row.run_uuid || '-'
|
|
]),
|
|
actions: {
|
|
enabled: false
|
|
},
|
|
search: {
|
|
input: '#scheduled-job-runs-search',
|
|
param: 'search',
|
|
debounce: 250
|
|
},
|
|
filters: [{
|
|
input: '#scheduled-job-runs-status-filter',
|
|
param: 'status'
|
|
},
|
|
{
|
|
input: '#scheduled-job-runs-trigger-filter',
|
|
param: 'trigger_type'
|
|
}
|
|
],
|
|
urlSync: false
|
|
});
|
|
</script>
|