Merge pull request #623 from Stirling-Tools/changes

pipeline Changes and example yml for testing
This commit is contained in:
Anthony Stirling 2024-01-01 19:32:59 +00:00 committed by GitHub
commit 7389543af6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 3324 additions and 2118 deletions

View file

@ -1,6 +1,6 @@
plugins { plugins {
id 'java' id 'java'
id 'org.springframework.boot' version '3.1.2' id 'org.springframework.boot' version '3.2.1'
id 'io.spring.dependency-management' version '1.1.3' id 'io.spring.dependency-management' version '1.1.3'
id 'org.springdoc.openapi-gradle-plugin' version '1.8.0' id 'org.springdoc.openapi-gradle-plugin' version '1.8.0'
id "io.swagger.swaggerhub" version "1.3.2" id "io.swagger.swaggerhub" version "1.3.2"
@ -80,17 +80,19 @@ dependencies {
//security updates //security updates
implementation 'ch.qos.logback:logback-classic:1.4.14' implementation 'ch.qos.logback:logback-classic:1.4.14'
implementation 'ch.qos.logback:logback-core:1.4.14' implementation 'ch.qos.logback:logback-core:1.4.14'
implementation 'org.springframework:spring-webmvc:6.0.15' implementation 'org.springframework:spring-webmvc:6.1.2'
implementation 'org.yaml:snakeyaml:2.1' implementation 'org.yaml:snakeyaml:2.2'
implementation 'org.springframework.boot:spring-boot-starter-web:3.2.1' implementation 'org.springframework.boot:spring-boot-starter-web:3.2.1'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.2.1' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.2.1'
if (System.getenv('DOCKER_ENABLE_SECURITY') != 'false') { if (System.getenv('DOCKER_ENABLE_SECURITY') != 'false') {
implementation 'org.springframework.boot:spring-boot-starter-security:3.2.1' implementation 'org.springframework.boot:spring-boot-starter-security:3.2.1'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE' implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5:3.1.2.RELEASE'
implementation "org.springframework.boot:spring-boot-starter-data-jpa" implementation "org.springframework.boot:spring-boot-starter-data-jpa:3.2.1"
implementation "com.h2database:h2"
//2.2.x requires rebuild of DB file.. need migration path
implementation "com.h2database:h2:2.1.214"
} }
testImplementation 'org.springframework.boot:spring-boot-starter-test:3.2.1' testImplementation 'org.springframework.boot:spring-boot-starter-test:3.2.1'
@ -122,7 +124,7 @@ dependencies {
//general PDF //general PDF
// https://mvnrepository.com/artifact/com.opencsv/opencsv // https://mvnrepository.com/artifact/com.opencsv/opencsv
implementation ('com.opencsv:opencsv:5.7.1') { implementation ('com.opencsv:opencsv:5.9') {
exclude group: 'commons-logging', module: 'commons-logging' exclude group: 'commons-logging', module: 'commons-logging'
} }

View file

@ -0,0 +1,31 @@
version: '3.3'
services:
stirling-pdf:
container_name: Stirling-PDF-Lite-Security
image: frooodle/s-pdf:latest-lite
deploy:
resources:
limits:
memory: 2G
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -q 'Please sign in'"]
interval: 5s
timeout: 10s
retries: 16
ports:
- 8080:8080
volumes:
- /stirling/latest/data:/usr/share/tesseract-ocr/5/tessdata:rw
- /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "true"
SECURITY_ENABLELOGIN: "true"
SYSTEM_DEFAULTLOCALE: en_US
UI_APPNAME: Stirling-PDF-Lite
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF-Lite Latest with Security
UI_APPNAMENAVBAR: Stirling-PDF-Lite Latest
SYSTEM_MAXFILESIZE: "100"
METRICS_ENABLED: "true"
SYSTEM_GOOGLEVISIBILITY: "true"
restart: on-failure:5

View file

@ -0,0 +1,30 @@
version: '3.3'
services:
stirling-pdf:
container_name: Stirling-PDF-Lite
image: frooodle/s-pdf:latest-lite
deploy:
resources:
limits:
memory: 2G
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -qv 'Please sign in'"]
interval: 5s
timeout: 10s
retries: 16
ports:
- 8080:8080
volumes:
- /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "false"
SECURITY_ENABLELOGIN: "false"
SYSTEM_DEFAULTLOCALE: en_US
UI_APPNAME: Stirling-PDF-Lite
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF-Lite Latest
UI_APPNAMENAVBAR: Stirling-PDF-Lite Latest
SYSTEM_MAXFILESIZE: "100"
METRICS_ENABLED: "true"
SYSTEM_GOOGLEVISIBILITY: "true"
restart: on-failure:5

View file

@ -0,0 +1,31 @@
version: '3.3'
services:
stirling-pdf:
container_name: Stirling-PDF-Security
image: frooodle/s-pdf:latest
deploy:
resources:
limits:
memory: 4G
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -q 'Please sign in'"]
interval: 5s
timeout: 10s
retries: 16
ports:
- 8080:8080
volumes:
- /stirling/latest/data:/usr/share/tesseract-ocr/5/tessdata:rw
- /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "true"
SECURITY_ENABLELOGIN: "true"
SYSTEM_DEFAULTLOCALE: en_US
UI_APPNAME: Stirling-PDF
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest with Security
UI_APPNAMENAVBAR: Stirling-PDF Latest
SYSTEM_MAXFILESIZE: "100"
METRICS_ENABLED: "true"
SYSTEM_GOOGLEVISIBILITY: "true"
restart: on-failure:5

View file

@ -0,0 +1,31 @@
version: '3.3'
services:
stirling-pdf:
container_name: Stirling-PDF-Ultra-Lite-Security
image: frooodle/s-pdf:latest-ultra-lite
deploy:
resources:
limits:
memory: 1G
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -q 'Please sign in'"]
interval: 5s
timeout: 10s
retries: 16
ports:
- 8080:8080
volumes:
- /stirling/latest/data:/usr/share/tesseract-ocr/5/tessdata:rw
- /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "true"
SECURITY_ENABLELOGIN: "true"
SYSTEM_DEFAULTLOCALE: en_US
UI_APPNAME: Stirling-PDF-Lite
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF-Lite Latest with Security
UI_APPNAMENAVBAR: Stirling-PDF-Lite Latest
SYSTEM_MAXFILESIZE: "100"
METRICS_ENABLED: "true"
SYSTEM_GOOGLEVISIBILITY: "true"
restart: on-failure:5

View file

@ -0,0 +1,30 @@
version: '3.3'
services:
stirling-pdf:
container_name: Stirling-PDF-Ultra-Lite
image: frooodle/s-pdf:latest-ultra-lite
deploy:
resources:
limits:
memory: 1G
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -qv 'Please sign in'"]
interval: 5s
timeout: 10s
retries: 16
ports:
- 8080:8080
volumes:
- /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "false"
SECURITY_ENABLELOGIN: "false"
SYSTEM_DEFAULTLOCALE: en_US
UI_APPNAME: Stirling-PDF-Ultra-lite
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF-Ultra-lite Latest
UI_APPNAMENAVBAR: Stirling-PDF-Ultra-lite Latest
SYSTEM_MAXFILESIZE: "100"
METRICS_ENABLED: "true"
SYSTEM_GOOGLEVISIBILITY: "true"
restart: on-failure:5

View file

@ -0,0 +1,31 @@
version: '3.3'
services:
stirling-pdf:
container_name: Stirling-PDF
image: frooodle/s-pdf:latest
deploy:
resources:
limits:
memory: 4G
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/api/v1/info/status | grep -q 'UP' && curl -fL http://localhost:8080/ | grep -qv 'Please sign in'"]
interval: 5s
timeout: 10s
retries: 16
ports:
- 8080:8080
volumes:
- /stirling/latest/data:/usr/share/tesseract-ocr/5/tessdata:rw
- /stirling/latest/config:/configs:rw
- /stirling/latest/logs:/logs:rw
environment:
DOCKER_ENABLE_SECURITY: "false"
SECURITY_ENABLELOGIN: "false"
SYSTEM_DEFAULTLOCALE: en_US
UI_APPNAME: Stirling-PDF
UI_HOMEDESCRIPTION: Demo site for Stirling-PDF Latest
UI_APPNAMENAVBAR: Stirling-PDF Latest
SYSTEM_MAXFILESIZE: "100"
METRICS_ENABLED: "true"
SYSTEM_GOOGLEVISIBILITY: "true"
restart: on-failure:5

View file

@ -102,7 +102,9 @@ public class SecurityConfiguration {
|| trimmedUri.startsWith("/images/") || trimmedUri.startsWith("/images/")
|| trimmedUri.startsWith("/public/") || trimmedUri.startsWith("/public/")
|| trimmedUri.startsWith("/css/") || trimmedUri.startsWith("/css/")
|| trimmedUri.startsWith("/js/"); || trimmedUri.startsWith("/js/")
|| trimmedUri.startsWith(
"/api/v1/info/status");
}) })
.permitAll() .permitAll()
.anyRequest() .anyRequest()
@ -113,6 +115,7 @@ public class SecurityConfiguration {
http.csrf(csrf -> csrf.disable()) http.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(authz -> authz.anyRequest().permitAll()); .authorizeHttpRequests(authz -> authz.anyRequest().permitAll());
} }
return http.build(); return http.build();
} }

