Files
app-autotest/site/static/js/params-render.js
T
naeel 91e97f6f75 v1.2.0: unified executor + flexible instance refs + params-render.js
Phase 1 — New modules:
- api/utils.py: find_uid(), uid_from_location() (replaces 2 duplicates)
- operations/poll.py: poll_until_done() (shared sync/async polling)
- operations/executor.py: execute_operation() (single CREATE/non-CREATE flow)

Phase 2 — Format + validation:
- routes/api_scenario_defs.py: _validate_steps with output/instance_ref/instance_uid
- operations/scenario.py: resolve instance_uid > instance_ref > service_id,
  use executor + poll_until_done, persist instance_bindings

Phase 3 — Migration:
- routes/api_test.py: create/non-create through executor, _finish_op through poll_until_done
- db/init_db.py: startup cleanup of stuck scenario_runs (>1h)

Phase 4 — UI shared module:
- static/js/params-render.js: renderParamRow, renderMapFixedRow, collectParams
- static/js/operations.js: use params-render.js (remove duplicates)
- templates/index.html: include params-render.js
- app.py: bump 1.1.57 → 1.2.0
2026-07-31 08:55:06 +04:00

82 lines
4.9 KiB
JavaScript

// params-render.js — общий рендер параметров операций
// Используется: operations.js (ручной режим), scenario-form.js (редактор сценариев)
// Зависимости: _esc() из utils.js, validateJson() из utils.js
function renderParamRow(p, allInst) {
const req = p.isRequired;
const hasDfl = p.defaultValue !== null && p.defaultValue !== undefined && p.defaultValue !== '';
const labelCls = req ? (hasDfl ? 'req' : 'req-nodfl') : '';
const dfl = hasDfl ? p.defaultValue : (req ? '' : '');
const vl = p.valueList;
const isMap = (p.dataType || '').startsWith('map');
let input;
if (vl && Array.isArray(vl)) {
input = `<select name="p_${p.svcOperationCfsParamId}" data-type="${_esc(p.dataType)}">${vl.map(v => `<option value="${_esc(v)}" ${v == dfl ? 'selected' : ''}>${_esc(v)}</option>`).join('')}</select>`;
} else if (p.refSvcId) {
const refInsts = allInst.filter(i => i.serviceId === p.refSvcId && i.explainedStatus !== 'deleted');
let opts = refInsts.map(i => `<option value="${_esc(i.instanceUid)}" ${i.instanceUid === dfl ? 'selected' : ''}>${_esc(i.displayName)}</option>`).join('');
if (!dfl) opts = '<option value="">— выбрать —</option>' + opts;
input = `<select name="p_${p.svcOperationCfsParamId}" data-type="ref">${opts}</select>`;
} else if (p.dataType === 'boolean') {
input = `<select name="p_${p.svcOperationCfsParamId}" data-type="boolean"><option value="true" ${dfl === 'true' || dfl === true ? 'selected' : ''}>true</option><option value="false" ${dfl === 'false' || dfl === false ? 'selected' : ''}>false</option></select>`;
} else if (p.dataDescriptor && isMap) {
return renderMapFixedRow(p, dfl);
} else {
const dt = isMap ? 'map' : '';
input = `<input type="text" name="p_${p.svcOperationCfsParamId}" value="${_esc(dfl)}" data-type="${dt}" placeholder="${req && !hasDfl ? 'обязательно' : ''}"${isMap ? ' onblur="validateJson(this)"' : ''}>`;
if (isMap) input += `<span class="json-err" style="display:none;color:var(--destructive);font-size:10px;margin-left:4px;"></span>`;
}
return `<div class="param-row"><label class="${labelCls}">${_esc(p.name)}</label>${input}</div>`;
}
function renderMapFixedRow(p, dfl) {
const dd = p.dataDescriptor;
let subHtml = '';
let dflObj = {};
try { dflObj = JSON.parse(dfl || '{}'); } catch (e) { }
Object.keys(dd).forEach(subKey => {
const sub = dd[subKey];
const subDfl = dflObj[subKey] !== undefined ? dflObj[subKey] : (sub.defaultValue || '');
const subVl = sub.valueList;
const subReq = sub.isRequired;
const subNoDfl = subReq && !subDfl && subDfl !== 0 && subDfl !== false;
const subLblCls = subNoDfl ? 'req-nodfl' : '';
let si;
if (subVl && Array.isArray(subVl)) {
si = `<select name="p_${p.svcOperationCfsParamId}.${subKey}" data-type="mapchild">${subVl.map(v => `<option value="${_esc(v)}" ${v == subDfl ? 'selected' : ''}>${_esc(v)}</option>`).join('')}</select>`;
} else if (sub.dataType === 'boolean') {
si = `<select name="p_${p.svcOperationCfsParamId}.${subKey}" data-type="mapchild"><option value="true" ${subDfl === 'true' || subDfl === true ? 'selected' : ''}>true</option><option value="false" ${subDfl === 'false' || subDfl === false ? 'selected' : ''}>false</option></select>`;
} else {
si = `<input type="text" name="p_${p.svcOperationCfsParamId}.${subKey}" value="${_esc(subDfl)}" data-type="mapchild">`;
}
subHtml += `<div class="param-row"><label class="${subLblCls}">${_esc(subKey)}</label>${si}</div>`;
});
return `<div class="param-row"><label class="${labelCls}">${_esc(p.name)}</label></div><div style="border-left:2px solid var(--brand-gray);margin-left:8px;padding:0 0 4px 8px;">${subHtml}</div>`;
}
function collectParams(containerSelector) {
containerSelector = containerSelector || '#params-form';
const pp = {};
const nested = {};
const container = document.querySelector(containerSelector);
if (!container) return pp;
container.querySelectorAll('[name^="p_"]').forEach(el => {
let v = el.value;
const dt = el.dataset.type || '';
if (dt === 'mapchild') {
const name = el.name.replace('p_', '');
const dot = name.indexOf('.');
const parentKey = name.substring(0, dot);
const subKey = name.substring(dot + 1);
if (!nested[parentKey]) nested[parentKey] = {};
nested[parentKey][subKey] = v;
return;
}
if (dt === 'array' || dt.startsWith('array')) v = JSON.stringify([v]);
if (dt === 'map' || dt === 'map-fixed') v = v || '{}';
pp[el.name.replace('p_', '')] = v;
});
for (const pk in nested) pp[pk] = JSON.stringify(nested[pk]);
return pp;
}