Changeset 0.28.6 (#192)
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
{ label: 'Every hour', cron: '0 * * * *' },
|
||||
{ label: 'Weekly (Monday 9am)', cron: '0 9 * * 1' },
|
||||
{ label: 'Monthly (1st midnight)', cron: '0 0 1 * *' },
|
||||
{ label: 'Webhook trigger', cron: 'webhook' },
|
||||
{ label: 'Custom...', cron: '' },
|
||||
];
|
||||
|
||||
@@ -73,12 +74,16 @@
|
||||
html += tasks.map(function(t) {
|
||||
var status = t.is_active ? '<span class="badge badge-success">active</span>' : '<span class="badge badge-muted">paused</span>';
|
||||
var teamBadge = t._source === 'team' ? '<span class="badge" style="background:var(--accent-dim);color:var(--accent)">' + esc(t._teamName || 'team') + '</span>' : '';
|
||||
var sched = t.schedule === 'once' ? 'One-shot' : t.schedule;
|
||||
var sched = t.schedule === 'once' ? 'One-shot' : t.schedule === 'webhook' ? 'Webhook trigger' : t.schedule;
|
||||
var lastStatus = '';
|
||||
if (t.last_run_at) {
|
||||
lastStatus = ' \u00b7 last: ' + new Date(t.last_run_at).toLocaleString();
|
||||
}
|
||||
var nextRun = t.next_run_at ? new Date(t.next_run_at).toLocaleString() : '\u2014';
|
||||
var nextRun = t.schedule === 'webhook' ? 'on trigger' : t.next_run_at ? new Date(t.next_run_at).toLocaleString() : '\u2014';
|
||||
var triggerBtn = '';
|
||||
if (t.schedule === 'webhook' && t.trigger_token) {
|
||||
triggerBtn = '<button class="btn-small task-trigger-btn" data-token="' + esc(t.trigger_token) + '" title="Copy Trigger URL">\ud83d\udd17</button>';
|
||||
}
|
||||
|
||||
return '<div class="settings-section" style="padding:12px 16px;margin-bottom:8px">' +
|
||||
'<div style="display:flex;align-items:center;gap:12px">' +
|
||||
@@ -89,6 +94,7 @@
|
||||
'</div>' +
|
||||
'<div style="display:flex;gap:6px;align-items:center">' +
|
||||
teamBadge + status +
|
||||
triggerBtn +
|
||||
'<button class="btn-small task-run-btn" data-id="' + t.id + '" title="Run Now">\u25b6</button>' +
|
||||
'<button class="btn-small task-toggle-btn" data-id="' + t.id + '" data-active="' + t.is_active + '" title="' + (t.is_active ? 'Pause' : 'Resume') + '">' + (t.is_active ? '\u23f8' : '\u25b6') + '</button>' +
|
||||
'<button class="btn-small btn-danger task-del-btn" data-id="' + t.id + '" title="Delete">\u2715</button>' +
|
||||
@@ -123,6 +129,16 @@
|
||||
mount.querySelectorAll('.task-del-btn').forEach(function(btn) {
|
||||
btn.addEventListener('click', function() { deleteTask(btn.dataset.id); });
|
||||
});
|
||||
mount.querySelectorAll('.task-trigger-btn').forEach(function(btn) {
|
||||
btn.addEventListener('click', function() {
|
||||
var url = location.origin + (window.__BASE__ || '') + '/api/v1/hooks/t/' + btn.dataset.token;
|
||||
navigator.clipboard.writeText(url).then(function() {
|
||||
UI.toast('Trigger URL copied', 'success');
|
||||
}).catch(function() {
|
||||
prompt('Trigger URL:', url);
|
||||
});
|
||||
});
|
||||
});
|
||||
} catch (err) {
|
||||
mount.innerHTML = '<p style="color:var(--danger)">Failed to load tasks: ' + esc(err.message) + '</p>';
|
||||
}
|
||||
@@ -164,6 +180,17 @@
|
||||
'<div class="form-group" style="flex:1" id="taskWebhookGroup" style="display:none"><label>Webhook URL</label>' +
|
||||
'<input type="text" id="taskWebhookURL" style="width:100%" placeholder="https://..."></div>' +
|
||||
'</div>' +
|
||||
'<div class="form-group" style="margin-top:8px" id="taskWebhookSecretGroup" style="display:none"><label>Webhook Secret (HMAC signing)</label>' +
|
||||
'<input type="text" id="taskWebhookSecret" style="width:100%" placeholder="auto-generated if empty">' +
|
||||
'<p style="font-size:11px;color:var(--text-3);margin:2px 0 0">Used to sign outbound webhook payloads. Leave blank for auto-generated secret.</p>' +
|
||||
'</div>' +
|
||||
'<div id="taskWebhookTriggerInfo" style="display:none;margin-top:12px;padding:12px;background:var(--bg-raised);border-radius:var(--radius);border:1px solid var(--border)">' +
|
||||
'<div style="font-weight:600;font-size:12px;margin-bottom:4px">' +
|
||||
'<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="vertical-align:-1px"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>' +
|
||||
' Webhook-triggered task</div>' +
|
||||
'<p style="font-size:12px;color:var(--text-2);margin:0;line-height:1.5">This task runs when an external service sends a POST request to its trigger URL. ' +
|
||||
'The trigger URL will be shown after creation — copy it into your CI, cron, or another task\\u2019s webhook URL for task-to-task chaining.</p>' +
|
||||
'</div>' +
|
||||
'<div class="form-row" style="gap:12px;margin-top:8px">' +
|
||||
'<div class="form-group" style="flex:1"><label>Max Tokens</label>' +
|
||||
'<input type="number" id="taskMaxTokens" value="" style="width:100%" placeholder="default"></div>' +
|
||||
@@ -183,19 +210,28 @@
|
||||
// Toggle custom cron visibility
|
||||
var preset = document.getElementById('taskPreset');
|
||||
var customGroup = document.getElementById('taskCustomCronGroup');
|
||||
var triggerInfo = document.getElementById('taskWebhookTriggerInfo');
|
||||
preset.addEventListener('change', function() {
|
||||
customGroup.style.display = preset.value === '' ? '' : 'none';
|
||||
if (preset.value !== '') document.getElementById('taskCron').value = preset.value;
|
||||
var isWebhook = preset.value === 'webhook';
|
||||
var isCustom = preset.value === '';
|
||||
customGroup.style.display = isCustom ? '' : 'none';
|
||||
triggerInfo.style.display = isWebhook ? '' : 'none';
|
||||
if (!isWebhook && !isCustom) document.getElementById('taskCron').value = preset.value;
|
||||
if (isWebhook) document.getElementById('taskCron').value = 'webhook';
|
||||
});
|
||||
// Initial state
|
||||
customGroup.style.display = preset.value === '' ? '' : 'none';
|
||||
if (preset.value !== '') document.getElementById('taskCron').value = preset.value;
|
||||
triggerInfo.style.display = preset.value === 'webhook' ? '' : 'none';
|
||||
if (preset.value !== '' && preset.value !== 'webhook') document.getElementById('taskCron').value = preset.value;
|
||||
|
||||
// Toggle webhook URL visibility
|
||||
// Toggle webhook URL and secret visibility
|
||||
var output = document.getElementById('taskOutput');
|
||||
var webhookGroup = document.getElementById('taskWebhookGroup');
|
||||
var webhookSecretGroup = document.getElementById('taskWebhookSecretGroup');
|
||||
output.addEventListener('change', function() {
|
||||
webhookGroup.style.display = output.value === 'webhook' ? '' : 'none';
|
||||
var isWH = output.value === 'webhook';
|
||||
webhookGroup.style.display = isWH ? '' : 'none';
|
||||
webhookSecretGroup.style.display = isWH ? '' : 'none';
|
||||
});
|
||||
}
|
||||
|
||||
@@ -227,12 +263,39 @@
|
||||
if (payload.output_mode === 'webhook' && webhookURL) {
|
||||
payload.webhook_url = webhookURL;
|
||||
}
|
||||
var webhookSecret = document.getElementById('taskWebhookSecret')?.value;
|
||||
if (payload.output_mode === 'webhook' && webhookSecret) {
|
||||
payload.webhook_secret = webhookSecret;
|
||||
}
|
||||
|
||||
try {
|
||||
await API._post('/api/v1/tasks', payload);
|
||||
var created = await API._post('/api/v1/tasks', payload);
|
||||
UI.toast('Task created', 'success');
|
||||
|
||||
// Show trigger URL for webhook-scheduled tasks
|
||||
if (created.schedule === 'webhook' && created.trigger_token) {
|
||||
var triggerURL = location.origin + (window.__BASE__ || '') + '/api/v1/hooks/t/' + created.trigger_token;
|
||||
UI.modal('Webhook Trigger URL',
|
||||
'<p style="font-size:12px;color:var(--text-2);margin-bottom:8px">POST to this URL to trigger the task. ' +
|
||||
'You can use this in CI pipelines, cron jobs, or as another task\\u2019s webhook URL for chaining.</p>' +
|
||||
'<div style="display:flex;gap:8px;align-items:center">' +
|
||||
'<input type="text" readonly value="' + esc(triggerURL) + '" style="flex:1;font-family:var(--mono);font-size:11px" id="_triggerURLInput">' +
|
||||
'<button class="btn-small btn-primary" id="_copyTriggerBtn">Copy</button>' +
|
||||
'</div>' +
|
||||
'<p style="font-size:11px;color:var(--text-3);margin-top:8px">The request body is passed to the task as trigger_payload. ' +
|
||||
'For task-to-task chaining: set Task A\\u2019s webhook_url to Task B\\u2019s trigger URL.</p>',
|
||||
[{ label: 'Done', variant: 'primary' }]
|
||||
);
|
||||
setTimeout(function() {
|
||||
var copyBtn = document.getElementById('_copyTriggerBtn');
|
||||
if (copyBtn) copyBtn.addEventListener('click', function() {
|
||||
var input = document.getElementById('_triggerURLInput');
|
||||
if (input) { navigator.clipboard.writeText(input.value); UI.toast('Copied', 'success'); }
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
|
||||
loadTaskList();
|
||||
// Refresh sidebar
|
||||
if (typeof TaskSidebar !== 'undefined') TaskSidebar.refresh();
|
||||
} catch (err) {
|
||||
UI.toast(err.message || 'Failed to create task', 'error');
|
||||
|
||||
Reference in New Issue
Block a user