fix: document cron router auth chain
This commit is contained in:
+123
-10
@@ -416,6 +416,7 @@
|
||||
<button class="btn ghost" onclick="reloadAll()">Refresh</button>
|
||||
<button class="btn" onclick="openCreate()">+ Создать функцию</button>
|
||||
<button class="btn ghost" onclick="openHelp()">Help</button>
|
||||
<a class="btn ghost" href="/cron/" target="_blank" rel="noopener">Cron</a>
|
||||
<button class="btn ghost" onclick="doLogout()" style="margin-left:8px;">Выход</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -438,6 +439,10 @@
|
||||
<div class="k">HTTP-триггеры</div>
|
||||
<div id="http-count" class="v">-</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="k">Крон-функции</div>
|
||||
<div id="cron-count" class="v">-</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box">
|
||||
@@ -455,6 +460,7 @@
|
||||
<th>Изменена</th>
|
||||
<th>Маршрут</th>
|
||||
<th>Методы</th>
|
||||
<th>Cron</th>
|
||||
<th class="nowrap">Действия</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -501,6 +507,18 @@
|
||||
<input id="c-timeout" type="number" min="1" value="60">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="field" style="min-width:240px; flex:0 0 260px;">
|
||||
<label style="display:flex; align-items:center; gap:8px; color:var(--text-primary); margin-top:18px;">
|
||||
<input id="c-schedule-enabled" type="checkbox" onchange="toggleScheduleFields('c')" style="width:auto;">
|
||||
Выполнять по расписанию
|
||||
</label>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Cron</label>
|
||||
<input id="c-cron" placeholder="*/5 * * * *" disabled>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label>Код</label>
|
||||
<textarea id="c-code">def main():
|
||||
@@ -559,6 +577,18 @@
|
||||
<input id="e-timeout" type="number" min="1" value="60">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="field" style="min-width:240px; flex:0 0 260px;">
|
||||
<label style="display:flex; align-items:center; gap:8px; color:var(--text-primary); margin-top:18px;">
|
||||
<input id="e-schedule-enabled" type="checkbox" onchange="toggleScheduleFields('e')" style="width:auto;">
|
||||
Выполнять по расписанию
|
||||
</label>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Cron</label>
|
||||
<input id="e-cron" placeholder="*/5 * * * *" disabled>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label>Код</label>
|
||||
<textarea id="e-code"></textarea>
|
||||
@@ -695,7 +725,8 @@
|
||||
const S = {
|
||||
envs: [],
|
||||
fns: [],
|
||||
triggers: [],
|
||||
httpTriggers: [],
|
||||
timeTriggers: [],
|
||||
currentEdit: null,
|
||||
currentInvoke: null
|
||||
};
|
||||
@@ -795,12 +826,65 @@
|
||||
return warning + '\n' + body;
|
||||
}
|
||||
|
||||
function triggerByFn(fnName) {
|
||||
return (S.triggers || []).find(function (t) {
|
||||
function httpTriggerByFn(fnName) {
|
||||
return (S.httpTriggers || []).find(function (t) {
|
||||
return t.spec && t.spec.functionref && t.spec.functionref.name === fnName;
|
||||
});
|
||||
}
|
||||
|
||||
function timeTriggerByFn(fnName) {
|
||||
return (S.timeTriggers || []).find(function (t) {
|
||||
return t.spec && t.spec.functionref && t.spec.functionref.name === fnName;
|
||||
});
|
||||
}
|
||||
|
||||
function toggleScheduleFields(prefix) {
|
||||
var enabled = !!document.getElementById(prefix + '-schedule-enabled').checked;
|
||||
var cronEl = document.getElementById(prefix + '-cron');
|
||||
cronEl.disabled = !enabled;
|
||||
if (enabled && !cronEl.value.trim()) {
|
||||
cronEl.value = '*/5 * * * *';
|
||||
}
|
||||
}
|
||||
|
||||
function schedulePayload(prefix) {
|
||||
return {
|
||||
enabled: !!document.getElementById(prefix + '-schedule-enabled').checked,
|
||||
cron: (document.getElementById(prefix + '-cron').value || '').trim()
|
||||
};
|
||||
}
|
||||
|
||||
async function syncScheduleForFunction(name, prefix) {
|
||||
var schedule = schedulePayload(prefix);
|
||||
var existing = timeTriggerByFn(name);
|
||||
var existingName = (existing && existing.metadata && existing.metadata.name) || name;
|
||||
|
||||
if (!schedule.enabled) {
|
||||
if (existing) {
|
||||
await requestJSON(API_BASE + '/timetriggers/' + encodeURIComponent(existingName), 'DELETE');
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!schedule.cron) {
|
||||
throw new Error('cron is required');
|
||||
}
|
||||
|
||||
var payload = {
|
||||
name: existingName,
|
||||
functionName: name,
|
||||
cron: schedule.cron,
|
||||
method: 'POST',
|
||||
subpath: '/'
|
||||
};
|
||||
|
||||
if (existing) {
|
||||
await requestJSON(API_BASE + '/timetriggers/' + encodeURIComponent(existingName), 'PUT', payload);
|
||||
} else {
|
||||
await requestJSON(API_BASE + '/timetriggers', 'POST', payload);
|
||||
}
|
||||
}
|
||||
|
||||
function h(v) {
|
||||
return String(v == null ? '' : v)
|
||||
.replaceAll('&', '&')
|
||||
@@ -861,6 +945,9 @@
|
||||
document.getElementById('c-lang').value = 'python';
|
||||
onLangChange();
|
||||
document.getElementById('c-timeout').value = '60';
|
||||
document.getElementById('c-schedule-enabled').checked = false;
|
||||
document.getElementById('c-cron').value = '';
|
||||
toggleScheduleFields('c');
|
||||
document.getElementById('create-modal').classList.add('open');
|
||||
document.getElementById('c-name').focus();
|
||||
}
|
||||
@@ -889,6 +976,17 @@
|
||||
code: document.getElementById('c-code').value
|
||||
});
|
||||
|
||||
try {
|
||||
await syncScheduleForFunction(name, 'c');
|
||||
} catch (scheduleErr) {
|
||||
try {
|
||||
await requestJSON(API_BASE + '/functions/' + encodeURIComponent(name), 'DELETE');
|
||||
} catch (rollbackErr) {
|
||||
scheduleErr.message += '; rollback failed: ' + rollbackErr.message;
|
||||
}
|
||||
throw scheduleErr;
|
||||
}
|
||||
|
||||
closeCreate();
|
||||
progress.stop('\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0430: ' + name, 'ok');
|
||||
await reloadAll();
|
||||
@@ -909,6 +1007,10 @@
|
||||
document.getElementById('e-entry').value = fn.entrypoint || '';
|
||||
document.getElementById('e-timeout').value = String(fn.timeout || 60);
|
||||
document.getElementById('e-code').value = fn.code || '';
|
||||
var schedule = timeTriggerByFn(name);
|
||||
document.getElementById('e-schedule-enabled').checked = !!schedule;
|
||||
document.getElementById('e-cron').value = (schedule && schedule.spec && schedule.spec.cron) || '';
|
||||
toggleScheduleFields('e');
|
||||
// Определяем язык по имени environment для линтера
|
||||
var envName = (fn.environment || '').toLowerCase();
|
||||
var lang = 'python';
|
||||
@@ -955,6 +1057,8 @@
|
||||
code: document.getElementById('e-code').value,
|
||||
timeout: parseTimeout(document.getElementById('e-timeout').value)
|
||||
});
|
||||
|
||||
await syncScheduleForFunction(name, 'e');
|
||||
closeEdit();
|
||||
progress.stop('\u041a\u043e\u0434 \u043e\u0431\u043d\u043e\u0432\u043b\u0451\u043d: ' + name, 'ok');
|
||||
await reloadAll();
|
||||
@@ -1047,21 +1151,26 @@
|
||||
|
||||
async function reloadAll() {
|
||||
try {
|
||||
const [envs, pkgs, fns, http] = await Promise.all([
|
||||
const [envs, pkgs, fns, http, times] = await Promise.all([
|
||||
getJSON(API_BASE + '/environments'),
|
||||
getJSON(API_BASE + '/packages'),
|
||||
getJSON(API_BASE + '/functions'),
|
||||
getJSON(API_BASE + '/httptriggers')
|
||||
getJSON(API_BASE + '/httptriggers'),
|
||||
getJSON(API_BASE + '/timetriggers')
|
||||
]);
|
||||
|
||||
S.envs = envs || [];
|
||||
S.fns = fns || [];
|
||||
S.triggers = http || [];
|
||||
S.httpTriggers = http || [];
|
||||
S.timeTriggers = times || [];
|
||||
|
||||
setText('env-count', envs.length || 0);
|
||||
setText('pkg-count', pkgs.length || 0);
|
||||
setText('fn-count', fns.length || 0);
|
||||
setText('http-count', http.length || 0);
|
||||
setText('cron-count', new Set((times || []).map(function (t) {
|
||||
return t && t.spec && t.spec.functionref && t.spec.functionref.name;
|
||||
}).filter(Boolean)).size);
|
||||
|
||||
const rows = (fns || []).map(function (f) {
|
||||
const spec = f.spec || {};
|
||||
@@ -1070,10 +1179,13 @@
|
||||
const env = (spec.environment && spec.environment.name) || '-';
|
||||
const pkg = (spec.package && spec.package.packageref && spec.package.packageref.name) || '-';
|
||||
const name = (f.metadata && f.metadata.name) || '-';
|
||||
const trig = triggerByFn(name) || {};
|
||||
const trig = httpTriggerByFn(name) || {};
|
||||
const timeTrig = timeTriggerByFn(name) || {};
|
||||
const route = (trig.spec && trig.spec.relativeurl) || '-';
|
||||
const methods = (trig.spec && trig.spec.methods) || [];
|
||||
const chips = methods.map(function (m) { return '<span class="chip">' + h(m) + '</span>'; }).join('');
|
||||
const cron = (timeTrig.spec && timeTrig.spec.cron) || '';
|
||||
const cronCell = cron ? '<span class="chip">' + h(cron) + '</span>' : '<span class="mono" style="color:var(--text-secondary)">—</span>';
|
||||
const createdAt = ann['fission-console/created-at'] || meta.creationTimestamp || '-';
|
||||
const updatedAt = ann['fission-console/updated-at'] || createdAt;
|
||||
var isGo = /go[-_]env/.test(env);
|
||||
@@ -1091,16 +1203,17 @@
|
||||
'<td>' + timestampCell(updatedAt) + '</td>' +
|
||||
'<td class="mono">' + h(route) + '</td>' +
|
||||
'<td>' + chips + '</td>' +
|
||||
'<td>' + cronCell + '</td>' +
|
||||
'<td class="nowrap">' + actions + '</td>' +
|
||||
'</tr>';
|
||||
}).join('');
|
||||
|
||||
document.getElementById('fn-rows').innerHTML = rows || '<tr><td colspan="8">\u041d\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u0439</td></tr>';
|
||||
document.getElementById('fn-rows').innerHTML = rows || '<tr><td colspan="9">\u041d\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u0439</td></tr>';
|
||||
if (!rows) {
|
||||
document.getElementById('fn-rows').innerHTML = '<tr><td colspan="8">\u041d\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u0439</td></tr>';
|
||||
document.getElementById('fn-rows').innerHTML = '<tr><td colspan="9">\u041d\u0435\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u0439</td></tr>';
|
||||
}
|
||||
} catch (e) {
|
||||
document.getElementById('fn-rows').innerHTML = '<tr><td colspan="8">Load error: ' + e.message + '</td></tr>';
|
||||
document.getElementById('fn-rows').innerHTML = '<tr><td colspan="9">Load error: ' + e.message + '</td></tr>';
|
||||
showStatus('\u041e\u0448\u0438\u0431\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438: ' + e.message, 'err');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user