View file

@ -103,6 +103,7 @@ public class UserAuthenticationFilter extends OncePerRequestFilter {
contextPath + "/css/", contextPath + "/css/",
contextPath + "/js/", contextPath + "/js/",
contextPath + "/pdfjs/", contextPath + "/pdfjs/",
contextPath + "/api/v1/info/status",
contextPath + "/site.webmanifest" contextPath + "/site.webmanifest"
}; };

View file

@ -120,6 +120,10 @@ public class SplitPdfBySectionsController {
float translateX = -subPageWidth * i; float translateX = -subPageWidth * i;
float translateY = height - subPageHeight * (verticalDivisions - j); float translateY = height - subPageHeight * (verticalDivisions - j);
//Code for google Docs pdfs..
//float translateY = -subPageHeight * (verticalDivisions - 1 - j);
contentStream.saveGraphicsState(); contentStream.saveGraphicsState();
contentStream.addRect(0, 0, subPageWidth, subPageHeight); contentStream.addRect(0, 0, subPageWidth, subPageHeight);
contentStream.clip(); contentStream.clip();

View file

@ -79,7 +79,7 @@ public class ConvertOfficeController {
@Operation( @Operation(
summary = "Convert a file to a PDF using LibreOffice", summary = "Convert a file to a PDF using LibreOffice",
description = description =
"This endpoint converts a given file to a PDF using LibreOffice API Input:Any Output:PDF Type:SISO") "This endpoint converts a given file to a PDF using LibreOffice API Input:ANY Output:PDF Type:SISO")
public ResponseEntity<byte[]> processFileToPDF(@ModelAttribute GeneralFile request) public ResponseEntity<byte[]> processFileToPDF(@ModelAttribute GeneralFile request)
throws Exception { throws Exception {
MultipartFile inputFile = request.getFileInput(); MultipartFile inputFile = request.getFileInput();

View file

@ -2,7 +2,9 @@ package stirling.software.SPDF.controller.api.pipeline;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.InputStream; import java.io.InputStream;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream; import java.util.zip.ZipOutputStream;
@ -84,9 +86,26 @@ public class PipelineController {
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream zipOut = new ZipOutputStream(baos); ZipOutputStream zipOut = new ZipOutputStream(baos);
// A map to keep track of filenames and their counts
Map<String, Integer> filenameCount = new HashMap<>();
// Loop through each file and add it to the zip // Loop through each file and add it to the zip
for (Resource file : outputFiles) { for (Resource file : outputFiles) {
ZipEntry zipEntry = new ZipEntry(file.getFilename()); String originalFilename = file.getFilename();
String filename = originalFilename;
// Check if the filename already exists, and modify it if necessary
if (filenameCount.containsKey(originalFilename)) {
int count = filenameCount.get(originalFilename);
String baseName = originalFilename.replaceAll("\\.[^.]*$", "");
String extension = originalFilename.replaceAll("^.*\\.", "");
filename = baseName + "(" + count + ")." + extension;
filenameCount.put(originalFilename, count + 1);
} else {
filenameCount.put(originalFilename, 1);
}
ZipEntry zipEntry = new ZipEntry(filename);
zipOut.putNextEntry(zipEntry); zipOut.putNextEntry(zipEntry);
// Read the file into a byte array // Read the file into a byte array

View file

@ -5,6 +5,8 @@ import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream; import java.io.PrintStream;
import java.net.URLDecoder;
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;
@ -132,8 +134,6 @@ public class PipelineProcessor {
+ operation); + operation);
hasErrors = true; hasErrors = true;
} }
outputFiles = newOutputFiles;
} }
} else { } else {
@ -185,10 +185,12 @@ 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;
} }
@ -196,6 +198,7 @@ public class PipelineProcessor {
RestTemplate restTemplate = new RestTemplate(); RestTemplate restTemplate = new RestTemplate();
// Set up headers, including API key // Set up headers, including API key
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
String apiKey = getApiKeyForUser(); String apiKey = getApiKeyForUser();
headers.add("X-API-Key", apiKey); headers.add("X-API-Key", apiKey);
@ -216,11 +219,12 @@ public class PipelineProcessor {
throws IOException { throws IOException {
// Define filename // Define filename
String newFilename; String newFilename;
if ("auto-rename".equals(operation)) { if (operation.contains("auto-rename")) {
// If the operation is "auto-rename", generate a new filename. // If the operation is "auto-rename", generate a new filename.
// This is a simple example of generating a filename using current timestamp. // This is a simple example of generating a filename using current timestamp.
// Modify as per your needs. // Modify as per your needs.
newFilename = "file_" + System.currentTimeMillis();
newFilename = extractFilename(response);
} else { } else {
// Otherwise, keep the original filename. // Otherwise, keep the original filename.
newFilename = fileName; newFilename = fileName;
@ -244,6 +248,28 @@ public class PipelineProcessor {
return newOutputFiles; return newOutputFiles;
} }
public String extractFilename(ResponseEntity<byte[]> response) {
String filename = "default-filename.ext"; // Default filename if not found
HttpHeaders headers = response.getHeaders();
String contentDisposition = headers.getFirst(HttpHeaders.CONTENT_DISPOSITION);
if (contentDisposition != null && !contentDisposition.isEmpty()) {
String[] parts = contentDisposition.split(";");
for (String part : parts) {
if (part.trim().startsWith("filename")) {
// Extracts filename and removes quotes if present
filename = part.split("=")[1].trim().replace("\"", "");
filename = URLDecoder.decode(filename, StandardCharsets.UTF_8);
break;
}
}
}
return filename;
}
List<Resource> generateInputFiles(File[] files) throws Exception { List<Resource> generateInputFiles(File[] files) throws Exception {
if (files == null || files.length == 0) { if (files == null || files.length == 0) {
logger.info("No files"); logger.info("No files");

View file

@ -59,6 +59,14 @@ public class GeneralWebController {
.readValue(config, new TypeReference<Map<String, Object>>() {}); .readValue(config, new TypeReference<Map<String, Object>>() {});
String name = (String) jsonContent.get("name"); String name = (String) jsonContent.get("name");
if (name == null || name.length() < 1) {
String filename =
jsonFiles
.get(pipelineConfigs.indexOf(config))
.getFileName()
.toString();
name = filename.substring(0, filename.lastIndexOf('.'));
}
Map<String, String> configWithName = new HashMap<>(); Map<String, String> configWithName = new HashMap<>();
configWithName.put("json", config); configWithName.put("json", config);
configWithName.put("name", name); configWithName.put("name", name);

View file

@ -9,6 +9,7 @@ public class RequestUriUtils {
|| requestURI.startsWith("/images/") || requestURI.startsWith("/images/")
|| requestURI.startsWith("/public/") || requestURI.startsWith("/public/")
|| requestURI.startsWith("/pdfjs/") || requestURI.startsWith("/pdfjs/")
|| requestURI.endsWith(".svg"); || requestURI.endsWith(".svg")
|| requestURI.startsWith("/api/v1/info/status");
} }
} }

View file

@ -1,4 +1,4 @@
fileToPDF.fileTypesList=Microsoft Word: (DOC, DOCX, DOT, DOTX) <br> \ fileToPDF.fileTypesList=Microsoft Word: (DOC, DOCX, DOT, DOTX) <br> \
Microsoft Excel: (CSV, XLS, XLSX, XLT, XLTX, SLK, DIF) <br> \ Microsoft Excel: (CSV, XLS, XLSX, XLT, XLTX, SLK, DIF) <br> \
Microsoft PowerPoint: (PPT, PPTX) <br> \ Microsoft PowerPoint: (PPT, PPTX) <br> \
OpenDocument Formats: (ODT, OTT, ODS, OTS, ODP, OTP, ODG, OTG) <br> \ OpenDocument Formats: (ODT, OTT, ODS, OTS, ODP, OTP, ODG, OTG) <br> \

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Red
green=Green green=Green
blue=Blue blue=Blue
custom=Custom... custom=Custom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Credentials changed! changedCredsMessage=Credentials changed!
notAuthenticatedMessage=User not authenticated. notAuthenticatedMessage=User not authenticated.
@ -50,6 +51,29 @@ incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Червено
green=Зелено green=Зелено
blue=Синьо blue=Синьо
custom=Персонализиране... custom=Персонализиране...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Идентификационните данни са променени! changedCredsMessage=Идентификационните данни са променени!
notAuthenticatedMessage=Потребителят не е автентикиран. notAuthenticatedMessage=Потребителят не е автентикиран.
@ -50,6 +51,29 @@ incorrectPasswordMessage=Текущата парола е неправилна.
usernameExistsMessage=Новият потребител вече съществува. usernameExistsMessage=Новият потребител вече съществува.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Vermell
green=Verd green=Verd
blue=Blau blue=Blau
custom=Personalitzat... custom=Personalitzat...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Credentials changed! changedCredsMessage=Credentials changed!
notAuthenticatedMessage=User not authenticated. notAuthenticatedMessage=User not authenticated.
@ -50,6 +51,29 @@ incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Rot
green=Grün green=Grün
blue=Blau blue=Blau
custom=benutzerdefiniert... custom=benutzerdefiniert...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Anmeldedaten geändert! changedCredsMessage=Anmeldedaten geändert!
notAuthenticatedMessage=Benutzer nicht authentifiziert. notAuthenticatedMessage=Benutzer nicht authentifiziert.
@ -50,6 +51,29 @@ incorrectPasswordMessage=Das Passwort ist falsch.
usernameExistsMessage=Neuer Benutzername existiert bereits. usernameExistsMessage=Neuer Benutzername existiert bereits.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=\u039A\u03CC\u03BA\u03BA\u03B9\u03BD\u03BF
green=\u03A0\u03C1\u03AC\u03C3\u03B9\u03BD\u03BF green=\u03A0\u03C1\u03AC\u03C3\u03B9\u03BD\u03BF
blue=\u039C\u03C0\u03BB\u03AD blue=\u039C\u03C0\u03BB\u03AD
custom=\u03A0\u03C1\u03BF\u03C3\u03B1\u03C1\u03BC\u03BF\u03B3\u03AE... custom=\u03A0\u03C1\u03BF\u03C3\u03B1\u03C1\u03BC\u03BF\u03B3\u03AE...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=\u03A4\u03B1 \u03B4\u03B9\u03B1\u03C0\u03B9\u03C3\u03C4\u03B5\u03C5\u03C4\u03AE\u03C1\u03B9\u03B1 \u03AD\u03C7\u03BF\u03C5\u03BD \u03B1\u03BB\u03BB\u03AC\u03BE\u03B5\u03B9! changedCredsMessage=\u03A4\u03B1 \u03B4\u03B9\u03B1\u03C0\u03B9\u03C3\u03C4\u03B5\u03C5\u03C4\u03AE\u03C1\u03B9\u03B1 \u03AD\u03C7\u03BF\u03C5\u03BD \u03B1\u03BB\u03BB\u03AC\u03BE\u03B5\u03B9!
notAuthenticatedMessage=\u039F \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03B4\u03B5\u03BD \u03AD\u03C7\u03B5\u03B9 \u03B1\u03C5\u03B8\u03B5\u03BD\u03C4\u03B9\u03BA\u03BF\u03C0\u03BF\u03B9\u03B7\u03B8\u03B5\u03AF. notAuthenticatedMessage=\u039F \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7\u03C2 \u03B4\u03B5\u03BD \u03AD\u03C7\u03B5\u03B9 \u03B1\u03C5\u03B8\u03B5\u03BD\u03C4\u03B9\u03BA\u03BF\u03C0\u03BF\u03B9\u03B7\u03B8\u03B5\u03AF.
@ -50,6 +51,29 @@ incorrectPasswordMessage=\u039F \u03C4\u03C1\u03AD\u03C7\u03C9\u03BD \u03BA\u03C
usernameExistsMessage=\u03A4\u03BF \u03BD\u03AD\u03BF \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03C5\u03C0\u03AC\u03C1\u03C7\u03B5\u03B9 \u03AE\u03B4\u03B7. usernameExistsMessage=\u03A4\u03BF \u03BD\u03AD\u03BF \u03CC\u03BD\u03BF\u03BC\u03B1 \u03C7\u03C1\u03AE\u03C3\u03C4\u03B7 \u03C5\u03C0\u03AC\u03C1\u03C7\u03B5\u03B9 \u03AE\u03B4\u03B7.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr = left to right, rtl = right to left) # the direction that the language is written (ltr = left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Red
green=Green green=Green
blue=Blue blue=Blue
custom=Custom... custom=Custom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Credentials changed! changedCredsMessage=Credentials changed!
notAuthenticatedMessage=User not authenticated. notAuthenticatedMessage=User not authenticated.
@ -50,6 +51,29 @@ incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Red
green=Green green=Green
blue=Blue blue=Blue
custom=Custom... custom=Custom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Credentials changed! changedCredsMessage=Credentials changed!
notAuthenticatedMessage=User not authenticated. notAuthenticatedMessage=User not authenticated.
@ -50,6 +51,29 @@ incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Rojo
green=Verde green=Verde
blue=Azul blue=Azul
custom=Personalizado... custom=Personalizado...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Se cambiaron las credenciales! changedCredsMessage=Se cambiaron las credenciales!
notAuthenticatedMessage=Usuario no autentificado. notAuthenticatedMessage=Usuario no autentificado.
@ -50,6 +51,29 @@ incorrectPasswordMessage=La contraseña actual no es correcta.
usernameExistsMessage=El nuevo nombre de usuario está en uso. usernameExistsMessage=El nuevo nombre de usuario está en uso.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Gorria
green=Berdea green=Berdea
blue=Urdina blue=Urdina
custom=Pertsonalizatu... custom=Pertsonalizatu...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Credentials changed! changedCredsMessage=Credentials changed!
notAuthenticatedMessage=User not authenticated. notAuthenticatedMessage=User not authenticated.
@ -50,6 +51,29 @@ incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Rouge
green=Vert green=Vert
blue=Bleu blue=Bleu
custom=Personnalisé\u2026 custom=Personnalisé\u2026
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Les identifiants ont été mis à jour\u00a0! changedCredsMessage=Les identifiants ont été mis à jour\u00a0!
notAuthenticatedMessage=Utilisateur non authentifié. notAuthenticatedMessage=Utilisateur non authentifié.
@ -50,6 +51,29 @@ incorrectPasswordMessage=Le mot de passe actuel est incorrect.
usernameExistsMessage=Le nouveau nom d\u2019utilisateur existe déjà. usernameExistsMessage=Le nouveau nom d\u2019utilisateur existe déjà.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=लाल
green=हरा green=हरा
blue=नीला blue=नीला
custom=कस्टम... custom=कस्टम...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=क्रेडेंशियल्स बदल दी गईं! changedCredsMessage=क्रेडेंशियल्स बदल दी गईं!
notAuthenticatedMessage=उपयोगकर्ता प्रमाणित नहीं है। notAuthenticatedMessage=उपयोगकर्ता प्रमाणित नहीं है।
@ -50,6 +51,29 @@ incorrectPasswordMessage=वर्तमान पासवर्ड गलत
usernameExistsMessage=नया उपयोगकर्ता नाम पहले से मौजूद है। usernameExistsMessage=नया उपयोगकर्ता नाम पहले से मौजूद है।
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Piros
green=Zöld green=Zöld
blue=Kék blue=Kék
custom=Egyedi... custom=Egyedi...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=A hitelek megváltoztak! changedCredsMessage=A hitelek megváltoztak!
notAuthenticatedMessage=Felhasználó nincs hitelesítve. notAuthenticatedMessage=Felhasználó nincs hitelesítve.
@ -50,6 +51,29 @@ incorrectPasswordMessage=A jelenlegi jelszó helytelen.
usernameExistsMessage=Az új felhasználónév már létezik. usernameExistsMessage=Az új felhasználónév már létezik.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl=right to left) # the direction that the language is written (ltr=left to right, rtl=right to left)
@ -42,6 +42,7 @@ red=Merah
green=Hijau green=Hijau
blue=Biru blue=Biru
custom=Kustom... custom=Kustom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Kredensial berubah!! changedCredsMessage=Kredensial berubah!!
notAuthenticatedMessage=Pengguna tidak ter-autentikasi. notAuthenticatedMessage=Pengguna tidak ter-autentikasi.
@ -50,6 +51,29 @@ incorrectPasswordMessage=Kata sandi saat ini salah.
usernameExistsMessage=Nama pengguna baru sudah ada. usernameExistsMessage=Nama pengguna baru sudah ada.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Rosso
green=Verde green=Verde
blue=Blu blue=Blu
custom=Personalizzato custom=Personalizzato
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Credenziali cambiate! changedCredsMessage=Credenziali cambiate!
notAuthenticatedMessage=Utente non autenticato. notAuthenticatedMessage=Utente non autenticato.
@ -50,6 +51,29 @@ incorrectPasswordMessage=La password attuale non è corretta.
usernameExistsMessage=Il nuovo nome utente esiste già. usernameExistsMessage=Il nuovo nome utente esiste già.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=赤
green= green=
blue= blue=
custom=カスタム... custom=カスタム...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=資格情報が変更されました! changedCredsMessage=資格情報が変更されました!
notAuthenticatedMessage=ユーザーが認証されていません。 notAuthenticatedMessage=ユーザーが認証されていません。
@ -50,6 +51,29 @@ incorrectPasswordMessage=現在のパスワードが正しくありません。
usernameExistsMessage=新しいユーザー名はすでに存在します。 usernameExistsMessage=新しいユーザー名はすでに存在します。
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Red
green=Green green=Green
blue=Blue blue=Blue
custom=Custom... custom=Custom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=계정 정보 변경 성공! changedCredsMessage=계정 정보 변경 성공!
notAuthenticatedMessage=User not authenticated. notAuthenticatedMessage=User not authenticated.
@ -50,6 +51,29 @@ incorrectPasswordMessage=현재 비밀번호가 틀립니다.
usernameExistsMessage=새 사용자명이 이미 존재합니다. usernameExistsMessage=새 사용자명이 이미 존재합니다.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Red
green=Green green=Green
blue=Blue blue=Blue
custom=Custom... custom=Custom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Credentials changed! changedCredsMessage=Credentials changed!
notAuthenticatedMessage=User not authenticated. notAuthenticatedMessage=User not authenticated.
@ -50,6 +51,29 @@ incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Red
green=Green green=Green
blue=Blue blue=Blue
custom=Custom... custom=Custom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Credentials changed! changedCredsMessage=Credentials changed!
notAuthenticatedMessage=User not authenticated. notAuthenticatedMessage=User not authenticated.
@ -50,6 +51,29 @@ incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Red
green=Green green=Green
blue=Blue blue=Blue
custom=Custom... custom=Custom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Credentials changed! changedCredsMessage=Credentials changed!
notAuthenticatedMessage=User not authenticated. notAuthenticatedMessage=User not authenticated.
@ -50,6 +51,29 @@ incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #
@ -119,6 +143,7 @@ adminUserSettings.role=Role
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
adminUserSettings.apiUser=Limited API User adminUserSettings.apiUser=Limited API User
adminUserSettings.webOnlyUser=Web Only User adminUserSettings.webOnlyUser=Web Only User
adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.forceChange=Force user to change username/password on login adminUserSettings.forceChange=Force user to change username/password on login
adminUserSettings.submit=Save User adminUserSettings.submit=Save User
@ -255,6 +280,10 @@ home.removeBlanks.title=Remover Páginas em Branco
home.removeBlanks.desc=Detectar e remover páginas em branco de um documento home.removeBlanks.desc=Detectar e remover páginas em branco de um documento
removeBlanks.tags=limpeza,otimização,sem-conteúdo,organizar removeBlanks.tags=limpeza,otimização,sem-conteúdo,organizar
home.removeAnnotations.title=Remove Annotations
home.removeAnnotations.desc=Removes all comments/annotations from a PDF
removeAnnotations.tags=comments,highlight,notes,markup,remove
home.compare.title=Comparar home.compare.title=Comparar
home.compare.desc=Comparar e mostrar as diferenças entre 2 documentos PDF home.compare.desc=Comparar e mostrar as diferenças entre 2 documentos PDF
compare.tags=diferenciar,contraste,mudanças,análise compare.tags=diferenciar,contraste,mudanças,análise
@ -336,6 +365,24 @@ home.autoRedact.title=Auto Redact
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
showJS.tags=JavaScript showJS.tags=JavaScript
home.tableExtraxt.title=PDF to CSV
home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV
tableExtraxt.tags=CSV,Table Extraction,extract,convert
home.autoSizeSplitPDF.title=Auto Split by Size/Count
home.autoSizeSplitPDF.desc=Split a single PDF into multiple documents based on size, page count, or document count
autoSizeSplitPDF.tags=pdf,split,document,organization
home.overlay-pdfs.title=Overlay PDFs
home.overlay-pdfs.desc=Overlays PDFs on-top of another PDF
overlay-pdfs.tags=Overlay
home.split-by-sections.title=Split PDF by Sections
home.split-by-sections.desc=Divide each page of a PDF into smaller horizontal and vertical sections
split-by-sections.tags=Section Split, Divide, Customize
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@ -521,6 +568,12 @@ removeBlanks.whitePercentDesc=Porcentagem da página que deve ser branca para se
removeBlanks.submit=Remover Páginas em Branco removeBlanks.submit=Remover Páginas em Branco
#removeAnnotations
removeAnnotations.title=Remove Annotations
removeAnnotations.header=Remove Annotations
removeAnnotations.submit=Remove
#compare #compare
compare.title=Comparar compare.title=Comparar
compare.header=Comparar PDFs compare.header=Comparar PDFs
@ -827,4 +880,41 @@ PDFToXML.submit=Converter
#PDFToCSV #PDFToCSV
PDFToCSV.title=PDF para CSV PDFToCSV.title=PDF para CSV
PDFToCSV.header=PDF para CSV PDFToCSV.header=PDF para CSV
PDFToCSV.submit=Eztennañ PDFToCSV.prompt=Choose page to extract table
PDFToCSV.submit=Eztenna
#split-by-size-or-count
split-by-size-or-count.header=Split PDF by Size or Count
split-by-size-or-count.type.label=Select Split Type
split-by-size-or-count.type.size=By Size
split-by-size-or-count.type.pageCount=By Page Count
split-by-size-or-count.type.docCount=By Document Count
split-by-size-or-count.value.label=Enter Value
split-by-size-or-count.value.placeholder=Enter size (e.g., 2MB or 3KB) or count (e.g., 5)
split-by-size-or-count.submit=Submit
#overlay-pdfs
overlay-pdfs.header=Overlay PDF Files
overlay-pdfs.baseFile.label=Select Base PDF File
overlay-pdfs.overlayFiles.label=Select Overlay PDF Files
overlay-pdfs.mode.label=Select Overlay Mode
overlay-pdfs.mode.sequential=Sequential Overlay
overlay-pdfs.mode.interleaved=Interleaved Overlay
overlay-pdfs.mode.fixedRepeat=Fixed Repeat Overlay
overlay-pdfs.counts.label=Overlay Counts (for Fixed Repeat Mode)
overlay-pdfs.counts.placeholder=Enter comma-separated counts (e.g., 2,3,1)
overlay-pdfs.position.label=Select Overlay Position
overlay-pdfs.position.foreground=Foreground
overlay-pdfs.position.background=Background
overlay-pdfs.submit=Submit
#split-by-sections
split-by-sections.title=Split PDF by Sections
split-by-sections.header=Split PDF into Sections
split-by-sections.horizontal.label=Horizontal Divisions
split-by-sections.vertical.label=Vertical Divisions
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
split-by-sections.vertical.placeholder=Enter number of vertical divisions
split-by-sections.submit=Split PDF

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Red
green=Green green=Green
blue=Blue blue=Blue
custom=Custom... custom=Custom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Credentials changed! changedCredsMessage=Credentials changed!
notAuthenticatedMessage=User not authenticated. notAuthenticatedMessage=User not authenticated.
@ -50,6 +51,29 @@ incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #
@ -119,6 +143,7 @@ adminUserSettings.role=Role
adminUserSettings.actions=Actions adminUserSettings.actions=Actions
adminUserSettings.apiUser=Limited API User adminUserSettings.apiUser=Limited API User
adminUserSettings.webOnlyUser=Web Only User adminUserSettings.webOnlyUser=Web Only User
adminUserSettings.demoUser=Demo User (No custom settings)
adminUserSettings.forceChange=Force user to change username/password on login adminUserSettings.forceChange=Force user to change username/password on login
adminUserSettings.submit=Save User adminUserSettings.submit=Save User
@ -255,6 +280,10 @@ home.removeBlanks.title=Elimină pagini goale
home.removeBlanks.desc=Detectează și elimină paginile goale dintr-un document. home.removeBlanks.desc=Detectează și elimină paginile goale dintr-un document.
removeBlanks.tags=cleanup,streamline,non-content,organize removeBlanks.tags=cleanup,streamline,non-content,organize
home.removeAnnotations.title=Remove Annotations
home.removeAnnotations.desc=Removes all comments/annotations from a PDF
removeAnnotations.tags=comments,highlight,notes,markup,remove
home.compare.title=Compară home.compare.title=Compară
home.compare.desc=Compară și arată diferențele dintre 2 documente PDF. home.compare.desc=Compară și arată diferențele dintre 2 documente PDF.
compare.tags=differentiate,contrast,changes,analysis compare.tags=differentiate,contrast,changes,analysis
@ -336,6 +365,24 @@ home.autoRedact.title=Auto Redact
home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text home.autoRedact.desc=Auto Redacts(Blacks out) text in a PDF based on input text
showJS.tags=JS showJS.tags=JS
home.tableExtraxt.title=PDF to CSV
home.tableExtraxt.desc=Extracts Tables from a PDF converting it to CSV
tableExtraxt.tags=CSV,Table Extraction,extract,convert
home.autoSizeSplitPDF.title=Auto Split by Size/Count
home.autoSizeSplitPDF.desc=Split a single PDF into multiple documents based on size, page count, or document count
autoSizeSplitPDF.tags=pdf,split,document,organization
home.overlay-pdfs.title=Overlay PDFs
home.overlay-pdfs.desc=Overlays PDFs on-top of another PDF
overlay-pdfs.tags=Overlay
home.split-by-sections.title=Split PDF by Sections
home.split-by-sections.desc=Divide each page of a PDF into smaller horizontal and vertical sections
split-by-sections.tags=Section Split, Divide, Customize
########################### ###########################
# # # #
# WEB PAGES # # WEB PAGES #
@ -521,6 +568,12 @@ removeBlanks.whitePercentDesc=Procentul paginii care trebuie să fie alb pentru
removeBlanks.submit=Elimină pagini goale removeBlanks.submit=Elimină pagini goale
#removeAnnotations
removeAnnotations.title=Remove Annotations
removeAnnotations.header=Remove Annotations
removeAnnotations.submit=Remove
#compare #compare
compare.title=Compară compare.title=Compară
compare.header=Compară PDF-uri compare.header=Compară PDF-uri
@ -825,6 +878,43 @@ PDFToXML.credit=Acest serviciu utilizează LibreOffice pentru conversia fișieru
PDFToXML.submit=Convert PDFToXML.submit=Convert
#PDFToCSV #PDFToCSV
PDFToCSV.title=PDF în CSV PDFToCSV.title=PDF <20>n CSV
PDFToCSV.header=PDF în CSV PDFToCSV.header=PDF <20>n CSV
PDFToCSV.prompt=Choose page to extract table
PDFToCSV.submit=Extrage PDFToCSV.submit=Extrage
#split-by-size-or-count
split-by-size-or-count.header=Split PDF by Size or Count
split-by-size-or-count.type.label=Select Split Type
split-by-size-or-count.type.size=By Size
split-by-size-or-count.type.pageCount=By Page Count
split-by-size-or-count.type.docCount=By Document Count
split-by-size-or-count.value.label=Enter Value
split-by-size-or-count.value.placeholder=Enter size (e.g., 2MB or 3KB) or count (e.g., 5)
split-by-size-or-count.submit=Submit
#overlay-pdfs
overlay-pdfs.header=Overlay PDF Files
overlay-pdfs.baseFile.label=Select Base PDF File
overlay-pdfs.overlayFiles.label=Select Overlay PDF Files
overlay-pdfs.mode.label=Select Overlay Mode
overlay-pdfs.mode.sequential=Sequential Overlay
overlay-pdfs.mode.interleaved=Interleaved Overlay
overlay-pdfs.mode.fixedRepeat=Fixed Repeat Overlay
overlay-pdfs.counts.label=Overlay Counts (for Fixed Repeat Mode)
overlay-pdfs.counts.placeholder=Enter comma-separated counts (e.g., 2,3,1)
overlay-pdfs.position.label=Select Overlay Position
overlay-pdfs.position.foreground=Foreground
overlay-pdfs.position.background=Background
overlay-pdfs.submit=Submit
#split-by-sections
split-by-sections.title=Split PDF by Sections
split-by-sections.header=Split PDF into Sections
split-by-sections.horizontal.label=Horizontal Divisions
split-by-sections.vertical.label=Vertical Divisions
split-by-sections.horizontal.placeholder=Enter number of horizontal divisions
split-by-sections.vertical.placeholder=Enter number of vertical divisions
split-by-sections.submit=Split PDF

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Red
green=Green green=Green
blue=Blue blue=Blue
custom=Custom... custom=Custom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Credentials changed! changedCredsMessage=Credentials changed!
notAuthenticatedMessage=User not authenticated. notAuthenticatedMessage=User not authenticated.
@ -50,6 +51,29 @@ incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Red
green=Green green=Green
blue=Blue blue=Blue
custom=Custom... custom=Custom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Credentials changed! changedCredsMessage=Credentials changed!
notAuthenticatedMessage=User not authenticated. notAuthenticatedMessage=User not authenticated.
@ -50,6 +51,29 @@ incorrectPasswordMessage=Current password is incorrect.
usernameExistsMessage=New Username already exists. usernameExistsMessage=New Username already exists.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Kırmızı
green=Yeşil green=Yeşil
blue=Mavi blue=Mavi
custom=Özel custom=Özel
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=Bilgiler değiştirildi! changedCredsMessage=Bilgiler değiştirildi!
notAuthenticatedMessage=Kullanıcı doğrulanmadı. notAuthenticatedMessage=Kullanıcı doğrulanmadı.
@ -50,6 +51,29 @@ incorrectPasswordMessage=Mevcut şifre yanlış.
usernameExistsMessage=Yeni Kullanıcı Adı zaten var. usernameExistsMessage=Yeni Kullanıcı Adı zaten var.
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -1,4 +1,4 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr=left to right, rtl = right to left)
@ -42,6 +42,7 @@ red=Red
green=Green green=Green
blue=Blue blue=Blue
custom=Custom... custom=Custom...
WorkInProgess=Work in progress, May not work or be buggy, Please report any ploblems!
changedCredsMessage=凭证已更改! changedCredsMessage=凭证已更改!
notAuthenticatedMessage=用户未经过身份验证。 notAuthenticatedMessage=用户未经过身份验证。
@ -50,6 +51,29 @@ incorrectPasswordMessage=当前密码不正确。
usernameExistsMessage=新用户名已存在。 usernameExistsMessage=新用户名已存在。
###############
# Pipeline #
###############
pipeline.header=Pipeline Menu (Alpha)
pipeline.uploadButton=Upload Custom
pipeline.configureButton=Configure
pipeline.defaultOption=Custom
pipeline.submitButton=Submit
######################
# Pipeline Options #
######################
pipelineOptions.header=Pipeline Configuration
pipelineOptions.pipelineNameLabel=Pipeline Name
pipelineOptions.saveSettings=Save Settings
pipelineOptions.pipelineNamePrompt=Enter pipeline name here
pipelineOptions.addOperationButton=Add operation
pipelineOptions.pipelineHeader=Pipeline:
pipelineOptions.saveButton=Download
pipelineOptions.validateButton=Validate
############# #############
# NAVBAR # # NAVBAR #

View file

@ -57,14 +57,14 @@ function validatePipeline() {
} }
function updateValidateButton(isValid) { function updateValidateButton(isValid) {
var validateButton = document.getElementById('validateButton'); var validateButton = document.getElementById('validateButton');
if (isValid) { if (isValid) {
validateButton.classList.remove('btn-danger'); validateButton.classList.remove('btn-danger');
validateButton.classList.add('btn-success'); validateButton.classList.add('btn-success');
} else { } else {
validateButton.classList.remove('btn-success'); validateButton.classList.remove('btn-success');
validateButton.classList.add('btn-danger'); validateButton.classList.add('btn-danger');
} }
} }
@ -131,34 +131,34 @@ document.getElementById('submitConfigBtn').addEventListener('click', function()
console.log("formData", formData); console.log("formData", formData);
fetch('api/v1/pipeline/handleData', { fetch('api/v1/pipeline/handleData', {
method: 'POST', method: 'POST',
body: formData body: formData
}) })
.then(response => { .then(response => {
// Save the response to use it later // Save the response to use it later
const responseToUseLater = response; const responseToUseLater = response;
return response.blob().then(blob => { return response.blob().then(blob => {
let url = window.URL.createObjectURL(blob); let url = window.URL.createObjectURL(blob);
let a = document.createElement('a'); let a = document.createElement('a');
a.href = url; a.href = url;
// Use responseToUseLater instead of response // Use responseToUseLater instead of response
const contentDisposition = responseToUseLater.headers.get('Content-Disposition'); const contentDisposition = responseToUseLater.headers.get('Content-Disposition');
let filename = 'download'; let filename = 'download';
if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) { if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) {
filename = decodeURIComponent(contentDisposition.split('filename=')[1].replace(/"/g, '')).trim(); filename = decodeURIComponent(contentDisposition.split('filename=')[1].replace(/"/g, '')).trim();
} }
a.download = filename; a.download = filename;
document.body.appendChild(a); document.body.appendChild(a);
a.click(); a.click();
a.remove(); a.remove();
}); });
}) })
.catch((error) => { .catch((error) => {
console.error('Error:', error); console.error('Error:', error);
}); });
}); });
@ -182,10 +182,11 @@ fetch('v1/api-docs')
// Group operations by tags // Group operations by tags
Object.keys(data.paths).forEach(operationPath => { Object.keys(data.paths).forEach(operationPath => {
let operation = data.paths[operationPath].post; let operation = data.paths[operationPath].post;
if(!operation || !operation.description) { if (!operation || !operation.description) {
console.log(operationPath); console.log(operationPath);
} }
if (operation && !ignoreOperations.includes(operationPath) && !operation.description.includes("Type:MISO")) { //!operation.description.includes("Type:MISO")
if (operation && !ignoreOperations.includes(operationPath)) {
let operationTag = operation.tags[0]; // This assumes each operation has exactly one tag let operationTag = operation.tags[0]; // This assumes each operation has exactly one tag
if (!operationsByTag[operationTag]) { if (!operationsByTag[operationTag]) {
operationsByTag[operationTag] = []; operationsByTag[operationTag] = [];
@ -193,6 +194,12 @@ fetch('v1/api-docs')
operationsByTag[operationTag].push(operationPath); operationsByTag[operationTag].push(operationPath);
} }
}); });
// Sort operations within each tag alphabetically
Object.keys(operationsByTag).forEach(tag => {
operationsByTag[tag].sort();
});
// Specify the order of tags // Specify the order of tags
let tagOrder = ["General", "Security", "Convert", "Misc", "Filter"]; let tagOrder = ["General", "Security", "Convert", "Misc", "Filter"];
@ -209,12 +216,12 @@ fetch('v1/api-docs')
operationPathDisplay = operationPath.replace(new RegExp("api/v1/" + tag.toLowerCase() + "/", 'i'), ""); operationPathDisplay = operationPath.replace(new RegExp("api/v1/" + tag.toLowerCase() + "/", 'i'), "");
if(operationPath.includes("/convert")){ if (operationPath.includes("/convert")) {
operationPathDisplay = operationPathDisplay.replace(/^\//, '').replaceAll("/", " to "); operationPathDisplay = operationPathDisplay.replace(/^\//, '').replaceAll("/", " to ");
} else { } else {
operationPathDisplay = operationPathDisplay.replace(/\//g, ''); // Remove slashes operationPathDisplay = operationPathDisplay.replace(/\//g, ''); // Remove slashes
} }
operationPathDisplay = operationPathDisplay.replaceAll(" ","-"); operationPathDisplay = operationPathDisplay.replaceAll(" ", "-");
option.textContent = operationPathDisplay; option.textContent = operationPathDisplay;
option.value = operationPath; // Keep the value with slashes for querying option.value = operationPath; // Keep the value with slashes for querying
group.appendChild(option); group.appendChild(option);
@ -234,37 +241,43 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
listItem.className = "list-group-item"; listItem.className = "list-group-item";
let hasSettings = false; let hasSettings = false;
if (apiDocs[selectedOperation] && apiDocs[selectedOperation].post) { if (apiDocs[selectedOperation] && apiDocs[selectedOperation].post) {
const postMethod = apiDocs[selectedOperation].post; const postMethod = apiDocs[selectedOperation].post;
// Check if parameters exist // Check if parameters exist
if (postMethod.parameters && postMethod.parameters.length > 0) { if (postMethod.parameters && postMethod.parameters.length > 0) {
hasSettings = true; hasSettings = true;
} else if (postMethod.requestBody && postMethod.requestBody.content['multipart/form-data']) { } else if (postMethod.requestBody && postMethod.requestBody.content['multipart/form-data']) {
// Extract the reference key // Extract the reference key
const refKey = postMethod.requestBody.content['multipart/form-data'].schema['$ref'].split('/').pop(); const refKey = postMethod.requestBody.content['multipart/form-data'].schema['$ref'].split('/').pop();
// Check if the referenced schema exists and has properties // Check if the referenced schema exists and has properties more than just its input file
if (apiSchemas[refKey] && Object.keys(apiSchemas[refKey].properties).length > 0) { if (apiSchemas[refKey]) {
hasSettings = true; const properties = apiSchemas[refKey].properties;
} const propertyKeys = Object.keys(properties);
}
// Check if there's more than one property or if there's exactly one property and its format is not 'binary'
if (propertyKeys.length > 1 || (propertyKeys.length === 1 && properties[propertyKeys[0]].format !== 'binary')) {
hasSettings = true;
}
}
}
} }
listItem.innerHTML = ` listItem.innerHTML = `
<div class="d-flex justify-content-between align-items-center w-100"> <div class="d-flex justify-content-between align-items-center w-100">
<div class="operationName">${selectedOperation}</div> <div class="operationName">${selectedOperation}</div>
<div class="arrows d-flex"> <div class="arrows d-flex">
<button class="btn btn-secondary move-up ms-1"><span>&uarr;</span></button> <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 btn-secondary move-down ms-1"><span>&darr;</span></button>
<button class="btn ${hasSettings ? 'btn-warning' : 'btn-secondary'} pipelineSettings ms-1" ${hasSettings ? "" : "disabled"}> <button class="btn ${hasSettings ? 'btn-warning' : 'btn-secondary'} pipelineSettings ms-1" ${hasSettings ? "" : "disabled"}>
<span style="color: ${hasSettings ? "white" : "grey"};"></span> <span style="color: ${hasSettings ? "white" : "grey"};"></span>
</button> </button>
<button class="btn btn-danger remove ms-1"><span>X</span></button> <button class="btn btn-danger remove ms-1"><span>X</span></button>
</div> </div>
</div> </div>
`; `;
pipelineList.appendChild(listItem); pipelineList.appendChild(listItem);
@ -273,6 +286,7 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
event.preventDefault(); event.preventDefault();
if (listItem.previousElementSibling) { if (listItem.previousElementSibling) {
pipelineList.insertBefore(listItem, listItem.previousElementSibling); pipelineList.insertBefore(listItem, listItem.previousElementSibling);
updateConfigInDropdown();
} }
}); });
@ -280,13 +294,16 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
event.preventDefault(); event.preventDefault();
if (listItem.nextElementSibling) { if (listItem.nextElementSibling) {
pipelineList.insertBefore(listItem.nextElementSibling, listItem); pipelineList.insertBefore(listItem.nextElementSibling, listItem);
updateConfigInDropdown();
} }
}); });
listItem.querySelector('.remove').addEventListener('click', function(event) { listItem.querySelector('.remove').addEventListener('click', function(event) {
event.preventDefault(); event.preventDefault();
pipelineList.removeChild(listItem); pipelineList.removeChild(listItem);
hideOrShowPipelineHeader(); hideOrShowPipelineHeader();
updateConfigInDropdown();
}); });
listItem.querySelector('.pipelineSettings').addEventListener('click', function(event) { listItem.querySelector('.pipelineSettings').addEventListener('click', function(event) {
@ -306,15 +323,15 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
// Combine operationData and requestBodyData into a single array // Combine operationData and requestBodyData into a single array
operationData = operationData.concat(Object.keys(requestBodyData).map(key => ({ operationData = operationData.concat(Object.keys(requestBodyData).map(key => ({
name: key, name: key,
schema: requestBodyData[key] schema: requestBodyData[key]
}))); })));
pipelineSettingsContent.innerHTML = ''; pipelineSettingsContent.innerHTML = '';
operationData.forEach(parameter => { operationData.forEach(parameter => {
// If the parameter name is 'fileInput', return early to skip the rest of this iteration // If the parameter name is 'fileInput', return early to skip the rest of this iteration
if (parameter.name === 'fileInput') return; if (parameter.name === 'fileInput') return;
let parameterDiv = document.createElement('div'); let parameterDiv = document.createElement('div');
parameterDiv.className = "mb-3"; parameterDiv.className = "mb-3";
@ -325,8 +342,8 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
parameterLabel.setAttribute('for', parameter.name); parameterLabel.setAttribute('for', parameter.name);
parameterDiv.appendChild(parameterLabel); parameterDiv.appendChild(parameterLabel);
let defaultValue = parameter.schema.example; let defaultValue = parameter.schema.example;
if (defaultValue === undefined) defaultValue = parameter.schema.default; if (defaultValue === undefined) defaultValue = parameter.schema.default;
let parameterInput; let parameterInput;
@ -357,7 +374,7 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
parameterInput = document.createElement('input'); parameterInput = document.createElement('input');
parameterInput.type = 'text'; parameterInput.type = 'text';
parameterInput.className = "form-control"; parameterInput.className = "form-control";
parameterInput.value = "FileInputPathToBeInputtedManuallyOffline"; parameterInput.value = "FileInputPathToBeInputtedManuallyForOffline";
} else { } else {
parameterInput = document.createElement('input'); parameterInput = document.createElement('input');
parameterInput.type = 'text'; parameterInput.type = 'text';
@ -379,8 +396,9 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
break; break;
case 'array': case 'array':
case 'object': case 'object':
//TODO compare to doc and check if fileInput array? parameter.schema.format === 'binary'
parameterInput = document.createElement('textarea'); parameterInput = document.createElement('textarea');
parameterInput.placeholder = `Enter a JSON formatted ${parameter.schema.type}`; parameterInput.placeholder = `Enter a JSON formatted ${parameter.schema.type}, If this is a fileInput, it is not currently supported`;
parameterInput.className = "form-control"; parameterInput.className = "form-control";
break; break;
default: default:
@ -419,41 +437,47 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
pipelineSettingsContent.appendChild(parameterDiv); pipelineSettingsContent.appendChild(parameterDiv);
}); });
let saveButton = document.createElement('button'); if(hasSettings) {
saveButton.textContent = "Save Settings"; let saveButton = document.createElement('button');
saveButton.className = "btn btn-primary"; saveButton.textContent = saveSettings;
saveButton.addEventListener('click', function(event) { saveButton.className = "btn btn-primary";
event.preventDefault(); saveButton.addEventListener('click', function(event) {
let settings = {}; event.preventDefault();
operationData.forEach(parameter => { let settings = {};
if(parameter.name !== "fileInput"){ operationData.forEach(parameter => {
let value = document.getElementById(parameter.name).value; if (parameter.name !== "fileInput") {
switch (parameter.schema.type) { let value = document.getElementById(parameter.name).value;
case 'number': switch (parameter.schema.type) {
case 'integer': case 'number':
settings[parameter.name] = Number(value); case 'integer':
break; settings[parameter.name] = Number(value);
case 'boolean': break;
settings[parameter.name] = document.getElementById(parameter.name).checked; case 'boolean':
break; settings[parameter.name] = document.getElementById(parameter.name).checked;
case 'array': break;
case 'object': case 'array':
try { case 'object':
settings[parameter.name] = JSON.parse(value); if (value === null || value === '') {
} catch (err) { settings[parameter.name] = '';
console.error(`Invalid JSON format for ${parameter.name}`); } else {
} try {
break; settings[parameter.name] = JSON.parse(value);
default: } catch (err) {
settings[parameter.name] = value; console.error(`Invalid JSON format for ${parameter.name}`);
}
}
break;
default:
settings[parameter.name] = value;
}
} }
} });
operationSettings[operation] = settings;
//pipelineSettingsModal.style.display = "none";
}); });
operationSettings[operation] = settings; pipelineSettingsContent.appendChild(saveButton);
//pipelineSettingsModal.style.display = "none"; saveButton.click();
}); }
pipelineSettingsContent.appendChild(saveButton);
//pipelineSettingsModal.style.display = "block"; //pipelineSettingsModal.style.display = "block";
//pipelineSettingsModal.getElementsByClassName("close")[0].onclick = function() { //pipelineSettingsModal.getElementsByClassName("close")[0].onclick = function() {
@ -466,144 +490,182 @@ document.getElementById('addOperationBtn').addEventListener('click', function()
// } // }
//} //}
} }
showpipelineSettingsModal(selectedOperation);
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;
}
var saveBtn = document.getElementById('savePipelineBtn');
// Remove any existing event listeners
saveBtn.removeEventListener('click', savePipeline);
// Add the event listener
saveBtn.addEventListener('click', savePipeline);
console.log("saveBtn", saveBtn)
function configToJson() {
if (!validatePipeline()) {
return null; // Return null if validation fails
}
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": "{outputFolder}",
"outputFileName": "{filename}"
};
for (let i = 0; i < pipelineList.length; i++) {
let operationName = pipelineList[i].querySelector('.operationName').textContent;
let parameters = operationSettings[operationName] || {};
parameters['fileInput'] = 'automated';
pipelineConfig.pipeline.push({
"operation": operationName,
"parameters": parameters
});
}
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');
a.href = URL.createObjectURL(new Blob([pipelineConfigJson], { type: 'application/json' }));
a.download = pipelineName + '.json';
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
async function processPipelineConfig(configString) {
console.log("configString", 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('uploadPipelineInput').click();
});
document.getElementById('uploadPipelineInput').addEventListener('change', function(e) {
let reader = new FileReader();
reader.onload = function(event) {
processPipelineConfig(event.target.result);
};
reader.readAsText(e.target.files[0]);
hideOrShowPipelineHeader(); hideOrShowPipelineHeader();
}); });
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);
});
var saveBtn = document.getElementById('savePipelineBtn'); function hideOrShowPipelineHeader() {
var pipelineHeader = document.getElementById('pipelineHeader');
var pipelineList = document.getElementById('pipelineList');
// Remove any existing event listeners if (pipelineList.children.length === 0) {
saveBtn.removeEventListener('click', savePipeline); // Hide the pipeline header if there are no items in the pipeline list
pipelineHeader.style.display = 'none';
// Add the event listener } else {
saveBtn.addEventListener('click', savePipeline); // Show the pipeline header if there are items in the pipeline list
console.log("saveBtn", saveBtn) pipelineHeader.style.display = 'block';
function savePipeline() {
if (validatePipeline() === false) {
return;
}
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": "{outputFolder}",
"outputFileName": "{filename}"
};
for (let i = 0; i < pipelineList.length; i++) {
let operationName = pipelineList[i].querySelector('.operationName').textContent;
let parameters = operationSettings[operationName] || {};
parameters['fileInput'] = 'automated';
pipelineConfig.pipeline.push({
"operation": operationName,
"parameters": parameters
});
}
console.log("Downloading..");
let a = document.createElement('a');
a.href = URL.createObjectURL(new Blob([JSON.stringify(pipelineConfig, null, 2)], {
type: 'application/json'
}));
a.download = pipelineName + '.json';
a.style.display = 'none';
document.body.appendChild(a);
a.click();
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('uploadPipelineInput').click();
});
document.getElementById('uploadPipelineInput').addEventListener('change', function(e) {
let reader = new FileReader();
reader.onload = function(event) {
processPipelineConfig(event.target.result);
};
reader.readAsText(e.target.files[0]);
hideOrShowPipelineHeader();
});
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);
});
function hideOrShowPipelineHeader() {
var pipelineHeader = document.getElementById('pipelineHeader');
var pipelineList = document.getElementById('pipelineList');
if (pipelineList.children.length === 0) {
// Hide the pipeline header if there are no items in the pipeline list
pipelineHeader.style.display = 'none';
} else {
// Show the pipeline header if there are items in the pipeline list
pipelineHeader.style.display = 'block';
}
} }
}

