mirror of
https://github.com/kestra-io/kestra.git
synced 2025-12-25 11:12:12 -05:00
Compare commits
1 Commits
run-develo
...
feat/previ
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
769adad5e8 |
@@ -6,6 +6,8 @@ import io.kestra.core.plugins.PluginCatalogService;
|
||||
import io.kestra.core.plugins.PluginRegistry;
|
||||
import io.kestra.core.storages.StorageInterface;
|
||||
import io.kestra.core.storages.StorageInterfaceFactory;
|
||||
import io.kestra.plugin.core.preview.PreviewRendererFactory;
|
||||
import io.kestra.plugin.core.preview.PreviewRendererRegistry;
|
||||
import io.micronaut.context.annotation.Bean;
|
||||
import io.micronaut.context.annotation.ConfigurationProperties;
|
||||
import io.micronaut.context.annotation.Factory;
|
||||
@@ -87,4 +89,9 @@ public class KestraBeansFactory {
|
||||
return (Map<String, Object>) storage.get(StringConvention.CAMEL_CASE.format(type));
|
||||
}
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public PreviewRendererFactory previewRendererFactory(final PluginRegistry pluginRegistry) {
|
||||
return new PreviewRendererFactory(pluginRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import io.kestra.core.models.ServerType;
|
||||
import io.kestra.core.plugins.PluginRegistry;
|
||||
import io.kestra.core.storages.StorageInterface;
|
||||
import io.kestra.core.utils.VersionProvider;
|
||||
import io.kestra.plugin.core.preview.PreviewRenderer;
|
||||
import io.kestra.plugin.core.preview.PreviewRendererRegistry;
|
||||
import io.micronaut.context.ApplicationContext;
|
||||
import io.micronaut.context.annotation.Context;
|
||||
import io.micronaut.context.annotation.Requires;
|
||||
@@ -82,6 +84,8 @@ public abstract class KestraContext {
|
||||
*/
|
||||
public abstract PluginRegistry getPluginRegistry();
|
||||
|
||||
public abstract PreviewRenderer getPreviewRenderer();
|
||||
|
||||
public abstract StorageInterface getStorageInterface();
|
||||
|
||||
/**
|
||||
@@ -107,8 +111,8 @@ public abstract class KestraContext {
|
||||
/**
|
||||
* Creates a new {@link KestraContext} instance.
|
||||
*
|
||||
* @param applicationContext The {@link ApplicationContext}.
|
||||
* @param environment The {@link Environment}.
|
||||
* @param applicationContext The {@link ApplicationContext}.
|
||||
* @param environment The {@link Environment}.
|
||||
*/
|
||||
public Initializer(ApplicationContext applicationContext,
|
||||
Environment environment) {
|
||||
@@ -118,7 +122,9 @@ public abstract class KestraContext {
|
||||
KestraContext.setContext(this);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} **/
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
**/
|
||||
@Override
|
||||
public ServerType getServerType() {
|
||||
return Optional.ofNullable(environment)
|
||||
@@ -126,20 +132,27 @@ public abstract class KestraContext {
|
||||
.orElse(ServerType.STANDALONE);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} **/
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
**/
|
||||
@Override
|
||||
public Optional<Integer> getWorkerMaxNumThreads() {
|
||||
return Optional.ofNullable(environment)
|
||||
.flatMap(env -> env.getProperty(KESTRA_WORKER_MAX_NUM_THREADS, Integer.class));
|
||||
}
|
||||
|
||||
/** {@inheritDoc} **/
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
**/
|
||||
@Override
|
||||
public Optional<String> getWorkerGroupKey() {
|
||||
return Optional.ofNullable(environment)
|
||||
.flatMap(env -> env.getProperty(KESTRA_WORKER_GROUP_KEY, String.class));
|
||||
}
|
||||
/** {@inheritDoc} **/
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
**/
|
||||
@Override
|
||||
public void injectWorkerConfigs(Integer maxNumThreads, String workerGroupKey) {
|
||||
final Map<String, Object> configs = new HashMap<>();
|
||||
@@ -154,7 +167,9 @@ public abstract class KestraContext {
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} **/
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
**/
|
||||
@Override
|
||||
public void shutdown() {
|
||||
if (isShutdown.compareAndSet(false, true)) {
|
||||
@@ -164,13 +179,17 @@ public abstract class KestraContext {
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} **/
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
**/
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} **/
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
**/
|
||||
@Override
|
||||
public PluginRegistry getPluginRegistry() {
|
||||
// Lazy init of the PluginRegistry.
|
||||
@@ -182,5 +201,11 @@ public abstract class KestraContext {
|
||||
// Lazy init of the PluginRegistry.
|
||||
return this.applicationContext.getBean(StorageInterface.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PreviewRenderer getPreviewRenderer() {
|
||||
// Lazy init of the PreviewRenderer.
|
||||
return this.applicationContext.getBean(PreviewRenderer.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import io.kestra.core.models.tasks.runners.TaskRunner;
|
||||
import io.kestra.core.models.triggers.AbstractTrigger;
|
||||
import io.kestra.core.secret.SecretPluginInterface;
|
||||
import io.kestra.core.storages.StorageInterface;
|
||||
import io.kestra.plugin.core.preview.PreviewRenderer;
|
||||
import io.swagger.v3.oas.annotations.Hidden;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
@@ -117,6 +118,7 @@ public class PluginScanner {
|
||||
List<Class<? extends AdditionalPlugin>> additionalPlugins = new ArrayList<>();
|
||||
List<String> guides = new ArrayList<>();
|
||||
Map<String, Class<?>> aliases = new HashMap<>();
|
||||
List<Class<? extends PreviewRenderer>> previewRenderers = new ArrayList<>();
|
||||
|
||||
if (manifest == null) {
|
||||
manifest = getManifest(classLoader);
|
||||
@@ -186,6 +188,11 @@ public class PluginScanner {
|
||||
log.debug("Loading additional plugin: '{}'", plugin.getClass());
|
||||
additionalPlugins.add(additionalPlugin.getClass());
|
||||
}
|
||||
case PreviewRenderer previewRenderer -> {
|
||||
log.info("Found PreviewRenderer: {}", plugin.getClass().getName());
|
||||
log.debug("Loading PreviewRenderer plugin: '{}'", plugin.getClass());
|
||||
previewRenderers.add(previewRenderer.getClass());
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
@@ -236,6 +243,7 @@ public class PluginScanner {
|
||||
e -> e.getKey().toLowerCase(),
|
||||
Function.identity()
|
||||
)))
|
||||
.previewRenderers(previewRenderers)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import io.kestra.core.models.tasks.runners.TaskRunner;
|
||||
import io.kestra.core.models.triggers.AbstractTrigger;
|
||||
import io.kestra.core.secret.SecretPluginInterface;
|
||||
import io.kestra.core.storages.StorageInterface;
|
||||
import io.kestra.plugin.core.preview.PreviewRenderer;
|
||||
import lombok.*;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
@@ -46,6 +47,8 @@ public class RegisteredPlugin {
|
||||
public static final String DATA_FILTERS_KPI_GROUP_NAME = "data-filters-kpi";
|
||||
public static final String LOG_EXPORTERS_GROUP_NAME = "log-exporters";
|
||||
public static final String ADDITIONAL_PLUGINS_GROUP_NAME = "additional-plugins";
|
||||
public static final String PREVIEW_RENDERERS_GROUP_NAME = "preview-renderers";
|
||||
|
||||
|
||||
private final ExternalPlugin externalPlugin;
|
||||
private final Manifest manifest;
|
||||
@@ -63,6 +66,7 @@ public class RegisteredPlugin {
|
||||
private final List<Class<? extends DataFilterKPI<?, ?>>> dataFiltersKPI;
|
||||
private final List<Class<? extends LogExporter<?>>> logExporters;
|
||||
private final List<Class<? extends AdditionalPlugin>> additionalPlugins;
|
||||
private final List<Class<? extends PreviewRenderer>> previewRenderers;
|
||||
private final List<String> guides;
|
||||
// Map<lowercasealias, <Alias, Class>>
|
||||
private final Map<String, Map.Entry<String, Class<?>>> aliases;
|
||||
@@ -117,6 +121,10 @@ public class RegisteredPlugin {
|
||||
return StorageInterface.class;
|
||||
}
|
||||
|
||||
if (this.getPreviewRenderers().stream().anyMatch(r -> r.getName().equals(cls))) {
|
||||
return PreviewRenderer.class;
|
||||
}
|
||||
|
||||
if (this.getSecrets().stream().anyMatch(r -> r.getName().equals(cls))) {
|
||||
return SecretPluginInterface.class;
|
||||
}
|
||||
@@ -187,6 +195,7 @@ public class RegisteredPlugin {
|
||||
result.put(DATA_FILTERS_KPI_GROUP_NAME, Arrays.asList(this.getDataFiltersKPI().toArray(Class[]::new)));
|
||||
result.put(LOG_EXPORTERS_GROUP_NAME, Arrays.asList(this.getLogExporters().toArray(Class[]::new)));
|
||||
result.put(ADDITIONAL_PLUGINS_GROUP_NAME, Arrays.asList(this.getAdditionalPlugins().toArray(Class[]::new)));
|
||||
result.put(PREVIEW_RENDERERS_GROUP_NAME, Arrays.asList(this.getPreviewRenderers().toArray(Class[]::new)));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ import io.kestra.core.storages.StorageInterface;
|
||||
import io.kestra.core.storages.kv.KVStore;
|
||||
import io.kestra.core.utils.ListUtils;
|
||||
import io.kestra.core.utils.VersionProvider;
|
||||
import io.kestra.plugin.core.preview.PreviewRenderer;
|
||||
import io.kestra.plugin.core.preview.PreviewRendererRegistry;
|
||||
import io.micronaut.context.ApplicationContext;
|
||||
import io.micronaut.core.annotation.Introspected;
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
@@ -602,6 +604,8 @@ public class DefaultRunContext extends RunContext {
|
||||
private List<String> secretInputs;
|
||||
private Task task;
|
||||
private AbstractTrigger trigger;
|
||||
private PreviewRenderer previewRenderer;
|
||||
private PreviewRendererRegistry previewRendererRegistry;
|
||||
|
||||
/**
|
||||
* Builds the new {@link DefaultRunContext} object.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.kestra.webserver.utils.filepreview;
|
||||
package io.kestra.plugin.core.preview;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Getter;
|
||||
@@ -18,7 +18,7 @@ public abstract class FileRender {
|
||||
@JsonInclude
|
||||
public boolean truncated = false;
|
||||
|
||||
FileRender(String extension, Integer maxLine) {
|
||||
protected FileRender(String extension, Integer maxLine) {
|
||||
this.maxLine = maxLine;
|
||||
this.extension = extension;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package io.kestra.plugin.core.preview;
|
||||
|
||||
import io.kestra.core.models.Plugin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Interface for plugins to provide file preview rendering capabilities.
|
||||
* Plugins can implement this to support preview of specific file formats.
|
||||
*/
|
||||
public interface PreviewRenderer extends Plugin {
|
||||
|
||||
/**
|
||||
* File extensions this renderer supports (without dot, e.g., "parquet", "csv")
|
||||
*/
|
||||
List<String> supportedExtensions();
|
||||
|
||||
/**
|
||||
* Render preview for the given file
|
||||
*
|
||||
* @param extension file extension
|
||||
* @param fileStream input stream of the file
|
||||
* @param charset charset for text-based files (optional)
|
||||
* @param maxLines maximum number of lines/records to preview
|
||||
* @return PreviewResult object containing preview data
|
||||
* @throws IOException if file cannot be read or parsed
|
||||
*/
|
||||
PreviewResult render(String extension, InputStream fileStream, Optional<Charset> charset, Integer maxLines) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package io.kestra.plugin.core.preview;
|
||||
|
||||
import io.kestra.core.plugins.PluginRegistry;
|
||||
import io.kestra.core.plugins.RegisteredPlugin;
|
||||
import io.kestra.plugin.core.preview.PreviewRenderer;
|
||||
import jakarta.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Slf4j
|
||||
public class PreviewRendererFactory {
|
||||
|
||||
private final PluginRegistry pluginRegistry;
|
||||
private Map<String, Class<? extends PreviewRenderer>> rendererClasses;
|
||||
|
||||
public PreviewRendererFactory(PluginRegistry pluginRegistry) {
|
||||
this.pluginRegistry = pluginRegistry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get preview renderer for given file extension
|
||||
*/
|
||||
public Optional<PreviewRenderer> getRenderer(String extension) {
|
||||
log.info("Looking for preview renderer for extension: '{}'", extension);
|
||||
|
||||
if (rendererClasses == null) {
|
||||
log.info("Renderer classes not initialized, initializing now...");
|
||||
initializeRenderers();
|
||||
}
|
||||
|
||||
String normalizedExt = extension.toLowerCase();
|
||||
Class<? extends PreviewRenderer> rendererClass = rendererClasses.get(normalizedExt);
|
||||
|
||||
log.info("Available extensions: {}", rendererClasses.keySet());
|
||||
log.info("Looking for normalized extension: '{}', found class: {}", normalizedExt,
|
||||
rendererClass != null ? rendererClass.getName() : "null");
|
||||
|
||||
if (rendererClass == null) {
|
||||
log.warn("No preview renderer found for extension '{}'", extension);
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
try {
|
||||
PreviewRenderer renderer = rendererClass.getDeclaredConstructor().newInstance();
|
||||
log.info("Successfully created preview renderer instance: {}", rendererClass.getSimpleName());
|
||||
return Optional.of(renderer);
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to instantiate preview renderer for extension '{}': {}", extension, e.getMessage(), e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize renderers by discovering all PreviewRenderer plugins
|
||||
*/
|
||||
private void initializeRenderers() {
|
||||
rendererClasses = new HashMap<>();
|
||||
|
||||
log.info("Starting to initialize preview renderers...");
|
||||
|
||||
List<RegisteredPlugin> plugins = pluginRegistry.plugins().stream().toList();
|
||||
log.info("Found {} registered plugins", plugins.size());
|
||||
|
||||
plugins.forEach(plugin -> {
|
||||
List<Class<? extends PreviewRenderer>> renderers = plugin.getPreviewRenderers();
|
||||
log.info("Plugin '{}' has {} preview renderers", plugin.name(), renderers.size());
|
||||
renderers.forEach(rendererClass ->
|
||||
log.info(" - Preview renderer class: {}", rendererClass.getName())
|
||||
);
|
||||
});
|
||||
|
||||
pluginRegistry.plugins()
|
||||
.stream()
|
||||
.map(RegisteredPlugin::getPreviewRenderers)
|
||||
.flatMap(List::stream)
|
||||
.forEach(rendererClass -> {
|
||||
try {
|
||||
log.info("Trying to instantiate preview renderer: {}", rendererClass.getName());
|
||||
PreviewRenderer instance = rendererClass.getDeclaredConstructor().newInstance();
|
||||
List<String> extensions = instance.supportedExtensions();
|
||||
log.info("Preview renderer {} supports extensions: {}", rendererClass.getSimpleName(), extensions);
|
||||
|
||||
for (String extension : extensions) {
|
||||
String normalizedExt = extension.toLowerCase();
|
||||
rendererClasses.put(normalizedExt, rendererClass);
|
||||
log.info("Registered preview renderer for '{}': {}", normalizedExt, rendererClass.getSimpleName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to register preview renderer {}: {}", rendererClass.getSimpleName(), e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
|
||||
log.info("Initialization complete. Registered renderers for extensions: {}", rendererClasses.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all supported extensions
|
||||
*/
|
||||
public List<String> getSupportedExtensions() {
|
||||
if (rendererClasses == null) {
|
||||
initializeRenderers();
|
||||
}
|
||||
return List.copyOf(rendererClasses.keySet());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package io.kestra.plugin.core.preview;
|
||||
|
||||
import jakarta.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class PreviewRendererRegistry {
|
||||
|
||||
private final Map<String, PreviewRenderer> renderers = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Register a preview renderer for specific file extensions
|
||||
*/
|
||||
public void register(PreviewRenderer renderer) {
|
||||
for (String extension : renderer.supportedExtensions()) {
|
||||
String normalizedExt = extension.toLowerCase();
|
||||
if (renderers.containsKey(normalizedExt)) {
|
||||
log.warn("Preview renderer for extension '{}' is being overridden by {}",
|
||||
normalizedExt, renderer.getClass().getSimpleName());
|
||||
}
|
||||
renderers.put(normalizedExt, renderer);
|
||||
log.debug("Registered preview renderer for '{}': {}", normalizedExt, renderer.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get preview renderer for given file extension
|
||||
*/
|
||||
public Optional<PreviewRenderer> getRenderer(String extension) {
|
||||
return Optional.ofNullable(renderers.get(extension.toLowerCase()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if preview is available for given extension
|
||||
*/
|
||||
public boolean hasRenderer(String extension) {
|
||||
return renderers.containsKey(extension.toLowerCase());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package io.kestra.plugin.core.preview;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PreviewResult {
|
||||
public String extension;
|
||||
public Type type;
|
||||
public Object content;
|
||||
public Integer maxLines;
|
||||
|
||||
@JsonInclude
|
||||
public boolean truncated = false;
|
||||
|
||||
public enum Type {
|
||||
TEXT, LIST, IMAGE, MARKDOWN, PDF
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ import io.kestra.webserver.services.ExecutionDependenciesStreamingService;
|
||||
import io.kestra.webserver.services.ExecutionStreamingService;
|
||||
import io.kestra.webserver.utils.PageableUtils;
|
||||
import io.kestra.webserver.utils.RequestUtils;
|
||||
import io.kestra.webserver.utils.filepreview.FileRender;
|
||||
import io.kestra.plugin.core.preview.FileRender;
|
||||
import io.kestra.webserver.utils.filepreview.FileRenderBuilder;
|
||||
import io.micronaut.context.ApplicationContext;
|
||||
import io.micronaut.context.annotation.Value;
|
||||
@@ -201,6 +201,9 @@ public class ExecutionController {
|
||||
@Inject
|
||||
private LocalPathFactory localPathFactory;
|
||||
|
||||
@Inject
|
||||
private FileRenderBuilder fileRenderBuilder;
|
||||
|
||||
@Value("${" + LocalPath.ENABLE_PREVIEW_CONFIG + ":true}")
|
||||
private boolean enableLocalFilePreview;
|
||||
|
||||
@@ -1869,7 +1872,7 @@ public class ExecutionController {
|
||||
};
|
||||
|
||||
try (fileStream) {
|
||||
FileRender fileRender = FileRenderBuilder.of(
|
||||
FileRender fileRender = fileRenderBuilder.of(
|
||||
extension,
|
||||
fileStream,
|
||||
charset,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.kestra.webserver.utils.filepreview;
|
||||
|
||||
import io.kestra.plugin.core.preview.FileRender;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.kestra.webserver.utils.filepreview;
|
||||
|
||||
import io.kestra.plugin.core.preview.FileRender;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
||||
@@ -1,15 +1,40 @@
|
||||
package io.kestra.webserver.utils.filepreview;
|
||||
|
||||
import io.kestra.plugin.core.preview.FileRender;
|
||||
import io.kestra.plugin.core.preview.PreviewRenderer;
|
||||
import io.kestra.plugin.core.preview.PreviewRendererFactory;
|
||||
import io.kestra.plugin.core.preview.PreviewRendererRegistry;
|
||||
import io.kestra.plugin.core.preview.PreviewResult;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Singleton;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Optional;
|
||||
|
||||
@Singleton
|
||||
@Slf4j
|
||||
public class FileRenderBuilder {
|
||||
private static final Charset DEFAULT_FILE_CHARSET = StandardCharsets.UTF_8;
|
||||
|
||||
public static FileRender of(String extension, InputStream filestream, Optional<Charset> charset, Integer maxLine) throws IOException {
|
||||
@Inject
|
||||
private PreviewRendererFactory previewRendererFactory;
|
||||
|
||||
public FileRender of(String extension, InputStream filestream, Optional<Charset> charset, Integer maxLine) throws IOException {
|
||||
// we check plugin renderers first
|
||||
Optional<PreviewRenderer> pluginRenderer = previewRendererFactory.getRenderer(extension);
|
||||
if (pluginRenderer.isPresent()) {
|
||||
try {
|
||||
PreviewResult result = pluginRenderer.get().render(extension, filestream, charset, maxLine);
|
||||
return convertToFileRender(result);
|
||||
} catch (Exception e) {
|
||||
log.warn("Plugin preview renderer failed for extension '{}': {}", extension, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (ImageFileRender.ImageFileExtension.isImageFileExtension(extension)) {
|
||||
return new ImageFileRender(extension, filestream, maxLine);
|
||||
}
|
||||
@@ -21,4 +46,24 @@ public class FileRenderBuilder {
|
||||
default -> new DefaultFileRender(extension, filestream, charset.orElse(DEFAULT_FILE_CHARSET), maxLine);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private FileRender convertToFileRender(PreviewResult result) {
|
||||
return new FileRender(result.getExtension(), result.getMaxLines()) {
|
||||
{
|
||||
this.type = convertType(result.getType());
|
||||
this.content = result.getContent();
|
||||
this.truncated = result.isTruncated();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private FileRender.Type convertType(PreviewResult.Type type) {
|
||||
return switch (type) {
|
||||
case TEXT -> FileRender.Type.TEXT;
|
||||
case LIST -> FileRender.Type.LIST;
|
||||
case IMAGE -> FileRender.Type.IMAGE;
|
||||
case MARKDOWN -> FileRender.Type.MARKDOWN;
|
||||
case PDF -> FileRender.Type.PDF;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.kestra.webserver.utils.filepreview;
|
||||
|
||||
import io.kestra.core.serializers.FileSerde;
|
||||
import io.kestra.plugin.core.preview.FileRender;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.kestra.webserver.utils.filepreview;
|
||||
|
||||
import jakarta.inject.Inject;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
@@ -13,13 +14,16 @@ import java.util.stream.Stream;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class FileRenderBuilderTest {
|
||||
|
||||
@Inject
|
||||
private FileRenderBuilder fileRenderBuilder;
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideExtensions")
|
||||
void of(String extension, Class returnedClass) throws IOException {
|
||||
var emptyInput = new ByteArrayInputStream("".getBytes());
|
||||
var charset = StandardCharsets.UTF_8;
|
||||
|
||||
assertThat(FileRenderBuilder.of(extension, emptyInput, Optional.of(charset), 1000).getClass()).isEqualTo(returnedClass);
|
||||
assertThat(fileRenderBuilder.of(extension, emptyInput, Optional.of(charset), 1000).getClass()).isEqualTo(returnedClass);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> provideExtensions() {
|
||||
|
||||
Reference in New Issue
Block a user