enhanced scheduler fixes

Signed-off-by: Andy Miller <rhuk@mac.com>
This commit is contained in:
Andy Miller
2025-08-25 14:05:19 +01:00
parent 04c761142d
commit 25f17ad9b1
2 changed files with 155 additions and 15 deletions

129
themes/grav/js/clipboard-helper.js vendored Normal file
View File

@@ -0,0 +1,129 @@
/**
* Clipboard Helper for Grav Admin
* Provides copy-to-clipboard functionality with visual feedback
*/
window.GravClipboard = {
/**
* Copy the value from an input/textarea element with visual feedback
* @param {HTMLElement} buttonElement - The button element that was clicked
* @param {string} inputId - Optional ID of input to copy from (if not previous sibling)
*/
copy: function(buttonElement, inputId) {
var input;
if (inputId) {
input = document.getElementById(inputId);
} else {
input = buttonElement.previousElementSibling;
}
if (!input) {
console.error('No input element found to copy from');
return;
}
// Select and copy the text
input.select();
var success = document.execCommand('copy');
if (success) {
// Store original content
var originalHTML = buttonElement.innerHTML;
// Show success feedback
buttonElement.innerHTML = '<i class="fa fa-check"></i> Copied!';
// Restore original content after delay
setTimeout(function() {
buttonElement.innerHTML = originalHTML;
}, 2000);
} else {
console.error('Failed to copy to clipboard');
}
},
/**
* Update webhook commands with actual token and URL values
* @param {string} tokenFieldSelector - Selector for the token input field
*/
updateWebhookCommands: function(tokenFieldSelector) {
tokenFieldSelector = tokenFieldSelector || '[name="data[scheduler][modern][webhook][token]"]';
// Try multiple ways to get the token field
var tokenField = document.querySelector(tokenFieldSelector);
if (!tokenField) {
tokenField = document.querySelector('input[name*="webhook][token"]');
}
if (!tokenField) {
// Look for the token input by searching in the webhook section
var inputs = document.querySelectorAll('input[type="text"]');
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].name && inputs[i].name.includes('webhook') && inputs[i].name.includes('token')) {
tokenField = inputs[i];
break;
}
}
}
var token = (tokenField && tokenField.value && tokenField.value.trim()) ? tokenField.value.trim() : 'YOUR_TOKEN';
var siteUrl = window.location.origin + window.location.pathname.replace(/\/admin.*$/, '');
// Update webhook commands with actual values (URLs quoted for shell compatibility)
var webhookAllCmd = 'curl -X POST "' + siteUrl + '/scheduler/webhook" \\\n -H "Authorization: Bearer ' + token + '"';
var webhookJobCmd = 'curl -X POST "' + siteUrl + '/scheduler/webhook?job=backup" \\\n -H "Authorization: Bearer ' + token + '"';
var healthCmd = 'curl "' + siteUrl + '/scheduler/health"';
// Set values in input fields if they exist
var allInput = document.getElementById('webhook-all-cmd');
var jobInput = document.getElementById('webhook-job-cmd');
var healthInput = document.getElementById('webhook-health-cmd');
if (allInput) allInput.value = webhookAllCmd;
if (jobInput) jobInput.value = webhookJobCmd;
if (healthInput) healthInput.value = healthCmd;
return {
token: token,
siteUrl: siteUrl,
webhookAllCmd: webhookAllCmd,
webhookJobCmd: webhookJobCmd,
healthCmd: healthCmd
};
},
/**
* Initialize webhook command updates and listeners
*/
initWebhookCommands: function() {
var self = this;
// Update on page load
self.updateWebhookCommands();
// Also update when token field changes
setTimeout(function() {
var tokenField = document.querySelector('[name="data[scheduler][modern][webhook][token]"]');
if (!tokenField) {
tokenField = document.querySelector('input[name*="webhook][token"]');
}
if (tokenField) {
tokenField.addEventListener('change', function() { self.updateWebhookCommands(); });
tokenField.addEventListener('input', function() { self.updateWebhookCommands(); });
}
}, 500);
}
};
// Auto-initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
if (document.getElementById('webhook-all-cmd')) {
GravClipboard.initWebhookCommands();
}
});
} else {
if (document.getElementById('webhook-all-cmd')) {
GravClipboard.initWebhookCommands();
}
}

View File