View file

@ -10,23 +10,29 @@
margin-right: 2px; margin-right: 2px;
} }
.bordered-box { .bordered-box {
border: 1px solid #ddd; border: 1px solid #ddd;
padding: 20px; padding: 20px;
margin: 20px; margin: 20px;
width: 70%; width: 70%;
} }
.center-element { .center-element {
width: 80%; width: 80%;
text-align: center; text-align: center;
margin: auto; margin: auto;
} }
.element-margin {
margin: 10px 0; /* Adjust this value to increase/decrease the margin as needed */ .element-margin {
} margin: 10px 0;
/* Adjust this value to increase/decrease the margin as needed */
}
</style> </style>
<script th:inline="javascript">
const saveSettings = /*[[#{pipelineOptions.saveSettings}]]*/ '';
</script>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
@ -36,153 +42,207 @@
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<h1>(Alpha) Pipeline Menu (Huge work in progress, very buggy!)</h1> <h1 th:text="#{pipeline.header}"></h1>
<div class="bordered-box"> <h2 th:text="#{WorkInProgess}"> </h2>
<div class="text-end text-top"> <div class="bordered-box">
<button id="uploadPipelineBtn" class="btn btn-primary">Upload <div class="text-end text-top">
Custom</button> <button id="uploadPipelineBtn" class="btn btn-primary"
<button type="button" class="btn btn-primary" data-bs-toggle="modal" th:text="#{pipeline.uploadButton}"></button>
data-bs-target="#pipelineSettingsModal">Configure</button> <button type="button" class="btn btn-primary"
</div> data-bs-toggle="modal" data-bs-target="#pipelineSettingsModal"
th:text="#{pipeline.configureButton}"></button>
<div class="center-element"> </div>
<div class="element-margin">
<select id="pipelineSelect" class="custom-select"> <div class="center-element">
<th:block th:each="config : ${pipelineConfigsWithNames}"> <div class="element-margin">
<option th:value="${config.json}" th:text="${config.name}"></option> <select id="pipelineSelect" class="custom-select">
</th:block> <option
</select> 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="#{pipeline.defaultOption}"></option>
<th:block th:each="config : ${pipelineConfigsWithNames}">
<option th:value="${config.json}" th:text="${config.name}"></option>
</th:block>
</select>
</div> </div>
<div class="element-margin"> <div class="element-margin">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=true)}"></div> <div
</div> th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=true)}"></div>
<div class="element-margin"> </div>
<button class="btn btn-primary" id="submitConfigBtn">Submit</button> <div class="element-margin">
</div> <button class="btn btn-primary" id="submitConfigBtn"
</div> th:text="#{pipeline.submitButton}"></button>
</div>
</div>
</div>
</div>
<h3>Current Limitations</h3> <h3>Current Limitations</h3>
<ul> <ul>
<li>Cannot have more than one of the same operation</li> <li>Cannot have more than one of the same operation</li>
<li>Cannot input additional files via UI</li> <li>Cannot input additional files via UI</li>
<li>Does not work with multi-input functions yet (like merges)</li> <li>All files and operations run in serial mode</li>
<li>All files and operations run in serial mode</li>
</ul> </ul>
<h3>How it Works Notes</h3> <h3>How it Works Notes</h3>
<ul> <ul>
<li>Configure the pipeline config file and input files to run files against it</li> <li>Configure the pipeline config file and input files to run
<li>For reuse, download the config file and re-upload it when needed, or place it in /pipeline/defaultWebUIConfigs/ to auto-load in the web UI for all users</li> files against it</li>
<li>For reuse, download the config file and re-upload it when
needed, or place it in /pipeline/defaultWebUIConfigs/ to
auto-load in the web UI for all users</li>
</ul> </ul>
<h3>How to use pre-load configs in web UI</h3> <h3>How to use pre-load configs in web UI</h3>
<ul> <ul>
<li>Download config files</li> <li>Download config files</li>
<li>For reuse, download the config file and re-upload it when needed, or place it in /pipeline/defaultWebUIConfigs/ to auto-load in the web UI for all users</li> <li>For reuse, download the config file and re-upload it when
needed, or place it in /pipeline/defaultWebUIConfigs/ to
auto-load in the web UI for all users</li>
</ul> </ul>
<h3>Todo</h3> <h3>Todo</h3>
<ul> <ul>
<li>fix initial config selected not loading</li> <li>Translation support</li>
<li>Fix operation adding requering settings to be openned and saved instead of saving defaults</li> <li>Save to browser/Account</li>
<li>multiInput support</li> <li>offline mode checks and testing</li>
<li>Translation support</li> <li>Improve operation config settings UI</li>
<li>offline mode checks and testing</li>
<li>Improve operation config settings UI</li>
</ul> </ul>
<h2>User Guide for Local Directory Scanning and File Processing</h2> <h2>User Guide for Local Directory Scanning and File
Processing</h2>
<h3>Setting Up Watched Folders:</h3> <h3>Setting Up Watched Folders:</h3>
<p>Create a folder where you want your files to be monitored. This is your 'watched folder'.</p> <p>Create a folder where you want your files to be monitored.
<p>The default directory for this is <code>./pipeline/watchedFolders/</code></p> This is your 'watched folder'.</p>
<p>Place any directories you want to be scanned into this folder, this folder should contain multiple folders each for their own tasks and pipelines.</p> <p>
The default directory for this is
<code>./pipeline/watchedFolders/</code>
</p>
<p>Place any directories you want to be scanned into this
folder, this folder should contain multiple folders each for their
own tasks and pipelines.</p>
<h3>Configuring Processing with JSON Files:</h3> <h3>Configuring Processing with JSON Files:</h3>
<p>In each directory you want processed (e.g <code>./pipeline/watchedFolders/officePrinter</code>), include a JSON configuration file.</p> <p>
<p>This JSON file should specify how you want the files in the directory to be handled (e.g., what operations to perform on them) which can be made, configured and downloaded from Stirling-PDF Pipeline interface.</p> In each directory you want processed (e.g
<code>./pipeline/watchedFolders/officePrinter</code>
), include a JSON configuration file.
</p>
<p>This JSON file should specify how you want the files in the
directory to be handled (e.g., what operations to perform on them)
which can be made, configured and downloaded from Stirling-PDF
Pipeline interface.</p>
<h3>Automatic Scanning and Processing:</h3> <h3>Automatic Scanning and Processing:</h3>
<p>The system automatically checks the watched folder every minute for new directories and files to process.</p> <p>The system automatically checks the watched folder every
<p>When a directory with a valid JSON configuration file is found, it begins processing the files inside as per the configuration.</p> minute for new directories and files to process.</p>
<p>When a directory with a valid JSON configuration file is
found, it begins processing the files inside as per the
configuration.</p>
<h3>Processing Steps:</h3> <h3>Processing Steps:</h3>
<p>Files in each directory are processed according to the instructions in the JSON file.</p> <p>Files in each directory are processed according to the
<p>This might involve file conversions, data filtering, renaming files, etc. If the output of a step is a zip, this zip will be automatically unzipped as it passes to next process.</p> instructions in the JSON file.</p>
<p>This might involve file conversions, data filtering,
renaming files, etc. If the output of a step is a zip, this zip
will be automatically unzipped as it passes to next process.</p>
<h3>Results and Output:</h3> <h3>Results and Output:</h3>
<p>After processing, the results are saved in a specified output location. This could be a different folder or location as defined in the JSON file or the default location <code>./pipeline/finishedFolders/</code>.</p> <p>
<p>Each processed file is named and organized according to the rules set in the JSON configuration.</p> After processing, the results are saved in a specified output
location. This could be a different folder or location as defined
in the JSON file or the default location
<code>./pipeline/finishedFolders/</code>
.
</p>
<p>Each processed file is named and organized according to the
rules set in the JSON configuration.</p>
<h3>Completion and Cleanup:</h3> <h3>Completion and Cleanup:</h3>
<p>Once processing is complete, the original files in the watched folder's directory are removed.</p> <p>Once processing is complete, the original files in the
<p>You can find the processed files in the designated output location.</p> watched folder's directory are removed.</p>
<p>You can find the processed files in the designated output
location.</p>
<h3>Error Handling:</h3> <h3>Error Handling:</h3>
<p>If there's an error during processing, the system will not delete the original files, allowing you to check and retry if necessary.</p> <p>If there's an error during processing, the system will not
delete the original files, allowing you to check and retry if
necessary.</p>
<h3>User Interaction:</h3> <h3>User Interaction:</h3>
<p>As a user, your main tasks are to set up the watched folders, place directories with files for processing, and create the corresponding JSON configuration files.</p> <p>As a user, your main tasks are to set up the watched
<p>The system handles the rest, including scanning, processing, and outputting results.</p> folders, place directories with files for processing, and create
the corresponding JSON configuration files.</p>
<p>The system handles the rest, including scanning, processing,
and outputting results.</p>
<!-- The Modal --> <!-- The Modal -->
<div class="modal" id="pipelineSettingsModal"> <div class="modal" id="pipelineSettingsModal">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content dark-card"> <div class="modal-content dark-card">
<!-- Modal Header -->
<div class="modal-header">
<h2 class="modal-title">Pipeline Configuration</h2>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<!-- Modal body -->
<div class="modal-body">
<div class="mb-3">
<label for="pipelineName" class="form-label">Pipeline
Name</label> <input type="text" id="pipelineName"
class="form-control" placeholder="Enter pipeline name here">
</div>
<div class="mb-3">
<select id="operationsDropdown" class="form-select">
<!-- Options will be dynamically populated here -->
</select>
</div>
<div class="mb-3">
<button id="addOperationBtn" class="btn btn-primary">Add
operation</button>
</div>
<h3 id="pipelineHeader" style="display: none;">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>
<!-- Modal Header -->
<div class="modal-header">
<h2 class="modal-title" th:text="#{pipelineOptions.header}"></h2>
<button type="button" class="btn-close" data-bs-dismiss="modal"
aria-label="Close"></button>
</div> </div>
<!-- Modal body -->
<div class="modal-body">
<div class="mb-3">
<label for="pipelineName" class="form-label"
th:text="#{pipelineOptions.pipelineNameLabel}"></label> <input
type="text" id="pipelineName" class="form-control"
th:placeholder="#{pipelineOptions.pipelineNamePrompt}">
</div>
<div class="mb-3">
<select id="operationsDropdown" class="form-select">
<!-- Options will be dynamically populated here -->
</select>
</div>
<div class="mb-3">
<button id="addOperationBtn" class="btn btn-primary"
th:text="#{pipelineOptions.addOperationButton}"></button>
</div>
<h3 id="pipelineHeader" style="display: none;"
th:text="#{pipelineOptions.pipelineHeader}"></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"
th:text="#{pipelineOptions.saveButton}"></button>
<button id="validateButton" class="btn btn-success"
th:text="#{pipelineOptions.validateButton}"></button>
<div class="btn-group">
<input type="file" id="uploadPipelineInput" accept=".json"
style="display: none;">
</div>
</div>
</div> </div>
</div> </div>
<script src="js/pipeline.js"></script>
</div> </div>
<script src="js/pipeline.js"></script>
</div>
</div> </div>
</div> </div>

