pipeline stuff

This commit is contained in:
Anthony Stirling 2023-07-12 00:17:44 +01:00
parent 94526de04b
commit 50bcca10e2
6 changed files with 1242 additions and 1180 deletions

View File

@ -59,6 +59,9 @@ public class SPdfApplication {
GeneralUtils.createDir("customFiles/static/"); GeneralUtils.createDir("customFiles/static/");
GeneralUtils.createDir("customFiles/templates/"); GeneralUtils.createDir("customFiles/templates/");
GeneralUtils.createDir("config"); GeneralUtils.createDir("config");
System.out.println("Stirling-PDF Started."); System.out.println("Stirling-PDF Started.");
String port = System.getProperty("local.server.port"); String port = System.getProperty("local.server.port");

View File

@ -60,8 +60,8 @@ public class Controller {
private ObjectMapper objectMapper; private ObjectMapper objectMapper;
final String jsonFileName = "pipelineConfig.json"; final String jsonFileName = "pipelineConfig.json";
final String watchedFoldersDir = "watchedFolders/"; final String watchedFoldersDir = "./pipeline/watchedFolders/";
final String finishedFoldersDir = "finishedFolders/"; final String finishedFoldersDir = "./pipeline/finishedFolders/";
@Scheduled(fixedRate = 25000) @Scheduled(fixedRate = 25000)
public void scanFolders() { public void scanFolders() {

View File

@ -1,29 +1,77 @@
package stirling.software.SPDF.controller.web; package stirling.software.SPDF.controller.web;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.v3.oas.annotations.Hidden; import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@Controller @Controller
@Tag(name = "General", description = "General APIs") @Tag(name = "General", description = "General APIs")
public class GeneralWebController { public class GeneralWebController {
@GetMapping("/pipeline")
@Hidden @GetMapping("/pipeline")
public String pipelineForm(Model model) { @Hidden
model.addAttribute("currentPage", "pipeline"); public String pipelineForm(Model model) {
return "pipeline"; model.addAttribute("currentPage", "pipeline");
List<String> pipelineConfigs = new ArrayList<>();
try (Stream<Path> paths = Files.walk(Paths.get("./pipeline/defaultWebUIConfigs/"))) {
List<Path> jsonFiles = paths
.filter(Files::isRegularFile)
.filter(p -> p.toString().endsWith(".json"))
.collect(Collectors.toList());
for (Path jsonFile : jsonFiles) {
String content = Files.readString(jsonFile, StandardCharsets.UTF_8);
pipelineConfigs.add(content);
}
List<Map<String, String>> pipelineConfigsWithNames = new ArrayList<>();
for (String config : pipelineConfigs) {
Map<String, Object> jsonContent = new ObjectMapper().readValue(config, Map.class);
String name = (String) jsonContent.get("name");
Map<String, String> configWithName = new HashMap<>();
configWithName.put("json", config);
configWithName.put("name", name);
pipelineConfigsWithNames.add(configWithName);
}
model.addAttribute("pipelineConfigsWithNames", pipelineConfigsWithNames);
} catch (IOException e) {
e.printStackTrace();
} }
model.addAttribute("pipelineConfigs", pipelineConfigs);
return "pipeline";
}
@GetMapping("/merge-pdfs") @GetMapping("/merge-pdfs")
@Hidden @Hidden
public String mergePdfForm(Model model) { public String mergePdfForm(Model model) {

View File

@ -381,52 +381,76 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
document.body.removeChild(a); document.body.removeChild(a);
}); });
async function processPipelineConfig(configString) {
let pipelineConfig = JSON.parse(configString);
let pipelineList = document.getElementById('pipelineList');
while (pipelineList.firstChild) {
pipelineList.removeChild(pipelineList.firstChild);
}
document.getElementById('pipelineName').value = pipelineConfig.name
for (const operationConfig of pipelineConfig.pipeline) {
let operationsDropdown = document.getElementById('operationsDropdown');
operationsDropdown.value = operationConfig.operation;
operationSettings[operationConfig.operation] = operationConfig.parameters;
// assuming addOperation is async
await new Promise((resolve) => {
document.getElementById('addOperationBtn').addEventListener('click', resolve, { once: true });
document.getElementById('addOperationBtn').click();
});
let lastOperation = pipelineList.lastChild;
Object.keys(operationConfig.parameters).forEach(parameterName => {
let input = document.getElementById(parameterName);
if (input) {
switch (input.type) {
case 'checkbox':
input.checked = operationConfig.parameters[parameterName];
break;
case 'number':
input.value = operationConfig.parameters[parameterName].toString();
break;
case 'file':
if (parameterName !== 'fileInput') {
// Create a new file input element
let newInput = document.createElement('input');
newInput.type = 'file';
newInput.id = parameterName;
// Add the new file input to the main page (change the selector according to your needs)
document.querySelector('#main').appendChild(newInput);
}
break;
case 'text':
case 'textarea':
default:
input.value = JSON.stringify(operationConfig.parameters[parameterName]);
}
}
});
}
}
document.getElementById('uploadPipelineBtn').addEventListener('click', function() { document.getElementById('uploadPipelineBtn').addEventListener('click', function() {
document.getElementById('uploadPipelineInput').click(); document.getElementById('uploadPipelineInput').click();
}); });
document.getElementById('uploadPipelineInput').addEventListener('change', function(e) { document.getElementById('uploadPipelineInput').addEventListener('change', function(e) {
let reader = new FileReader(); let reader = new FileReader();
reader.onload = function(event) { reader.onload = function(event) {
let pipelineConfig = JSON.parse(event.target.result); processPipelineConfig(event.target.result);
let pipelineList = document.getElementById('pipelineList'); };
reader.readAsText(e.target.files[0]);
while (pipelineList.firstChild) {
pipelineList.removeChild(pipelineList.firstChild);
}
document.getElementById('pipelineName').value = pipelineConfig.name
pipelineConfig.pipeline.forEach(operationConfig => {
let operationsDropdown = document.getElementById('operationsDropdown');
operationsDropdown.value = operationConfig.operation;
operationSettings[operationConfig.operation] = operationConfig.parameters;
document.getElementById('addOperationBtn').click();
let lastOperation = pipelineList.lastChild;
lastOperation.querySelector('.pipelineSettings').click();
Object.keys(operationConfig.parameters).forEach(parameterName => {
let input = document.getElementById(parameterName);
if (input) {
switch (input.type) {
case 'checkbox':
input.checked = operationConfig.parameters[parameterName];
break;
case 'number':
input.value = operationConfig.parameters[parameterName].toString();
break;
case 'text':
case 'textarea':
default:
input.value = JSON.stringify(operationConfig.parameters[parameterName]);
}
}
});
document.querySelector('#pipelineSettingsModal .btn-primary').click();
});
};
reader.readAsText(e.target.files[0]);
}); });
document.getElementById('pipelineSelect').addEventListener('change', function(e) {
let selectedPipelineJson = e.target.value; // assuming the selected value is the JSON string of the pipeline config
processPipelineConfig(selectedPipelineJson);
});
}); });