@@ -1,3 +1,4 @@
<script src="{{ url('plugin://admin/themes/grav/js/clipboard-helper.js') }}"></script>
<div class="scheduler-content">
{% set data = admin.data('config/scheduler') %}
@@ -10,27 +11,21 @@
{# We have at least one active trigger method #}
{% if 'webhook' in active_triggers and 'cron' not in active_triggers %}
{# Webhook only mode #}
<div class="alert notice" style="display:flex;justify-content:space-between;">
<div>
<i class="fa fa-plug"></i> <strong>Webhook Active</strong> - Scheduler is ready to receive webhook triggers
</div>
<div class="alert notice secondary-accent">
<div id="show-instructions" class="button button-small button-outline float-right"><i class="fa fa-clock-o"></i> {{ "PLUGIN_ADMIN.SCHEDULER_INSTALL_INSTRUCTIONS"|t }}</div>
<i class="fa fa-plug"></i> <strong>Webhook Active</strong> - Scheduler is ready to receive webhook triggers
</div>
{% elseif 'cron' in active_triggers and 'webhook' in active_triggers %}
{# Both cron and webhook #}
<div class="alert notice secondary-accent" style="display:flex;justify-content:space-between;">
<div>
<i class="fa fa-check"></i> <strong>Cron & Webhook Active</strong> - Scheduler is running via cron and accepts webhook triggers
</div>
<div class="alert notice secondary-accent">
<div id="show-instructions" class="button button-small button-outline float-right"><i class="fa fa-clock-o"></i> {{ "PLUGIN_ADMIN.SCHEDULER_INSTALL_INSTRUCTIONS"|t }}</div>
<i class="fa fa-check"></i> <strong>Cron & Webhook Active</strong> - Scheduler is running via cron and accepts webhook triggers
</div>
{% elseif 'cron' in active_triggers %}
{# Cron only #}
<div class="alert notice secondary-accent" style="display:flex;justify-content:space-between;">
<div>
<i class="fa fa-check"></i> {{ "PLUGIN_ADMIN.SCHEDULER_INSTALLED_READY"|t }}
</div>
<div class="alert notice secondary-accent">
<div id="show-instructions" class="button button-small button-outline float-right"><i class="fa fa-clock-o"></i> {{ "PLUGIN_ADMIN.SCHEDULER_INSTALL_INSTRUCTIONS"|t }}</div>
<i class="fa fa-check"></i> {{ "PLUGIN_ADMIN.SCHEDULER_INSTALLED_READY"|t }}
</div>
{% endif %}
{% elseif cron_status == 2 %}
@@ -45,15 +40,31 @@
{% if webhook_enabled %}
<h3>Webhook Setup</h3>
<p>The scheduler is configured to use webhooks. To trigger jobs via webhook:</p>
<pre><code>curl -X POST {{ grav.base_url_absolute }}/scheduler/webhook \
-H "Authorization: Bearer YOUR_TOKEN"</code></pre>
{% set webhook_token = config.get('scheduler.modern.webhook.token') %}
{% if not webhook_token %}
{% set webhook_token = 'YOUR_TOKEN' %}
{% endif %}
<div class="form-input-wrapper form-input-addon-wrapper" style="margin: 1rem 0;">
<textarea id="webhook-setup-cmd" readonly rows="2" style="font-family: monospace; background: #f8f9fa; border: 1px solid #dee2e6; padding: 0.375rem 0.75rem; resize: none; white-space: pre; border-radius: 4px 0 0 4px;">curl -X POST "{{ grav.base_url_absolute }}/scheduler/webhook" \
-H "Authorization: Bearer {{ webhook_token }}"</textarea>
<div class="form-input-addon form-input-append" style="cursor: pointer; background: #e9ecef; border: 1px solid #dee2e6; border-left: 0; padding: 0.375rem 0.75rem; display: inline-flex; align-items: center; border-radius: 0 4px 4px 0;" onclick="GravClipboard.copy(this)">
<i class="fa fa-copy" style="margin-right: 0.25rem;"></i> Copy
</div>
</div>
<p>Make sure the <strong>scheduler-webhook</strong> plugin is installed and enabled.</p>
<hr>
<h3>Alternative: Cron Setup</h3>
{% endif %}
<pre><code>{{- grav.scheduler.getCronCommand()|trim -}}</code></pre>
<div class="form-input-wrapper form-input-addon-wrapper" style="margin: 1rem 0;">
<input type="text" id="cron-setup-cmd" readonly value="{{ grav.scheduler.getCronCommand()|trim }}" style="font-family: monospace; background: #f8f9fa; border: 1px solid #dee2e6; padding: 0.375rem 0.75rem; border-radius: 4px 0 0 4px;">
<div class="form-input-addon form-input-append" style="cursor: pointer; background: #e9ecef; border: 1px solid #dee2e6; border-left: 0; padding: 0.375rem 0.75rem; display: inline-flex; align-items: center; border-radius: 0 4px 4px 0;" onclick="GravClipboard.copy(this)">
<i class="fa fa-copy" style="margin-right: 0.25rem;"></i> Copy
</div>
</div>
<p>{{ "PLUGIN_ADMIN.SCHEDULER_POST_INSTRUCTIONS"|t([user])|raw }}</p>
</div>