128
test.sh Normal file
View file

@ -0,0 +1,128 @@
#!/bin/bash
# Function to check the health of the service with a timeout of 80 seconds
check_health() {
local service_name=$1
local compose_file=$2
local end=$((SECONDS+60))
echo -n "Waiting for $service_name to become healthy..."
until [ "$(docker inspect --format='{{json .State.Health.Status}}' "$service_name")" == '"healthy"' ] || [ $SECONDS -ge $end ]; do
sleep 3
echo -n "."
if [ $SECONDS -ge $end ]; then
echo -e "\n$service_name health check timed out after 80 seconds."
echo "Printing logs for $service_name:"
docker logs "$service_name"
return 1
fi
done
echo -e "\n$service_name is healthy!"
return 0
}
# Function to test a Docker Compose configuration
test_compose() {
local compose_file=$1
local service_name=$2
local status=0
echo "Testing $compose_file configuration..."
# Start up the Docker Compose service
docker-compose -f "$compose_file" up -d
# Wait for the service to become healthy
if check_health "$service_name" "$compose_file"; then
echo "$service_name test passed."
else
echo "$service_name test failed."
status=1
fi
# Perform additional tests if needed
# Tear down the service
docker-compose -f "$compose_file" down
return $status
}
# Keep track of which tests passed and failed
declare -a passed_tests
declare -a failed_tests
run_tests() {
local test_name=$1
local compose_file=$2
if test_compose "$compose_file" "$test_name"; then
passed_tests+=("$test_name")
else
failed_tests+=("$test_name")
fi
}
# Main testing routine
main() {
SECONDS=0
export DOCKER_ENABLE_SECURITY=false
./gradlew clean build
# Building Docker images
docker build --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest -f ./Dockerfile .
docker build --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-lite -f ./Dockerfile-lite .
docker build --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-ultra-lite -f ./Dockerfile-ultra-lite .
# Test each configuration
run_tests "Stirling-PDF-Ultra-Lite" "./exampleYmlFiles/docker-compose-latest-ultra-lite.yml"
run_tests "Stirling-PDF-Lite" "./exampleYmlFiles/docker-compose-latest-lite.yml"
run_tests "Stirling-PDF" "./exampleYmlFiles/docker-compose-latest.yml"
export DOCKER_ENABLE_SECURITY=true
./gradlew clean build
# Building Docker images with security enabled
docker build --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest -f ./Dockerfile .
docker build --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-lite -f ./Dockerfile-lite .
docker build --build-arg VERSION_TAG=alpha -t frooodle/s-pdf:latest-ultra-lite -f ./Dockerfile-ultra-lite .
# Test each configuration with security
run_tests "Stirling-PDF-Ultra-Lite-Security" "./exampleYmlFiles/docker-compose-latest-ultra-lite-security.yml"
run_tests "Stirling-PDF-Lite-Security" "./exampleYmlFiles/docker-compose-latest-lite-security.yml"
run_tests "Stirling-PDF-Security" "./exampleYmlFiles/docker-compose-latest-security.yml"
# Report results
echo "All tests completed in $SECONDS seconds."
if [ ${#passed_tests[@]} -ne 0 ]; then
echo "Passed tests:"
fi
for test in "${passed_tests[@]}"; do
echo -e "\e[32m$test\e[0m" # Green color for passed tests
done
if [ ${#failed_tests[@]} -ne 0 ]; then
echo "Failed tests:"
fi
for test in "${failed_tests[@]}"; do
echo -e "\e[31m$test\e[0m" # Red color for failed tests
done
# Check if there are any failed tests and exit with an error code if so
if [ ${#failed_tests[@]} -ne 0 ]; then
echo "Some tests failed."
exit 1
else
echo "All tests passed successfully."
exit 0
fi
}
main