lots of stuff
This commit is contained in:
parent
54e7998bf7
commit
320f56e473
10 changed files with 153 additions and 46 deletions
|
@ -12,9 +12,7 @@ COPY build/libs/*.jar app.jar
|
||||||
EXPOSE 8080
|
EXPOSE 8080
|
||||||
|
|
||||||
# Set environment variables
|
# Set environment variables
|
||||||
ENV APP_HOME_NAME="Stirling PDF"
|
ENV GROUPS_TO_REMOVE=LibreOffice
|
||||||
#ENV APP_HOME_DESCRIPTION="Personal PDF Website!"
|
|
||||||
#ENV APP_NAVBAR_NAME="Stirling PDF"
|
|
||||||
|
|
||||||
# Run the application
|
# Run the application
|
||||||
RUN chmod +x /scripts/init.sh
|
RUN chmod +x /scripts/init.sh
|
||||||
|
|
14
Dockerfile-ultralite
Normal file
14
Dockerfile-ultralite
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
# Build jbig2enc in a separate stage
|
||||||
|
FROM openjdk:17-jdk-slim
|
||||||
|
|
||||||
|
# Copy the application JAR file
|
||||||
|
COPY build/libs/*.jar app.jar
|
||||||
|
|
||||||
|
# Expose the application port
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
ENV GROUPS_TO_REMOVE=LibreOffice,CLI
|
||||||
|
|
||||||
|
# Run the application
|
||||||
|
CMD ["java", "-jar", "/app.jar"]
|
|
@ -26,11 +26,11 @@ RUN git clone https://github.com/agl/jbig2enc && \
|
||||||
FROM openjdk:17-jdk-slim AS base
|
FROM openjdk:17-jdk-slim AS base
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y --no-install-recommends \
|
apt-get install -y --no-install-recommends \
|
||||||
libreoffice-core \
|
libreoffice-core-nogui \
|
||||||
libreoffice-common \
|
libreoffice-common \
|
||||||
libreoffice-writer \
|
libreoffice-writer-nogui \
|
||||||
libreoffice-calc \
|
libreoffice-calc-nogui \
|
||||||
libreoffice-impress \
|
libreoffice-impress-nogui \
|
||||||
python3-uno \
|
python3-uno \
|
||||||
python3-pip \
|
python3-pip \
|
||||||
unoconv \
|
unoconv \
|
||||||
|
|
|
@ -7,11 +7,12 @@ import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.slf4j.Logger;
|
||||||
@Service
|
@Service
|
||||||
public class EndpointConfiguration {
|
public class EndpointConfiguration {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(EndpointConfiguration.class);
|
||||||
private Map<String, Boolean> endpointStatuses = new ConcurrentHashMap<>();
|
private Map<String, Boolean> endpointStatuses = new ConcurrentHashMap<>();
|
||||||
private Map<String, Set<String>> endpointGroups = new ConcurrentHashMap<>();
|
private Map<String, Set<String>> endpointGroups = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@ -25,6 +26,7 @@ public class EndpointConfiguration {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disableEndpoint(String endpoint) {
|
public void disableEndpoint(String endpoint) {
|
||||||
|
logger.info("Disabling {}", endpoint);
|
||||||
endpointStatuses.put(endpoint, false);
|
endpointStatuses.put(endpoint, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,6 +164,7 @@ public class EndpointConfiguration {
|
||||||
addEndpointToGroup("Javascript", "pdf-organizer");
|
addEndpointToGroup("Javascript", "pdf-organizer");
|
||||||
addEndpointToGroup("Javascript", "sign");
|
addEndpointToGroup("Javascript", "sign");
|
||||||
addEndpointToGroup("Javascript", "compare");
|
addEndpointToGroup("Javascript", "compare");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processEnvironmentConfigs() {
|
private void processEnvironmentConfigs() {
|
||||||
|
|
|
@ -17,12 +17,10 @@ public class EndpointInterceptor implements HandlerInterceptor {
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
String requestURI = request.getRequestURI();
|
String requestURI = request.getRequestURI();
|
||||||
System.out.println("trying " + requestURI);
|
|
||||||
if (!endpointConfiguration.isEndpointEnabled(requestURI)) {
|
if (!endpointConfiguration.isEndpointEnabled(requestURI)) {
|
||||||
response.sendError(HttpServletResponse.SC_FORBIDDEN, "This endpoint is disabled");
|
response.sendError(HttpServletResponse.SC_FORBIDDEN, "This endpoint is disabled");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ public class MetricsConfig {
|
||||||
return new MeterFilter() {
|
return new MeterFilter() {
|
||||||
@Override
|
@Override
|
||||||
public MeterFilterReply accept(Meter.Id id) {
|
public MeterFilterReply accept(Meter.Id id) {
|
||||||
if (id.getName().equals("http.requests") || id.getName().equals("health")) {
|
if (id.getName().equals("http.requests")) {
|
||||||
return MeterFilterReply.NEUTRAL;
|
return MeterFilterReply.NEUTRAL;
|
||||||
}
|
}
|
||||||
return MeterFilterReply.DENY;
|
return MeterFilterReply.DENY;
|
||||||
|
|
|
@ -33,7 +33,7 @@ public class MetricsFilter extends OncePerRequestFilter {
|
||||||
String uri = request.getRequestURI();
|
String uri = request.getRequestURI();
|
||||||
|
|
||||||
// Ignore static resources
|
// Ignore static resources
|
||||||
if (!(uri.startsWith("/css") || uri.startsWith("/js") || uri.startsWith("/images") || uri.endsWith(".ico") || uri.endsWith(".svg")|| uri.endsWith(".js"))) {
|
if (!(uri.startsWith("/js") || uri.startsWith("/images") || uri.endsWith(".ico") || uri.endsWith(".css") || uri.endsWith(".svg")|| uri.endsWith(".js") || uri.contains("swagger") || uri.startsWith("/api"))) {
|
||||||
Counter counter = Counter.builder("http.requests")
|
Counter counter = Counter.builder("http.requests")
|
||||||
.tag("uri", uri)
|
.tag("uri", uri)
|
||||||
.tag("method", request.getMethod())
|
.tag("method", request.getMethod())
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
package stirling.software.SPDF.controller.web;
|
||||||
|
import io.micrometer.core.instrument.Counter;
|
||||||
|
import io.micrometer.core.instrument.Meter;
|
||||||
|
import io.micrometer.core.instrument.MeterRegistry;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1")
|
||||||
|
public class MetricsController {
|
||||||
|
|
||||||
|
private final MeterRegistry meterRegistry;
|
||||||
|
|
||||||
|
public MetricsController(MeterRegistry meterRegistry) {
|
||||||
|
this.meterRegistry = meterRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/status")
|
||||||
|
@Operation(summary = "Application status and version",
|
||||||
|
description = "This endpoint returns the status of the application and its version number.")
|
||||||
|
public Map<String, String> getStatus() {
|
||||||
|
Map<String, String> status = new HashMap<>();
|
||||||
|
status.put("status", "UP");
|
||||||
|
status.put("version", getClass().getPackage().getImplementationVersion());
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/loads")
|
||||||
|
@Operation(summary = "GET request count",
|
||||||
|
description = "This endpoint returns the total count of GET requests or the count of GET requests for a specific endpoint.")
|
||||||
|
public Double getPageLoads(@RequestParam Optional<String> endpoint) {
|
||||||
|
try {
|
||||||
|
double count = 0.0;
|
||||||
|
|
||||||
|
for (Meter meter : meterRegistry.getMeters()) {
|
||||||
|
if (meter.getId().getName().equals("http.requests")) {
|
||||||
|
String method = meter.getId().getTag("method");
|
||||||
|
if (method != null && method.equals("GET")) {
|
||||||
|
if (meter instanceof Counter) {
|
||||||
|
count += ((Counter) meter).count();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return -1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/requests")
|
||||||
|
@Operation(summary = "POST request count",
|
||||||
|
description = "This endpoint returns the total count of POST requests or the count of POST requests for a specific endpoint.")
|
||||||
|
public Double getTotalRequests(@RequestParam Optional<String> endpoint) {
|
||||||
|
try {
|
||||||
|
Counter counter;
|
||||||
|
if (endpoint.isPresent()) {
|
||||||
|
counter = meterRegistry.get("http.requests")
|
||||||
|
.tags("method", "POST", "uri", endpoint.get()).counter();
|
||||||
|
} else {
|
||||||
|
counter = meterRegistry.get("http.requests")
|
||||||
|
.tags("method", "POST").counter();
|
||||||
|
}
|
||||||
|
return counter.count();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -22,5 +22,4 @@ server.servlet.context-path=${APP_ROOT_PATH:/}
|
||||||
spring.devtools.restart.enabled=true
|
spring.devtools.restart.enabled=true
|
||||||
spring.devtools.livereload.enabled=true
|
spring.devtools.livereload.enabled=true
|
||||||
|
|
||||||
spring.thymeleaf.encoding=UTF-8
|
spring.thymeleaf.encoding=UTF-8
|
||||||
|
|
|
@ -151,11 +151,11 @@ function compareVersions(version1, version2) {
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||||
<!-- Existing menu items -->
|
<!-- Existing menu items -->
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('merge-pdfs', 'images/union.svg', 'home.merge.title', 'home.merge.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('merge-pdfs', 'images/union.svg', 'home.merge.title', 'home.merge.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('split-pdfs', 'images/layout-split.svg', 'home.split.title', 'home.split.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('split-pdfs', 'images/layout-split.svg', 'home.split.title', 'home.split.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ( 'pdf-organizer', 'images/sort-numeric-down.svg', 'home.pdfOrganiser.title', 'home.pdfOrganiser.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ( 'pdf-organizer', 'images/sort-numeric-down.svg', 'home.pdfOrganiser.title', 'home.pdfOrganiser.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ( 'rotate-pdf', 'images/arrow-clockwise.svg', 'home.rotate.title', 'home.rotate.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ( 'rotate-pdf', 'images/arrow-clockwise.svg', 'home.rotate.title', 'home.rotate.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ( 'remove-pages', 'images/file-earmark-x.svg', 'home.removePages.title', 'home.removePages.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ( 'remove-pages', 'images/file-earmark-x.svg', 'home.removePages.title', 'home.removePages.desc')}"></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@ -167,16 +167,16 @@ function compareVersions(version1, version2) {
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||||
<!-- Existing menu items -->
|
<!-- Existing menu items -->
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('img-to-pdf', 'images/image.svg', 'home.imageToPdf.title', 'home.imageToPdf.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('img-to-pdf', 'images/image.svg', 'home.imageToPdf.title', 'home.imageToPdf.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('file-to-pdf', 'images/file.svg', 'home.fileToPDF.title', 'home.fileToPDF.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('file-to-pdf', 'images/file.svg', 'home.fileToPDF.title', 'home.fileToPDF.desc')}"></div>
|
||||||
<hr class="dropdown-divider">
|
<hr class="dropdown-divider">
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('pdf-to-img', 'images/image.svg', 'home.pdfToImage.title', 'home.pdfToImage.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-img', 'images/image.svg', 'home.pdfToImage.title', 'home.pdfToImage.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('pdf-to-word', 'images/file-earmark-word.svg', 'home.PDFToWord.title', 'home.PDFToWord.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-word', 'images/file-earmark-word.svg', 'home.PDFToWord.title', 'home.PDFToWord.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('pdf-to-presentation', 'images/file-earmark-ppt.svg', 'home.PDFToPresentation.title', 'home.PDFToPresentation.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-presentation', 'images/file-earmark-ppt.svg', 'home.PDFToPresentation.title', 'home.PDFToPresentation.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('pdf-to-text', 'images/filetype-txt.svg', 'home.PDFToText.title', 'home.PDFToText.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-text', 'images/filetype-txt.svg', 'home.PDFToText.title', 'home.PDFToText.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('pdf-to-html', 'images/filetype-html.svg', 'home.PDFToHTML.title', 'home.PDFToHTML.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-html', 'images/filetype-html.svg', 'home.PDFToHTML.title', 'home.PDFToHTML.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('pdf-to-xml', 'images/filetype-xml.svg', 'home.PDFToXML.title', 'home.PDFToXML.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-xml', 'images/filetype-xml.svg', 'home.PDFToXML.title', 'home.PDFToXML.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('pdf-to-pdfa', 'images/file-earmark-pdf.svg', 'home.pdfToPDFA.title', 'home.pdfToPDFA.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-pdfa', 'images/file-earmark-pdf.svg', 'home.pdfToPDFA.title', 'home.pdfToPDFA.desc')}"></div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -191,10 +191,10 @@ function compareVersions(version1, version2) {
|
||||||
<img class="icon" src="images/shield-check.svg" alt="icon" style="width: 16px; height: 16px; vertical-align: middle;"> <span class="icon-text" th:text="#{navbar.security}"></span>
|
<img class="icon" src="images/shield-check.svg" alt="icon" style="width: 16px; height: 16px; vertical-align: middle;"> <span class="icon-text" th:text="#{navbar.security}"></span>
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('add-password', 'images/lock.svg', 'home.addPassword.title', 'home.addPassword.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('add-password', 'images/lock.svg', 'home.addPassword.title', 'home.addPassword.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('remove-password', 'images/unlock.svg', 'home.removePassword.title', 'home.removePassword.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-password', 'images/unlock.svg', 'home.removePassword.title', 'home.removePassword.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('change-permissions', 'images/shield-lock.svg', 'home.permissions.title', 'home.permissions.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('change-permissions', 'images/shield-lock.svg', 'home.permissions.title', 'home.permissions.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('add-watermark', 'images/droplet.svg', 'home.watermark.title', 'home.watermark.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('add-watermark', 'images/droplet.svg', 'home.watermark.title', 'home.watermark.desc')}"></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
@ -207,18 +207,17 @@ function compareVersions(version1, version2) {
|
||||||
|
|
||||||
</a>
|
</a>
|
||||||
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('ocr-pdf', 'images/search.svg', 'home.ocr.title', 'home.ocr.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('ocr-pdf', 'images/search.svg', 'home.ocr.title', 'home.ocr.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('add-image', 'images/file-earmark-richtext.svg', 'home.addImage.title', 'home.addImage.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('add-image', 'images/file-earmark-richtext.svg', 'home.addImage.title', 'home.addImage.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('compress-pdf', 'images/file-zip.svg', 'home.compressPdfs.title', 'home.compressPdfs.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('compress-pdf', 'images/file-zip.svg', 'home.compressPdfs.title', 'home.compressPdfs.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('extract-images', 'images/images.svg', 'home.extractImages.title', 'home.extractImages.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('extract-images', 'images/images.svg', 'home.extractImages.title', 'home.extractImages.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('change-metadata', 'images/clipboard-data.svg', 'home.changeMetadata.title', 'home.changeMetadata.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('change-metadata', 'images/clipboard-data.svg', 'home.changeMetadata.title', 'home.changeMetadata.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('extract-image-scans', 'images/scanner.svg', 'home.ScannerImageSplit.title', 'home.ScannerImageSplit.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('extract-image-scans', 'images/scanner.svg', 'home.ScannerImageSplit.title', 'home.ScannerImageSplit.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('sign', 'images/sign.svg', 'home.sign.title', 'home.sign.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('sign', 'images/sign.svg', 'home.sign.title', 'home.sign.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('flatten', 'images/flatten.svg', 'home.flatten.title', 'home.flatten.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('flatten', 'images/flatten.svg', 'home.flatten.title', 'home.flatten.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('repair', 'images/wrench.svg', 'home.repair.title', 'home.repair.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('repair', 'images/wrench.svg', 'home.repair.title', 'home.repair.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('remove-blanks', 'images/blank-file.svg', 'home.removeBlanks.title', 'home.removeBlanks.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-blanks', 'images/blank-file.svg', 'home.removeBlanks.title', 'home.removeBlanks.desc')}"></div>
|
||||||
<div th:replace="fragments/navbarEntry :: navbarEntry ('compare', 'images/scales.svg', 'home.compare.title', 'home.compare.desc')"></div>
|
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('compare', 'images/scales.svg', 'home.compare.title', 'home.compare.desc')}"></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
@ -351,9 +350,13 @@ function compareVersions(version1, version2) {
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
<p class="mb-0" th:utext="#{settings.appVersion} + ' ' + ${@appVersion}"></p>
|
<p class="mb-0" th:utext="#{settings.appVersion} + ' ' + ${@appVersion}"></p>
|
||||||
|
<a href="swagger-ui/index.html" target="_blank">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary"> API </button>
|
||||||
|
</a>
|
||||||
<a href="https://github.com/Frooodle/Stirling-PDF/releases" target="_blank">
|
<a href="https://github.com/Frooodle/Stirling-PDF/releases" target="_blank">
|
||||||
<button type="button" class="btn btn-sm btn-outline-primary" id="update-btn" th:utext="#{settings.update}"></button>
|
<button type="button" class="btn btn-sm btn-outline-primary" id="update-btn" th:utext="#{settings.update}"></button>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
@ -375,6 +378,7 @@ function compareVersions(version1, version2) {
|
||||||
<label class="custom-control-label" for="boredWaiting" th:text="#{bored}"></label>
|
<label class="custom-control-label" for="boredWaiting" th:text="#{bored}"></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal" th:text="#{close}"></button>
|
<button type="button" class="btn btn-secondary" data-dismiss="modal" th:text="#{close}"></button>
|
||||||
|
@ -385,6 +389,17 @@ function compareVersions(version1, version2) {
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
$(document).ready(function() {
|
||||||
|
$(".nav-item.dropdown").each(function() {
|
||||||
|
var $dropdownMenu = $(this).find(".dropdown-menu");
|
||||||
|
if ($dropdownMenu.children().length <= 2 && $dropdownMenu.children("hr.dropdown-divider").length === $dropdownMenu.children().length) {
|
||||||
|
$(this).prev('.nav-item.nav-item-separator').remove();
|
||||||
|
$(this).remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Get the download option from local storage, or set it to 'sameWindow' if it doesn't exist
|
// Get the download option from local storage, or set it to 'sameWindow' if it doesn't exist
|
||||||
|
|
Loading…
Reference in a new issue