View File

@ -11,102 +11,89 @@
<br> <br> <br> <br>
<div class="container" id="dropContainer"> <div class="container" id="dropContainer">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6">
<div class="mb-3"> <!-- Trigger/Open The Modal -->
<button id="savePipelineBtn" class="btn btn-success">Download</button> <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#pipelineSettingsModal">
Open Pipeline Settings
<button id="validateButton" class="btn btn-success">Validate</button> </button>
<div class="btn-group">
<button id="uploadPipelineBtn" class="btn btn-primary">Upload</button>
<input type="file" id="uploadPipelineInput" accept=".json" <button id="uploadPipelineBtn" class="btn btn-primary">Upload Custom Pipeline</button>
style="display: none;"> <select id="pipelineSelect">
</div> <option value="">Select a pipeline</option>
</div> <th:block th:each="config : ${pipelineConfigsWithNames}">
<option th:value="${config.json}" th:text="${config.name}"></option>
<div id="pipelineContainer" class="card"> </th:block>
<!-- Pipeline Configuration Card Header --> </select>
<div class="card-header">
<h2 class="card-title">Pipeline Configuration</h2>
</div>
<input type="file" id="fileInput" multiple>
<!-- Pipeline Configuration Body --> <button class="btn btn-primary" id="submitConfigBtn">Submit</button>
<div class="card-body">
<div class="mb-3">
<label for="pipelineName" class="form-label">Pipeline Name</label> <!-- The Modal -->
<input type="text" id="pipelineName" class="form-control" placeholder="Enter pipeline name here"> <div class="modal" id="pipelineSettingsModal">
</div> <div class="modal-dialog">
<div class="mb-3"> <div class="modal-content">
<select id="operationsDropdown" class="form-select">
<!-- Options will be dynamically populated here --> <!-- Modal Header -->
</select> <div class="modal-header">
</div> <h2 class="modal-title">Pipeline Configuration</h2>
<div class="mb-3"> <button type="button" class="close" data-dismiss="modal">&times;</button>
<button id="addOperationBtn" class="btn btn-primary">Add operation</button> </div>
</div>
<h3>Pipeline:</h3> <!-- Modal body -->
<ol id="pipelineList" class="list-group"> <div class="modal-body">
<!-- Pipeline operations will be dynamically populated here --> <div class="mb-3">
</ol> <label for="pipelineName" class="form-label">Pipeline Name</label>
</div> <input type="text" id="pipelineName" class="form-control" placeholder="Enter pipeline name here">
</div>
<input type="file" id="fileInput" multiple> <div class="mb-3">
<select id="operationsDropdown" class="form-select">
<button class="btn btn-primary" id="submitConfigBtn">Submit</button> <!-- Options will be dynamically populated here -->
</select>
</div>
<div class="mb-3">
<button id="addOperationBtn" class="btn btn-primary">Add operation</button>
</div>
<h3>Pipeline:</h3>
<ol id="pipelineList" class="list-group">
<!-- Pipeline operations will be dynamically populated here -->
</ol>
<div id="pipelineSettingsContent">
<!-- pipelineSettings will be dynamically populated here -->
</div>
</div>
<!-- Modal footer -->
<div class="modal-footer">
<button id="savePipelineBtn" class="btn btn-success">Download</button>
<button id="validateButton" class="btn btn-success">Validate</button>
<div class="btn-group">
<input type="file" id="uploadPipelineInput" accept=".json" style="display: none;">
</div>
</div>
</div>
</div>
</div>
<script src="js/pipeline.js"></script>
</div>
<!-- pipelineSettings modal -->
<div id="pipelineSettingsModal" class="modal">
<div class="modal-content">
<div class="modal-body">
<span class="close">&times;</span>
<h2>Operation Settings</h2>
<div id="pipelineSettingsContent">
<!-- pipelineSettings will be dynamically populated here -->
</div>
</div>
</div>
<script src="js/pipeline.js"></script>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
<style> <style>
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
padding-top: 100px; /* Location of the box */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0, 0, 0); /* Fallback color */
background-color: rgba(0, 0, 0, 0.4); /* Black w/ opacity */
}
/* Modal Content */
.modal-content {
background-color: #fefefe;
margin: auto;
padding: 20px;
border: 1px solid #888;
width: 50%;
}
.btn-margin { .btn-margin {
margin-right: 2px; margin-right: 2px;
} }
.modal-body {
display: flex;
flex-direction: column;
}
</style> </style>
<div th:insert="~{fragments/footer.html :: footer}"></div> <div th:insert="~{fragments/footer.html :: footer}"></div>
</div> </div>