pipeline enhance for MI

This commit is contained in:
Anthony Stirling 2023-12-31 13:05:38 +00:00
parent eda91cc556
commit f535387ac4
3 changed files with 521 additions and 482 deletions

View file

@ -138,7 +138,7 @@ public class PipelineProcessor {
hasErrors = true; hasErrors = true;
} }
outputFiles = newOutputFiles;
} }
} else { } else {
@ -177,11 +177,13 @@ public class PipelineProcessor {
} }
} }
logPrintStream.close(); logPrintStream.close();
outputFiles = newOutputFiles;
} }
if (hasErrors) { if (hasErrors) {
logger.error("Errors occurred during processing. Log: {}", logStream.toString()); logger.error("Errors occurred during processing. Log: {}", logStream.toString());
} }
return outputFiles; return outputFiles;
} }

View file

@ -1,475 +1,496 @@
document.getElementById('validateButton').addEventListener('click', function(event) { document.getElementById('validateButton').addEventListener('click', function(event) {
event.preventDefault(); event.preventDefault();
validatePipeline(); validatePipeline();
});
function validatePipeline() {
let pipelineListItems = document.getElementById('pipelineList').children;
let isValid = true;
let containsAddPassword = false;
for (let i = 0; i < pipelineListItems.length - 1; i++) {
let currentOperation = pipelineListItems[i].querySelector('.operationName').textContent;
let nextOperation = pipelineListItems[i + 1].querySelector('.operationName').textContent;
if (currentOperation === '/add-password') {
containsAddPassword = true;
}
let currentOperationDescription = apiDocs[currentOperation]?.post?.description || "";
let nextOperationDescription = apiDocs[nextOperation]?.post?.description || "";
// Strip off 'ZIP-' prefix
currentOperationDescription = currentOperationDescription.replace("ZIP-", '');
nextOperationDescription = nextOperationDescription.replace("ZIP-", '');
let currentOperationOutput = currentOperationDescription.match(/Output:([A-Z\/]*)/)?.[1] || "";
let nextOperationInput = nextOperationDescription.match(/Input:([A-Z\/]*)/)?.[1] || "";
// Splitting in case of multiple possible output/input
let currentOperationOutputArr = currentOperationOutput.split('/');
let nextOperationInputArr = nextOperationInput.split('/');
if (currentOperationOutput !== 'ANY' && nextOperationInput !== 'ANY') {
let intersection = currentOperationOutputArr.filter(value => nextOperationInputArr.includes(value));
console.log(`Intersection: ${intersection}`);
if (intersection.length === 0) {
updateValidateButton(false);
isValid = false;
console.log(`Incompatible operations: The output of operation '${currentOperation}' (${currentOperationOutput}) is not compatible with the input of the following operation '${nextOperation}' (${nextOperationInput}).`);
alert(`Incompatible operations: The output of operation '${currentOperation}' (${currentOperationOutput}) is not compatible with the input of the following operation '${nextOperation}' (${nextOperationInput}).`);
break;
}
}
}
if (containsAddPassword && pipelineListItems[pipelineListItems.length - 1].querySelector('.operationName').textContent !== '/add-password') {
updateValidateButton(false);
alert('The "add-password" operation should be at the end of the operations sequence. Please adjust the operations order.');
return false;
}
if (isValid) {
console.log('Pipeline is valid');
// Continue with the pipeline operation
} else {
console.error('Pipeline is not valid');
// Stop operation, maybe display an error to the user
}
updateValidateButton(isValid);
return isValid;
}
function updateValidateButton(isValid) {
var validateButton = document.getElementById('validateButton');
if (isValid) {
validateButton.classList.remove('btn-danger');
validateButton.classList.add('btn-success');
} else {
validateButton.classList.remove('btn-success');
validateButton.classList.add('btn-danger');
}
}
document.getElementById('submitConfigBtn').addEventListener('click', function() {
if (validatePipeline() === false) {
return;
}
let selectedOperation = document.getElementById('operationsDropdown').value;
var pipelineName = document.getElementById('pipelineName').value;
let pipelineList = document.getElementById('pipelineList').children;
let pipelineConfig = {
"name": pipelineName,
"pipeline": [],
"_examples": {
"outputDir": "{outputFolder}/{folderName}",
"outputFileName": "{filename}-{pipelineName}-{date}-{time}"
},
"outputDir": "httpWebRequest",
"outputFileName": "{filename}"
};
for (let i = 0; i < pipelineList.length; i++) {
let operationName = pipelineList[i].querySelector('.operationName').textContent;
let parameters = operationSettings[operationName] || {};
pipelineConfig.pipeline.push({
"operation": operationName,
"parameters": parameters
});
}
let pipelineConfigJson = JSON.stringify(pipelineConfig, null, 2);
let formData = new FormData();
let fileInput = document.getElementById('fileInput-input');
let files = fileInput.files;
for (let i = 0; i < files.length; i++) {
console.log("files[i]", files[i].name);
formData.append('fileInput', files[i], files[i].name);
}
console.log("pipelineConfigJson", pipelineConfigJson);
formData.append('json', pipelineConfigJson);
console.log("formData", formData);
fetch('api/v1/pipeline/handleData', {
method: 'POST',
body: formData
})
.then(response => {
// Save the response to use it later
const responseToUseLater = response;
return response.blob().then(blob => {
let url = window.URL.createObjectURL(blob);
let a = document.createElement('a');
a.href = url;
// Use responseToUseLater instead of response
const contentDisposition = responseToUseLater.headers.get('Content-Disposition');
let filename = 'download';
if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) {
filename = decodeURIComponent(contentDisposition.split('filename=')[1].replace(/"/g, '')).trim();
}
a.download = filename;
document.body.appendChild(a);
a.click();
a.remove();
});
})
.catch((error) => {
console.error('Error:', error);
}); });
function validatePipeline() {
}); let pipelineListItems = document.getElementById('pipelineList').children;
let isValid = true;
let apiDocs = {}; let containsAddPassword = false;
let apiSchemas = {}; for (let i = 0; i < pipelineListItems.length - 1; i++) {
let operationSettings = {}; let currentOperation = pipelineListItems[i].querySelector('.operationName').textContent;
let nextOperation = pipelineListItems[i + 1].querySelector('.operationName').textContent;
fetch('v1/api-docs') if (currentOperation === '/add-password') {
.then(response => response.json()) containsAddPassword = true;
.then(data => {
apiDocs = data.paths;
apiSchemas = data.components.schemas;
let operationsDropdown = document.getElementById('operationsDropdown');
const ignoreOperations = ["/api/v1/pipeline/handleData", "/api/v1/pipeline/operationToIgnore"]; // Add the operations you want to ignore here
operationsDropdown.innerHTML = '';
let operationsByTag = {};
// Group operations by tags
Object.keys(data.paths).forEach(operationPath => {
let operation = data.paths[operationPath].post;
if(!operation || !operation.description) {
console.log(operationPath);
} }
if (operation && !ignoreOperations.includes(operationPath) && !operation.description.includes("Type:MISO")) {
let operationTag = operation.tags[0]; // This assumes each operation has exactly one tag let currentOperationDescription = apiDocs[currentOperation]?.post?.description || "";
if (!operationsByTag[operationTag]) { let nextOperationDescription = apiDocs[nextOperation]?.post?.description || "";
operationsByTag[operationTag] = [];
// Strip off 'ZIP-' prefix
currentOperationDescription = currentOperationDescription.replace("ZIP-", '');
nextOperationDescription = nextOperationDescription.replace("ZIP-", '');
let currentOperationOutput = currentOperationDescription.match(/Output:([A-Z\/]*)/)?.[1] || "";
let nextOperationInput = nextOperationDescription.match(/Input:([A-Z\/]*)/)?.[1] || "";
// Splitting in case of multiple possible output/input
let currentOperationOutputArr = currentOperationOutput.split('/');
let nextOperationInputArr = nextOperationInput.split('/');
if (currentOperationOutput !== 'ANY' && nextOperationInput !== 'ANY') {
let intersection = currentOperationOutputArr.filter(value => nextOperationInputArr.includes(value));
console.log(`Intersection: ${intersection}`);
if (intersection.length === 0) {
updateValidateButton(false);
isValid = false;
console.log(`Incompatible operations: The output of operation '${currentOperation}' (${currentOperationOutput}) is not compatible with the input of the following operation '${nextOperation}' (${nextOperationInput}).`);
alert(`Incompatible operations: The output of operation '${currentOperation}' (${currentOperationOutput}) is not compatible with the input of the following operation '${nextOperation}' (${nextOperationInput}).`);
break;
} }
operationsByTag[operationTag].push(operationPath);
} }
}); }
// Specify the order of tags if (containsAddPassword && pipelineListItems[pipelineListItems.length - 1].querySelector('.operationName').textContent !== '/add-password') {
let tagOrder = ["General", "Security", "Convert", "Misc", "Filter"]; updateValidateButton(false);
alert('The "add-password" operation should be at the end of the operations sequence. Please adjust the operations order.');
return false;
}
if (isValid) {
console.log('Pipeline is valid');
// Continue with the pipeline operation
} else {
console.error('Pipeline is not valid');
// Stop operation, maybe display an error to the user
}
updateValidateButton(isValid);
return isValid;
}
// Create dropdown options function updateValidateButton(isValid) {
tagOrder.forEach(tag => { var validateButton = document.getElementById('validateButton');
if (operationsByTag[tag]) { if (isValid) {
let group = document.createElement('optgroup'); validateButton.classList.remove('btn-danger');
group.label = tag; validateButton.classList.add('btn-success');
} else {
operationsByTag[tag].forEach(operationPath => { validateButton.classList.remove('btn-success');
let option = document.createElement('option'); validateButton.classList.add('btn-danger');
}
let operationPathDisplay = operationPath
operationPathDisplay = operationPath.replace(new RegExp("api/v1/" + tag.toLowerCase() + "/", 'i'), "");
if(operationPath.includes("/convert")){
operationPathDisplay = operationPathDisplay.replace(/^\//, '').replaceAll("/", " to ");
} else {
operationPathDisplay = operationPathDisplay.replace(/\//g, ''); // Remove slashes
}
operationPathDisplay = operationPathDisplay.replaceAll(" ","-");
option.textContent = operationPathDisplay;
option.value = operationPath; // Keep the value with slashes for querying
group.appendChild(option);
});
operationsDropdown.appendChild(group);
}
});
});
document.getElementById('addOperationBtn').addEventListener('click', function() {
let selectedOperation = document.getElementById('operationsDropdown').value;
let pipelineList = document.getElementById('pipelineList');
let listItem = document.createElement('li');
listItem.className = "list-group-item";
let hasSettings = false;
if (apiDocs[selectedOperation] && apiDocs[selectedOperation].post) {
const postMethod = apiDocs[selectedOperation].post;
// Check if parameters exist
if (postMethod.parameters && postMethod.parameters.length > 0) {
hasSettings = true;
} else if (postMethod.requestBody && postMethod.requestBody.content['multipart/form-data']) {
// Extract the reference key
const refKey = postMethod.requestBody.content['multipart/form-data'].schema['$ref'].split('/').pop();
// Check if the referenced schema exists and has properties
if (apiSchemas[refKey] && Object.keys(apiSchemas[refKey].properties).length > 0) {
hasSettings = true;
}
}
} }
listItem.innerHTML = ` document.getElementById('submitConfigBtn').addEventListener('click', function() {
<div class="d-flex justify-content-between align-items-center w-100">
<div class="operationName">${selectedOperation}</div>
<div class="arrows d-flex">
<button class="btn btn-secondary move-up ms-1"><span>&uarr;</span></button>
<button class="btn btn-secondary move-down ms-1"><span>&darr;</span></button>
<button class="btn ${hasSettings ? 'btn-warning' : 'btn-secondary'} pipelineSettings ms-1" ${hasSettings ? "" : "disabled"}>
<span style="color: ${hasSettings ? "white" : "grey"};"></span>
</button>
<button class="btn btn-danger remove ms-1"><span>X</span></button>
</div>
</div>
`;
if (validatePipeline() === false) {
pipelineList.appendChild(listItem); return;
listItem.querySelector('.move-up').addEventListener('click', function(event) {
event.preventDefault();
if (listItem.previousElementSibling) {
pipelineList.insertBefore(listItem, listItem.previousElementSibling);
} }
}); let selectedOperation = document.getElementById('operationsDropdown').value;
listItem.querySelector('.move-down').addEventListener('click', function(event) {
event.preventDefault();
if (listItem.nextElementSibling) { var pipelineName = document.getElementById('pipelineName').value;
pipelineList.insertBefore(listItem.nextElementSibling, listItem); let pipelineList = document.getElementById('pipelineList').children;
let pipelineConfig = {
"name": pipelineName,
"pipeline": [],
"_examples": {
"outputDir": "{outputFolder}/{folderName}",
"outputFileName": "{filename}-{pipelineName}-{date}-{time}"
},
"outputDir": "httpWebRequest",
"outputFileName": "{filename}"
};
for (let i = 0; i < pipelineList.length; i++) {
let operationName = pipelineList[i].querySelector('.operationName').textContent;
let parameters = operationSettings[operationName] || {};
pipelineConfig.pipeline.push({
"operation": operationName,
"parameters": parameters
});
} }
});
listItem.querySelector('.remove').addEventListener('click', function(event) {
event.preventDefault();
pipelineList.removeChild(listItem);
hideOrShowPipelineHeader();
});
listItem.querySelector('.pipelineSettings').addEventListener('click', function(event) {
event.preventDefault();
showpipelineSettingsModal(selectedOperation);
hideOrShowPipelineHeader();
});
function showpipelineSettingsModal(operation) {
let pipelineSettingsModal = document.getElementById('pipelineSettingsModal');
let pipelineSettingsContent = document.getElementById('pipelineSettingsContent');
let operationData = apiDocs[operation].post.parameters || [];
// Resolve the $ref reference to get actual schema properties
let refKey = apiDocs[operation].post.requestBody.content['multipart/form-data'].schema['$ref'].split('/').pop();
let requestBodyData = apiSchemas[refKey].properties || {};
// Combine operationData and requestBodyData into a single array
operationData = operationData.concat(Object.keys(requestBodyData).map(key => ({
name: key,
schema: requestBodyData[key]
})));
pipelineSettingsContent.innerHTML = '';
operationData.forEach(parameter => {
// If the parameter name is 'fileInput', return early to skip the rest of this iteration
if (parameter.name === 'fileInput') return;
let parameterDiv = document.createElement('div');
parameterDiv.className = "mb-3";
let parameterLabel = document.createElement('label');
parameterLabel.textContent = `${parameter.name} (${parameter.schema.type}): `;
parameterLabel.title = parameter.schema.description;
parameterLabel.setAttribute('for', parameter.name);
parameterDiv.appendChild(parameterLabel);
let defaultValue = parameter.schema.example;
if (defaultValue === undefined) defaultValue = parameter.schema.default;
let parameterInput;
// check if enum exists in schema
if (parameter.schema.enum) {
// if enum exists, create a select element
parameterInput = document.createElement('select');
parameterInput.className = "form-control";
// iterate over each enum value and create an option for it let pipelineConfigJson = JSON.stringify(pipelineConfig, null, 2);
parameter.schema.enum.forEach(value => {
let option = document.createElement('option'); let formData = new FormData();
option.value = value;
option.text = value; let fileInput = document.getElementById('fileInput-input');
parameterInput.appendChild(option); let files = fileInput.files;
for (let i = 0; i < files.length; i++) {
console.log("files[i]", files[i].name);
formData.append('fileInput', files[i], files[i].name);
}
console.log("pipelineConfigJson", pipelineConfigJson);
formData.append('json', pipelineConfigJson);
console.log("formData", formData);
fetch('api/v1/pipeline/handleData', {
method: 'POST',
body: formData
})
.then(response => {
// Save the response to use it later
const responseToUseLater = response;
return response.blob().then(blob => {
let url = window.URL.createObjectURL(blob);
let a = document.createElement('a');
a.href = url;
// Use responseToUseLater instead of response
const contentDisposition = responseToUseLater.headers.get('Content-Disposition');
let filename = 'download';
if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) {
filename = decodeURIComponent(contentDisposition.split('filename=')[1].replace(/"/g, '')).trim();
}
a.download = filename;
document.body.appendChild(a);
a.click();
a.remove();
}); });
} else { })
// switch-case statement for handling non-enum types .catch((error) => {
switch (parameter.schema.type) { console.error('Error:', error);
case 'string': });
if (parameter.schema.format === 'binary') {
// This is a file input
//parameterInput = document.createElement('input'); });
//parameterInput.type = 'file';
//parameterInput.className = "form-control";
parameterInput = document.createElement('input'); let apiDocs = {};
parameterInput.type = 'text'; let apiSchemas = {};
parameterInput.className = "form-control"; let operationSettings = {};
parameterInput.value = "FileInputPathToBeInputtedManuallyOffline";
fetch('v1/api-docs')
.then(response => response.json())
.then(data => {
apiDocs = data.paths;
apiSchemas = data.components.schemas;
let operationsDropdown = document.getElementById('operationsDropdown');
const ignoreOperations = ["/api/v1/pipeline/handleData", "/api/v1/pipeline/operationToIgnore"]; // Add the operations you want to ignore here
operationsDropdown.innerHTML = '';
let operationsByTag = {};
// Group operations by tags
Object.keys(data.paths).forEach(operationPath => {
let operation = data.paths[operationPath].post;
if (!operation || !operation.description) {
console.log(operationPath);
}
//!operation.description.includes("Type:MISO")
if (operation && !ignoreOperations.includes(operationPath)) {
let operationTag = operation.tags[0]; // This assumes each operation has exactly one tag
if (!operationsByTag[operationTag]) {
operationsByTag[operationTag] = [];
}
operationsByTag[operationTag].push(operationPath);
}
});
// Specify the order of tags
let tagOrder = ["General", "Security", "Convert", "Misc", "Filter"];
// Create dropdown options
tagOrder.forEach(tag => {
if (operationsByTag[tag]) {
let group = document.createElement('optgroup');
group.label = tag;
operationsByTag[tag].forEach(operationPath => {
let option = document.createElement('option');
let operationPathDisplay = operationPath
operationPathDisplay = operationPath.replace(new RegExp("api/v1/" + tag.toLowerCase() + "/", 'i'), "");
if (operationPath.includes("/convert")) {
operationPathDisplay = operationPathDisplay.replace(/^\//, '').replaceAll("/", " to ");
} else { } else {
operationPathDisplay = operationPathDisplay.replace(/\//g, ''); // Remove slashes
}
operationPathDisplay = operationPathDisplay.replaceAll(" ", "-");
option.textContent = operationPathDisplay;
option.value = operationPath; // Keep the value with slashes for querying
group.appendChild(option);
});
operationsDropdown.appendChild(group);
}
});
});
document.getElementById('addOperationBtn').addEventListener('click', function() {
let selectedOperation = document.getElementById('operationsDropdown').value;
let pipelineList = document.getElementById('pipelineList');
let listItem = document.createElement('li');
listItem.className = "list-group-item";
let hasSettings = false;
if (apiDocs[selectedOperation] && apiDocs[selectedOperation].post) {
const postMethod = apiDocs[selectedOperation].post;
// Check if parameters exist
if (postMethod.parameters && postMethod.parameters.length > 0) {
hasSettings = true;
} else if (postMethod.requestBody && postMethod.requestBody.content['multipart/form-data']) {
// Extract the reference key
const refKey = postMethod.requestBody.content['multipart/form-data'].schema['$ref'].split('/').pop();
// Check if the referenced schema exists and has properties
if (apiSchemas[refKey] && Object.keys(apiSchemas[refKey].properties).length > 0) {
hasSettings = true;
}
}
}
listItem.innerHTML = `
<div class="d-flex justify-content-between align-items-center w-100">
<div class="operationName">${selectedOperation}</div>
<div class="arrows d-flex">
<button class="btn btn-secondary move-up ms-1"><span>&uarr;</span></button>
<button class="btn btn-secondary move-down ms-1"><span>&darr;</span></button>
<button class="btn ${hasSettings ? 'btn-warning' : 'btn-secondary'} pipelineSettings ms-1" ${hasSettings ? "" : "disabled"}>
<span style="color: ${hasSettings ? "white" : "grey"};"></span>
</button>
<button class="btn btn-danger remove ms-1"><span>X</span></button>
</div>
</div>
`;
pipelineList.appendChild(listItem);
listItem.querySelector('.move-up').addEventListener('click', function(event) {
event.preventDefault();
if (listItem.previousElementSibling) {
pipelineList.insertBefore(listItem, listItem.previousElementSibling);
updateConfigInDropdown();
}
});
listItem.querySelector('.move-down').addEventListener('click', function(event) {
event.preventDefault();
if (listItem.nextElementSibling) {
pipelineList.insertBefore(listItem.nextElementSibling, listItem);
updateConfigInDropdown();
}
});
listItem.querySelector('.remove').addEventListener('click', function(event) {
event.preventDefault();
pipelineList.removeChild(listItem);
hideOrShowPipelineHeader();
updateConfigInDropdown();
});
listItem.querySelector('.pipelineSettings').addEventListener('click', function(event) {
event.preventDefault();
showpipelineSettingsModal(selectedOperation);
hideOrShowPipelineHeader();
});
function showpipelineSettingsModal(operation) {
let pipelineSettingsModal = document.getElementById('pipelineSettingsModal');
let pipelineSettingsContent = document.getElementById('pipelineSettingsContent');
let operationData = apiDocs[operation].post.parameters || [];
// Resolve the $ref reference to get actual schema properties
let refKey = apiDocs[operation].post.requestBody.content['multipart/form-data'].schema['$ref'].split('/').pop();
let requestBodyData = apiSchemas[refKey].properties || {};
// Combine operationData and requestBodyData into a single array
operationData = operationData.concat(Object.keys(requestBodyData).map(key => ({
name: key,
schema: requestBodyData[key]
})));
pipelineSettingsContent.innerHTML = '';
operationData.forEach(parameter => {
// If the parameter name is 'fileInput', return early to skip the rest of this iteration
if (parameter.name === 'fileInput') return;
let parameterDiv = document.createElement('div');
parameterDiv.className = "mb-3";
let parameterLabel = document.createElement('label');
parameterLabel.textContent = `${parameter.name} (${parameter.schema.type}): `;
parameterLabel.title = parameter.schema.description;
parameterLabel.setAttribute('for', parameter.name);
parameterDiv.appendChild(parameterLabel);
let defaultValue = parameter.schema.example;
if (defaultValue === undefined) defaultValue = parameter.schema.default;
let parameterInput;
// check if enum exists in schema
if (parameter.schema.enum) {
// if enum exists, create a select element
parameterInput = document.createElement('select');
parameterInput.className = "form-control";
// iterate over each enum value and create an option for it
parameter.schema.enum.forEach(value => {
let option = document.createElement('option');
option.value = value;
option.text = value;
parameterInput.appendChild(option);
});
} else {
// switch-case statement for handling non-enum types
switch (parameter.schema.type) {
case 'string':
if (parameter.schema.format === 'binary') {
// This is a file input
//parameterInput = document.createElement('input');
//parameterInput.type = 'file';
//parameterInput.className = "form-control";
parameterInput = document.createElement('input');
parameterInput.type = 'text';
parameterInput.className = "form-control";
parameterInput.value = "FileInputPathToBeInputtedManuallyOffline";
} else {
parameterInput = document.createElement('input');
parameterInput.type = 'text';
parameterInput.className = "form-control";
if (defaultValue !== undefined) parameterInput.value = defaultValue;
}
break;
case 'number':
case 'integer':
parameterInput = document.createElement('input');
parameterInput.type = 'number';
parameterInput.className = "form-control";
if (defaultValue !== undefined) parameterInput.value = defaultValue;
break;
case 'boolean':
parameterInput = document.createElement('input');
parameterInput.type = 'checkbox';
if (defaultValue === true) parameterInput.checked = true;
break;
case 'array':
case 'object':
parameterInput = document.createElement('textarea');
parameterInput.placeholder = `Enter a JSON formatted ${parameter.schema.type}`;
parameterInput.className = "form-control";
break;
default:
parameterInput = document.createElement('input'); parameterInput = document.createElement('input');
parameterInput.type = 'text'; parameterInput.type = 'text';
parameterInput.className = "form-control"; parameterInput.className = "form-control";
if (defaultValue !== undefined) parameterInput.value = defaultValue; if (defaultValue !== undefined) parameterInput.value = defaultValue;
} }
break;
case 'number':
case 'integer':
parameterInput = document.createElement('input');
parameterInput.type = 'number';
parameterInput.className = "form-control";
if (defaultValue !== undefined) parameterInput.value = defaultValue;
break;
case 'boolean':
parameterInput = document.createElement('input');
parameterInput.type = 'checkbox';
if (defaultValue === true) parameterInput.checked = true;
break;
case 'array':
case 'object':
parameterInput = document.createElement('textarea');
parameterInput.placeholder = `Enter a JSON formatted ${parameter.schema.type}`;
parameterInput.className = "form-control";
break;
default:
parameterInput = document.createElement('input');
parameterInput.type = 'text';
parameterInput.className = "form-control";
if (defaultValue !== undefined) parameterInput.value = defaultValue;
} }
} parameterInput.id = parameter.name;
parameterInput.id = parameter.name;
console.log("defaultValue", defaultValue); console.log("defaultValue", defaultValue);
console.log("parameterInput", parameterInput); console.log("parameterInput", parameterInput);
if (operationSettings[operation] && operationSettings[operation][parameter.name] !== undefined) { if (operationSettings[operation] && operationSettings[operation][parameter.name] !== undefined) {
let savedValue = operationSettings[operation][parameter.name]; let savedValue = operationSettings[operation][parameter.name];
switch (parameter.schema.type) {
case 'number':
case 'integer':
parameterInput.value = savedValue.toString();
break;
case 'boolean':
parameterInput.checked = savedValue;
break;
case 'array':
case 'object':
parameterInput.value = JSON.stringify(savedValue);
break;
default:
parameterInput.value = savedValue;
}
}
console.log("parameterInput2", parameterInput);
parameterDiv.appendChild(parameterInput);
pipelineSettingsContent.appendChild(parameterDiv);
});
let saveButton = document.createElement('button');
saveButton.textContent = "Save Settings";
saveButton.className = "btn btn-primary";
saveButton.addEventListener('click', function(event) {
event.preventDefault();
let settings = {};
operationData.forEach(parameter => {
if(parameter.name !== "fileInput"){
let value = document.getElementById(parameter.name).value;
switch (parameter.schema.type) { switch (parameter.schema.type) {
case 'number': case 'number':
case 'integer': case 'integer':
settings[parameter.name] = Number(value); parameterInput.value = savedValue.toString();
break; break;
case 'boolean': case 'boolean':
settings[parameter.name] = document.getElementById(parameter.name).checked; parameterInput.checked = savedValue;
break; break;
case 'array': case 'array':
case 'object': case 'object':
try { parameterInput.value = JSON.stringify(savedValue);
settings[parameter.name] = JSON.parse(value);
} catch (err) {
console.error(`Invalid JSON format for ${parameter.name}`);
}
break; break;
default: default:
settings[parameter.name] = value; parameterInput.value = savedValue;
} }
} }
console.log("parameterInput2", parameterInput);
parameterDiv.appendChild(parameterInput);
pipelineSettingsContent.appendChild(parameterDiv);
}); });
operationSettings[operation] = settings;
//pipelineSettingsModal.style.display = "none";
});
pipelineSettingsContent.appendChild(saveButton);
//pipelineSettingsModal.style.display = "block"; let saveButton = document.createElement('button');
saveButton.textContent = "Save Settings";
saveButton.className = "btn btn-primary";
saveButton.addEventListener('click', function(event) {
event.preventDefault();
let settings = {};
operationData.forEach(parameter => {
if (parameter.name !== "fileInput") {
let value = document.getElementById(parameter.name).value;
switch (parameter.schema.type) {
case 'number':
case 'integer':
settings[parameter.name] = Number(value);
break;
case 'boolean':
settings[parameter.name] = document.getElementById(parameter.name).checked;
break;
case 'array':
case 'object':
try {
settings[parameter.name] = JSON.parse(value);
} catch (err) {
console.error(`Invalid JSON format for ${parameter.name}`);
}
break;
default:
settings[parameter.name] = value;
}
}
});
operationSettings[operation] = settings;
//pipelineSettingsModal.style.display = "none";
});
pipelineSettingsContent.appendChild(saveButton);
//pipelineSettingsModal.getElementsByClassName("close")[0].onclick = function() { //pipelineSettingsModal.style.display = "block";
// pipelineSettingsModal.style.display = "none";
//} //pipelineSettingsModal.getElementsByClassName("close")[0].onclick = function() {
// pipelineSettingsModal.style.display = "none";
//}
//window.onclick = function(event) {
// if (event.target == pipelineSettingsModal) {
// pipelineSettingsModal.style.display = "none";
// }
//}
}
updateConfigInDropdown();
hideOrShowPipelineHeader();
});
function updateConfigInDropdown() {
let pipelineSelect = document.getElementById('pipelineSelect');
let selectedOption = pipelineSelect.options[pipelineSelect.selectedIndex];
// Get the current configuration as JSON
let pipelineConfigJson = configToJson();
console.log("pipelineConfigJson", pipelineConfigJson);
if (!pipelineConfigJson) {
console.error("Failed to update configuration: Invalid configuration");
return;
}
// Update the value of the selected option with the new configuration
selectedOption.value = pipelineConfigJson;
//window.onclick = function(event) {
// if (event.target == pipelineSettingsModal) {
// pipelineSettingsModal.style.display = "none";
// }
//}
} }
hideOrShowPipelineHeader();
});
var saveBtn = document.getElementById('savePipelineBtn'); var saveBtn = document.getElementById('savePipelineBtn');
@ -479,10 +500,10 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
// Add the event listener // Add the event listener
saveBtn.addEventListener('click', savePipeline); saveBtn.addEventListener('click', savePipeline);
console.log("saveBtn", saveBtn) console.log("saveBtn", saveBtn)
function savePipeline() {
if (validatePipeline() === false) { function configToJson() {
return; if (!validatePipeline()) {
return null; // Return null if validation fails
} }
var pipelineName = document.getElementById('pipelineName').value; var pipelineName = document.getElementById('pipelineName').value;
@ -509,11 +530,23 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
"parameters": parameters "parameters": parameters
}); });
} }
console.log("Downloading..");
return JSON.stringify(pipelineConfig, null, 2);
}
function savePipeline() {
let pipelineConfigJson = configToJson();
if (!pipelineConfigJson) {
console.error("Failed to save pipeline: Invalid configuration");
return;
}
let pipelineName = document.getElementById('pipelineName').value;
console.log("Downloading...");
let a = document.createElement('a'); let a = document.createElement('a');
a.href = URL.createObjectURL(new Blob([JSON.stringify(pipelineConfig, null, 2)], { a.href = URL.createObjectURL(new Blob([pipelineConfigJson], { type: 'application/json' }));
type: 'application/json'
}));
a.download = pipelineName + '.json'; a.download = pipelineName + '.json';
a.style.display = 'none'; a.style.display = 'none';
@ -522,7 +555,9 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
document.body.removeChild(a); document.body.removeChild(a);
} }
async function processPipelineConfig(configString) { async function processPipelineConfig(configString) {
console.log("configString",configString);
let pipelineConfig = JSON.parse(configString); let pipelineConfig = JSON.parse(configString);
let pipelineList = document.getElementById('pipelineList'); let pipelineList = document.getElementById('pipelineList');
@ -596,14 +631,14 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
function hideOrShowPipelineHeader() { function hideOrShowPipelineHeader() {
var pipelineHeader = document.getElementById('pipelineHeader'); var pipelineHeader = document.getElementById('pipelineHeader');
var pipelineList = document.getElementById('pipelineList'); var pipelineList = document.getElementById('pipelineList');
if (pipelineList.children.length === 0) { if (pipelineList.children.length === 0) {
// Hide the pipeline header if there are no items in the pipeline list // Hide the pipeline header if there are no items in the pipeline list
pipelineHeader.style.display = 'none'; pipelineHeader.style.display = 'none';
} else { } else {
// Show the pipeline header if there are items in the pipeline list // Show the pipeline header if there are items in the pipeline list
pipelineHeader.style.display = 'block'; pipelineHeader.style.display = 'block';
} }
} }

View file

@ -48,6 +48,8 @@
<div class="center-element"> <div class="center-element">
<div class="element-margin"> <div class="element-margin">
<select id="pipelineSelect" class="custom-select"> <select id="pipelineSelect" class="custom-select">
<option value="{&quot;name&quot;:&quot;Custom&quot;,&quot;pipeline&quot;:[],&quot;_examples&quot;:{&quot;outputDir&quot;:&quot;{outputFolder}/{folderName}&quot;,&quot;outputFileName&quot;:&quot;{filename}-{pipelineName}-{date}-{time}&quot;},&quot;outputDir&quot;:&quot;{outputFolder}&quot;,&quot;outputFileName&quot;:&quot;{filename}&quot;}" th:text="Custom"></option>
<th:block th:each="config : ${pipelineConfigsWithNames}"> <th:block th:each="config : ${pipelineConfigsWithNames}">
<option th:value="${config.json}" th:text="${config.name}"></option> <option th:value="${config.json}" th:text="${config.name}"></option>
</th:block> </th:block>