69 lines
6.7 KiB
JavaScript
69 lines
6.7 KiB
JavaScript
'use strict';
|
|
|
|
async function graphicalProfileForm(kind,existing=null) {
|
|
const p=existing||{};
|
|
const install=kind==='installation';
|
|
const [secrets,modules]=await Promise.all([api('/secrets'),install?Promise.resolve([]):api('/modules')]);
|
|
const fields=field('name','Profilname',p.name,{required:true,full:true,placeholder:install?'PVE · Einzelplatte':'PVE · Basiskonfiguration',hint:'Beim Speichern entsteht eine neue Profilversion.'})+
|
|
dataEditor('profile-builds',arr(p.target_builds),{label:'Unterstützte Zielbuilds',schema:{type:'array',minItems:1,items:{type:'string',minLength:1}}})+
|
|
(install?installationEditor(p.values||{},{prefix:'installation',secrets:arr(secrets)}):postinstallEditor(p,arr(modules).filter(m=>m.status==='published'),arr(secrets)))+
|
|
field('reason','Änderungsgrund','',{full:true,placeholder:'Grund für diesen Profilstand'});
|
|
showModal(existing?'Neue Profilversion':'Profil erstellen',form(fields,'Entwurf speichern'),async data=>{
|
|
const builds=readDataEditor(modal,'profile-builds');
|
|
if(!builds.length||builds.some(build=>typeof build!=='string'||!build.trim()))throw new Error('Bitte mindestens einen tatsächlich geprüften Zielbuild angeben.');
|
|
const configuration=install?{values:readInstallationEditor(modal,'installation',p.values||{}),steps:[]}:readPostinstallEditor(modal,p);
|
|
const body={name:data.get('name'),kind,target_builds:builds.map(build=>build.trim()),...configuration,reason:data.get('reason')||''};
|
|
if(Object.hasOwn(p,'locked_fields'))body.locked_fields=p.locked_fields;
|
|
await api('/profiles',{method:'POST',body});closeModal();toast('Profilentwurf gespeichert.');await refresh();
|
|
},install?'INSTALLATIONSPROFIL':'POSTINSTALLATIONSPROFIL');
|
|
wireDataEditors(modal);
|
|
if(install)wireInstallationEditor(modal,'installation');else wirePostinstallEditor(modal,arr(modules).filter(m=>m.status==='published'),arr(secrets));
|
|
}
|
|
async function graphicalModuleForm(existing=null) {
|
|
const m=existing||{};
|
|
const [catalog,modules]=await Promise.all([api('/modules/builtin'),api('/modules')]);
|
|
const templates=arr(catalog);
|
|
let source=m.source||'';
|
|
let schema=structuredClone(m.parameters_schema||{type:'object',properties:{},additionalProperties:false});
|
|
let previousTemplateName='';
|
|
const currentTemplate=templates.find(item=>item.id===m.id||item.source===m.source);
|
|
const fields=field('name','Modulname',m.name,{required:true,full:true,placeholder:'PVE-Dienste prüfen'})+
|
|
`<section class="form-section full"><h3>Modul auswählen</h3><div class="form-grid">${field('module_template','Vorlage',currentTemplate?.id||'',{type:'select',full:true,options:[{value:'',label:source?'Vorhandenes Skript beibehalten':'Vorlage auswählen oder Skriptdatei laden'},...templates.map(item=>({value:item.id,label:item.name}))]})}<label class="full">Eigene Skriptdatei laden<input type="file" accept=".sh,text/plain,application/x-sh" data-module-file><small>Eine vorhandene Bash-Datei mit check-, apply- und verify-Aufrufen auswählen.</small></label></div><p class="source-status" data-source-status>${source?'Skript übernommen.':'Noch kein Skript ausgewählt.'}</p><details><summary>Skript ansehen</summary><pre class="code-block script-preview" data-source-preview>${esc(source)}</pre></details></section>`+
|
|
dataEditor('module-builds',arr(m.target_builds),{label:'Unterstützte Zielbuilds',schema:{type:'array',items:{type:'string'}}})+
|
|
field('timeout_seconds','Timeout in Sekunden',m.timeout_seconds??300,{type:'number',required:true,min:1,max:7200,full:true})+
|
|
`<div class="full" data-schema-container>${moduleSchemaEditor(schema)}</div>`+
|
|
`<div class="full" data-dependencies-container>${dataEditor('module-dependencies',arr(m.dependencies),{label:'Vorher benötigte Module',schema:{type:'array',items:{type:'string',enum:[...new Set([...arr(modules).map(item=>item.name),...templates.map(item=>item.name),...arr(m.dependencies)])]}}})}</div>`+
|
|
field('retry_safe','Apply darf nach Zustandsprüfung wiederholt werden.',m.retry_safe??false,{type:'checkbox',full:true,hint:'Nur aktivieren, wenn die Wiederholbarkeit nachgewiesen wurde.'})+
|
|
field('reason','Änderungsgrund','',{full:true});
|
|
showModal(existing?'Neue Modulversion':'Skriptmodul erstellen',form(fields,'Entwurf speichern'),async data=>{
|
|
if(!source)throw new Error('Bitte eine Vorlage oder Skriptdatei auswählen.');
|
|
const builds=readDataEditor(modal,'module-builds');
|
|
if(!builds.length||builds.some(build=>typeof build!=='string'||!build.trim()))throw new Error('Bitte mindestens einen geprüften Zielbuild angeben.');
|
|
await api('/modules',{method:'POST',body:{name:data.get('name'),source,parameters_schema:readModuleSchemaEditor(modal,schema),dependencies:readDataEditor(modal,'module-dependencies'),target_builds:builds.map(build=>build.trim()),timeout_seconds:Number(data.get('timeout_seconds')),retry_safe:data.get('retry_safe')==='on',reason:data.get('reason')||''}});closeModal();toast('Modulentwurf gespeichert.');await refresh();
|
|
},'VERSIONIERTE SKRIPTMODULE');
|
|
wireDataEditors(modal);
|
|
wireModuleSchemaEditor(modal);
|
|
const updateSource=label=>{modal.querySelector('[data-source-status]').textContent=label;modal.querySelector('[data-source-preview]').textContent=source;};
|
|
modal.querySelector('[name="module_template"]').addEventListener('change',event=>{
|
|
const template=templates.find(item=>item.id===event.target.value);
|
|
if(!template)return;
|
|
source=template.source;
|
|
const nameInput=modal.querySelector('[name="name"]');
|
|
if(!nameInput.value||nameInput.value===previousTemplateName)nameInput.value=template.name;
|
|
previousTemplateName=template.name;
|
|
schema=structuredClone(template.parameters_schema);
|
|
modal.querySelector('[data-schema-container]').innerHTML=moduleSchemaEditor(schema);
|
|
modal.querySelector('[data-dependencies-container]').innerHTML=dataEditor('module-dependencies',template.dependencies,{label:'Vorher benötigte Module',schema:{type:'array',items:{type:'string',enum:[...new Set([...arr(modules).map(item=>item.name),...templates.map(item=>item.name)])]}}});
|
|
modal.querySelector('[name="timeout_seconds"]').value=template.timeout_seconds;
|
|
modal.querySelector('[name="retry_safe"]').checked=template.retry_safe;
|
|
wireModuleSchemaEditor(modal);
|
|
updateSource(`${template.name}: Vorlage übernommen.`);
|
|
});
|
|
modal.querySelector('[data-module-file]').addEventListener('change',async event=>{
|
|
const file=event.target.files[0];
|
|
if(!file)return;
|
|
if(file.size>262144){toast('Die Skriptdatei darf höchstens 256 KiB groß sein.',true);event.target.value='';return;}
|
|
try{source=await file.text();modal.querySelector('[name="module_template"]').value='';updateSource(`${file.name}: Skript geladen.`);}catch{toast('Die Skriptdatei konnte nicht gelesen werden.',true);}
|
|
});
|
|
}
|