asset metadata form added
This commit is contained in:
parent
f34c5a7691
commit
4050fcbcaa
@ -14,6 +14,7 @@ public record PackerAssetDetailsDTO(
|
|||||||
OutputCodecCatalog outputCodec,
|
OutputCodecCatalog outputCodec,
|
||||||
List<OutputCodecCatalog> availableOutputCodecs,
|
List<OutputCodecCatalog> availableOutputCodecs,
|
||||||
Map<OutputCodecCatalog, List<PackerCodecConfigurationFieldDTO>> codecConfigurationFieldsByCodec,
|
Map<OutputCodecCatalog, List<PackerCodecConfigurationFieldDTO>> codecConfigurationFieldsByCodec,
|
||||||
|
List<PackerCodecConfigurationFieldDTO> metadataFields,
|
||||||
Map<String, List<Path>> inputsByRole,
|
Map<String, List<Path>> inputsByRole,
|
||||||
List<PackerDiagnosticDTO> diagnostics) {
|
List<PackerDiagnosticDTO> diagnostics) {
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ public record PackerAssetDetailsDTO(
|
|||||||
outputCodec = Objects.requireNonNullElse(outputCodec, OutputCodecCatalog.UNKNOWN);
|
outputCodec = Objects.requireNonNullElse(outputCodec, OutputCodecCatalog.UNKNOWN);
|
||||||
availableOutputCodecs = List.copyOf(Objects.requireNonNull(availableOutputCodecs, "availableOutputCodecs"));
|
availableOutputCodecs = List.copyOf(Objects.requireNonNull(availableOutputCodecs, "availableOutputCodecs"));
|
||||||
codecConfigurationFieldsByCodec = Map.copyOf(Objects.requireNonNull(codecConfigurationFieldsByCodec, "codecConfigurationFieldsByCodec"));
|
codecConfigurationFieldsByCodec = Map.copyOf(Objects.requireNonNull(codecConfigurationFieldsByCodec, "codecConfigurationFieldsByCodec"));
|
||||||
|
metadataFields = List.copyOf(Objects.requireNonNull(metadataFields, "metadataFields"));
|
||||||
inputsByRole = Map.copyOf(Objects.requireNonNull(inputsByRole, "inputsByRole"));
|
inputsByRole = Map.copyOf(Objects.requireNonNull(inputsByRole, "inputsByRole"));
|
||||||
diagnostics = List.copyOf(Objects.requireNonNull(diagnostics, "diagnostics"));
|
diagnostics = List.copyOf(Objects.requireNonNull(diagnostics, "diagnostics"));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,12 +10,14 @@ public record UpdateAssetContractRequest(
|
|||||||
AssetReference assetReference,
|
AssetReference assetReference,
|
||||||
boolean preloadEnabled,
|
boolean preloadEnabled,
|
||||||
OutputCodecCatalog outputCodec,
|
OutputCodecCatalog outputCodec,
|
||||||
Map<String, String> codecFieldValues) {
|
Map<String, String> codecFieldValues,
|
||||||
|
Map<String, String> metadataFieldValues) {
|
||||||
|
|
||||||
public UpdateAssetContractRequest {
|
public UpdateAssetContractRequest {
|
||||||
Objects.requireNonNull(project, "project");
|
Objects.requireNonNull(project, "project");
|
||||||
Objects.requireNonNull(assetReference, "assetReference");
|
Objects.requireNonNull(assetReference, "assetReference");
|
||||||
outputCodec = Objects.requireNonNullElse(outputCodec, OutputCodecCatalog.UNKNOWN);
|
outputCodec = Objects.requireNonNullElse(outputCodec, OutputCodecCatalog.UNKNOWN);
|
||||||
codecFieldValues = Map.copyOf(Objects.requireNonNullElse(codecFieldValues, Map.of()));
|
codecFieldValues = Map.copyOf(Objects.requireNonNullElse(codecFieldValues, Map.of()));
|
||||||
|
metadataFieldValues = Map.copyOf(Objects.requireNonNullElse(metadataFieldValues, Map.of()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@ public record PackerAssetDeclaration(
|
|||||||
Map<String, List<String>> inputsByRole,
|
Map<String, List<String>> inputsByRole,
|
||||||
OutputFormatCatalog outputFormat,
|
OutputFormatCatalog outputFormat,
|
||||||
OutputCodecCatalog outputCodec,
|
OutputCodecCatalog outputCodec,
|
||||||
|
Map<String, String> outputMetadata,
|
||||||
boolean preloadEnabled) {
|
boolean preloadEnabled) {
|
||||||
|
|
||||||
public PackerAssetDeclaration {
|
public PackerAssetDeclaration {
|
||||||
@ -29,6 +30,7 @@ public record PackerAssetDeclaration(
|
|||||||
inputsByRole = Map.copyOf(Objects.requireNonNull(inputsByRole, "inputsByRole"));
|
inputsByRole = Map.copyOf(Objects.requireNonNull(inputsByRole, "inputsByRole"));
|
||||||
outputFormat = Objects.requireNonNull(outputFormat, "outputFormat");
|
outputFormat = Objects.requireNonNull(outputFormat, "outputFormat");
|
||||||
outputCodec = Objects.requireNonNull(outputCodec, "outputCodec");
|
outputCodec = Objects.requireNonNull(outputCodec, "outputCodec");
|
||||||
|
outputMetadata = Map.copyOf(Objects.requireNonNull(outputMetadata, "outputMetadata"));
|
||||||
if (StringUtils.isBlank(assetUuid) || StringUtils.isBlank(name)) {
|
if (StringUtils.isBlank(assetUuid) || StringUtils.isBlank(name)) {
|
||||||
throw new IllegalArgumentException("declaration fields must not be blank");
|
throw new IllegalArgumentException("declaration fields must not be blank");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ public record PackerAssetDetails(
|
|||||||
OutputCodecCatalog outputCodec,
|
OutputCodecCatalog outputCodec,
|
||||||
List<OutputCodecCatalog> availableOutputCodecs,
|
List<OutputCodecCatalog> availableOutputCodecs,
|
||||||
Map<OutputCodecCatalog, List<PackerCodecConfigurationField>> codecConfigurationFieldsByCodec,
|
Map<OutputCodecCatalog, List<PackerCodecConfigurationField>> codecConfigurationFieldsByCodec,
|
||||||
|
List<PackerCodecConfigurationField> metadataFields,
|
||||||
Map<String, List<Path>> inputsByRole,
|
Map<String, List<Path>> inputsByRole,
|
||||||
List<PackerDiagnostic> diagnostics) {
|
List<PackerDiagnostic> diagnostics) {
|
||||||
|
|
||||||
@ -23,6 +24,7 @@ public record PackerAssetDetails(
|
|||||||
outputCodec = Objects.requireNonNullElse(outputCodec, OutputCodecCatalog.UNKNOWN);
|
outputCodec = Objects.requireNonNullElse(outputCodec, OutputCodecCatalog.UNKNOWN);
|
||||||
availableOutputCodecs = List.copyOf(Objects.requireNonNull(availableOutputCodecs, "availableOutputCodecs"));
|
availableOutputCodecs = List.copyOf(Objects.requireNonNull(availableOutputCodecs, "availableOutputCodecs"));
|
||||||
codecConfigurationFieldsByCodec = Map.copyOf(Objects.requireNonNull(codecConfigurationFieldsByCodec, "codecConfigurationFieldsByCodec"));
|
codecConfigurationFieldsByCodec = Map.copyOf(Objects.requireNonNull(codecConfigurationFieldsByCodec, "codecConfigurationFieldsByCodec"));
|
||||||
|
metadataFields = List.copyOf(Objects.requireNonNull(metadataFields, "metadataFields"));
|
||||||
inputsByRole = Map.copyOf(Objects.requireNonNull(inputsByRole, "inputsByRole"));
|
inputsByRole = Map.copyOf(Objects.requireNonNull(inputsByRole, "inputsByRole"));
|
||||||
diagnostics = List.copyOf(Objects.requireNonNull(diagnostics, "diagnostics"));
|
diagnostics = List.copyOf(Objects.requireNonNull(diagnostics, "diagnostics"));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -672,6 +672,17 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
|
|||||||
}
|
}
|
||||||
codecConfigurationNode.put(normalizedFieldKey, Objects.requireNonNullElse(fieldValue, ""));
|
codecConfigurationNode.put(normalizedFieldKey, Objects.requireNonNullElse(fieldValue, ""));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final ObjectNode metadataNode = mutableObject(outputNode, "metadata");
|
||||||
|
metadataNode.removeAll();
|
||||||
|
request.metadataFieldValues().entrySet().stream()
|
||||||
|
.sorted(Map.Entry.comparingByKey())
|
||||||
|
.forEach(entry -> {
|
||||||
|
if (entry.getKey() == null || entry.getKey().isBlank()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
metadataNode.put(entry.getKey().trim(), Objects.requireNonNullElse(entry.getValue(), ""));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private ObjectNode mutableObject(ObjectNode parent, String fieldName) {
|
private ObjectNode mutableObject(ObjectNode parent, String fieldName) {
|
||||||
|
|||||||
@ -47,6 +47,7 @@ public final class PackerAssetDeclarationParser {
|
|||||||
final Map<String, List<String>> inputsByRole = requiredInputs(root.path("inputs"), diagnostics, manifestPath);
|
final Map<String, List<String>> inputsByRole = requiredInputs(root.path("inputs"), diagnostics, manifestPath);
|
||||||
final OutputFormatCatalog outputFormat = requiredOutputFormat(root.path("output"), diagnostics, manifestPath);
|
final OutputFormatCatalog outputFormat = requiredOutputFormat(root.path("output"), diagnostics, manifestPath);
|
||||||
final OutputCodecCatalog outputCodec = requiredOutputCodec(root.path("output"), diagnostics, manifestPath);
|
final OutputCodecCatalog outputCodec = requiredOutputCodec(root.path("output"), diagnostics, manifestPath);
|
||||||
|
final Map<String, String> outputMetadata = optionalOutputMetadata(root.path("output"), diagnostics, manifestPath);
|
||||||
final Boolean preloadEnabled = requiredBoolean(root.path("preload"), "enabled", diagnostics, manifestPath);
|
final Boolean preloadEnabled = requiredBoolean(root.path("preload"), "enabled", diagnostics, manifestPath);
|
||||||
|
|
||||||
if (schemaVersion != null && schemaVersion != SUPPORTED_SCHEMA_VERSION) {
|
if (schemaVersion != null && schemaVersion != SUPPORTED_SCHEMA_VERSION) {
|
||||||
@ -71,6 +72,7 @@ public final class PackerAssetDeclarationParser {
|
|||||||
inputsByRole,
|
inputsByRole,
|
||||||
outputFormat,
|
outputFormat,
|
||||||
outputCodec,
|
outputCodec,
|
||||||
|
outputMetadata,
|
||||||
preloadEnabled),
|
preloadEnabled),
|
||||||
diagnostics);
|
diagnostics);
|
||||||
}
|
}
|
||||||
@ -156,6 +158,53 @@ public final class PackerAssetDeclarationParser {
|
|||||||
return outputCodec;
|
return outputCodec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<String, String> optionalOutputMetadata(
|
||||||
|
JsonNode outputNode,
|
||||||
|
List<PackerDiagnostic> diagnostics,
|
||||||
|
Path manifestPath) {
|
||||||
|
final JsonNode metadataNode = outputNode.path("metadata");
|
||||||
|
if (metadataNode.isMissingNode() || metadataNode.isNull()) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
if (!metadataNode.isObject()) {
|
||||||
|
diagnostics.add(new PackerDiagnostic(
|
||||||
|
PackerDiagnosticSeverity.ERROR,
|
||||||
|
PackerDiagnosticCategory.STRUCTURAL,
|
||||||
|
"Field 'output.metadata' must be a JSON object.",
|
||||||
|
manifestPath,
|
||||||
|
true));
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
final Map<String, String> metadata = new LinkedHashMap<>();
|
||||||
|
metadataNode.fields().forEachRemaining(entry -> {
|
||||||
|
final String key = Objects.requireNonNullElse(entry.getKey(), "").trim();
|
||||||
|
if (key.isBlank()) {
|
||||||
|
diagnostics.add(new PackerDiagnostic(
|
||||||
|
PackerDiagnosticSeverity.ERROR,
|
||||||
|
PackerDiagnosticCategory.STRUCTURAL,
|
||||||
|
"Field 'output.metadata' has an invalid empty key.",
|
||||||
|
manifestPath,
|
||||||
|
true));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final JsonNode valueNode = entry.getValue();
|
||||||
|
if (valueNode == null || valueNode.isContainerNode()) {
|
||||||
|
diagnostics.add(new PackerDiagnostic(
|
||||||
|
PackerDiagnosticSeverity.ERROR,
|
||||||
|
PackerDiagnosticCategory.STRUCTURAL,
|
||||||
|
"Field 'output.metadata' values must be scalar (text/number/boolean).",
|
||||||
|
manifestPath,
|
||||||
|
true));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
metadata.put(key, valueNode.asText());
|
||||||
|
});
|
||||||
|
|
||||||
|
return Map.copyOf(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, List<String>> requiredInputs(JsonNode inputsNode, List<PackerDiagnostic> diagnostics, Path manifestPath) {
|
private Map<String, List<String>> requiredInputs(JsonNode inputsNode, List<PackerDiagnostic> diagnostics, Path manifestPath) {
|
||||||
if (!inputsNode.isObject()) {
|
if (!inputsNode.isObject()) {
|
||||||
diagnostics.add(missingOrInvalid("inputs", "object of input roles", manifestPath));
|
diagnostics.add(missingOrInvalid("inputs", "object of input roles", manifestPath));
|
||||||
|
|||||||
@ -73,6 +73,7 @@ public final class PackerAssetDetailsService {
|
|||||||
declaration.outputCodec(),
|
declaration.outputCodec(),
|
||||||
outputContract.availableCodecs(),
|
outputContract.availableCodecs(),
|
||||||
outputContract.codecConfigurationFieldsByCodec(),
|
outputContract.codecConfigurationFieldsByCodec(),
|
||||||
|
metadataFields(declaration.outputMetadata()),
|
||||||
resolveInputs(resolved.assetRoot(), declaration.inputsByRole()),
|
resolveInputs(resolved.assetRoot(), declaration.inputsByRole()),
|
||||||
diagnostics);
|
diagnostics);
|
||||||
return new GetAssetDetailsResult(
|
return new GetAssetDetailsResult(
|
||||||
@ -111,6 +112,7 @@ public final class PackerAssetDetailsService {
|
|||||||
OutputCodecCatalog.UNKNOWN,
|
OutputCodecCatalog.UNKNOWN,
|
||||||
List.of(OutputCodecCatalog.NONE),
|
List.of(OutputCodecCatalog.NONE),
|
||||||
Map.of(OutputCodecCatalog.NONE, List.of()),
|
Map.of(OutputCodecCatalog.NONE, List.of()),
|
||||||
|
List.of(),
|
||||||
Map.of(),
|
Map.of(),
|
||||||
diagnostics);
|
diagnostics);
|
||||||
return new GetAssetDetailsResult(
|
return new GetAssetDetailsResult(
|
||||||
@ -130,6 +132,18 @@ public final class PackerAssetDetailsService {
|
|||||||
return Map.copyOf(resolved);
|
return Map.copyOf(resolved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<PackerCodecConfigurationField> metadataFields(Map<String, String> outputMetadata) {
|
||||||
|
return outputMetadata.entrySet().stream()
|
||||||
|
.map(entry -> new PackerCodecConfigurationField(
|
||||||
|
entry.getKey(),
|
||||||
|
entry.getKey(),
|
||||||
|
PackerCodecConfigurationFieldType.TEXT,
|
||||||
|
entry.getValue(),
|
||||||
|
false,
|
||||||
|
List.of()))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
private List<PackerDiagnostic> identityMismatchDiagnostics(
|
private List<PackerDiagnostic> identityMismatchDiagnostics(
|
||||||
final Optional<PackerRegistryEntry> registryEntry,
|
final Optional<PackerRegistryEntry> registryEntry,
|
||||||
final PackerAssetDeclaration declaration,
|
final PackerAssetDeclaration declaration,
|
||||||
|
|||||||
@ -30,6 +30,7 @@ public final class PackerReadMessageMapper {
|
|||||||
details.outputCodec(),
|
details.outputCodec(),
|
||||||
details.availableOutputCodecs(),
|
details.availableOutputCodecs(),
|
||||||
toCodecConfigurationFieldsByCodecDTO(details.codecConfigurationFieldsByCodec()),
|
toCodecConfigurationFieldsByCodecDTO(details.codecConfigurationFieldsByCodec()),
|
||||||
|
toCodecConfigurationFieldDTOs(details.metadataFields()),
|
||||||
details.inputsByRole(),
|
details.inputsByRole(),
|
||||||
toDiagnosticDTOs(details.diagnostics()));
|
toDiagnosticDTOs(details.diagnostics()));
|
||||||
}
|
}
|
||||||
@ -74,6 +75,11 @@ public final class PackerReadMessageMapper {
|
|||||||
field.options());
|
field.options());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static List<PackerCodecConfigurationFieldDTO> toCodecConfigurationFieldDTOs(
|
||||||
|
List<PackerCodecConfigurationField> fields) {
|
||||||
|
return fields.stream().map(PackerReadMessageMapper::toCodecConfigurationFieldDTO).toList();
|
||||||
|
}
|
||||||
|
|
||||||
private static PackerDiagnosticDTO toDiagnosticDTO(PackerDiagnostic diagnostic) {
|
private static PackerDiagnosticDTO toDiagnosticDTO(PackerDiagnostic diagnostic) {
|
||||||
return new PackerDiagnosticDTO(
|
return new PackerDiagnosticDTO(
|
||||||
diagnostic.severity(),
|
diagnostic.severity(),
|
||||||
|
|||||||
@ -191,7 +191,10 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
OutputCodecCatalog.NONE,
|
OutputCodecCatalog.NONE,
|
||||||
Map.of(
|
Map.of(
|
||||||
"NONE:packMode", "tight",
|
"NONE:packMode", "tight",
|
||||||
"NONE:palette", "mono")));
|
"NONE:palette", "mono"),
|
||||||
|
Map.of(
|
||||||
|
"tile_size", "16",
|
||||||
|
"channels", "1")));
|
||||||
|
|
||||||
assertTrue(result.success());
|
assertTrue(result.success());
|
||||||
assertNull(result.errorMessage());
|
assertNull(result.errorMessage());
|
||||||
@ -202,6 +205,8 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
assertEquals("NONE", manifest.path("output").path("codec").asText());
|
assertEquals("NONE", manifest.path("output").path("codec").asText());
|
||||||
assertEquals("tight", manifest.path("output").path("codec_configuration").path("packMode").asText());
|
assertEquals("tight", manifest.path("output").path("codec_configuration").path("packMode").asText());
|
||||||
assertEquals("mono", manifest.path("output").path("codec_configuration").path("palette").asText());
|
assertEquals("mono", manifest.path("output").path("codec_configuration").path("palette").asText());
|
||||||
|
assertEquals("16", manifest.path("output").path("metadata").path("tile_size").asText());
|
||||||
|
assertEquals("1", manifest.path("output").path("metadata").path("channels").asText());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -218,7 +223,8 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
AssetReference.forAssetId(1),
|
AssetReference.forAssetId(1),
|
||||||
false,
|
false,
|
||||||
OutputCodecCatalog.NONE,
|
OutputCodecCatalog.NONE,
|
||||||
Map.of("NONE:packMode", "tight")));
|
Map.of("NONE:packMode", "tight"),
|
||||||
|
Map.of()));
|
||||||
|
|
||||||
assertTrue(updateResult.success());
|
assertTrue(updateResult.success());
|
||||||
assertEquals(1, loader.loadCount());
|
assertEquals(1, loader.loadCount());
|
||||||
@ -243,6 +249,7 @@ final class FileSystemPackerWorkspaceServiceTest {
|
|||||||
AssetReference.forAssetId(1),
|
AssetReference.forAssetId(1),
|
||||||
true,
|
true,
|
||||||
OutputCodecCatalog.NONE,
|
OutputCodecCatalog.NONE,
|
||||||
|
Map.of(),
|
||||||
Map.of()));
|
Map.of()));
|
||||||
|
|
||||||
assertFalse(result.success());
|
assertFalse(result.success());
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package p.packer.services;
|
package p.packer.services;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.io.TempDir;
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
import p.packer.messages.AssetReference;
|
import p.packer.messages.AssetReference;
|
||||||
@ -16,6 +17,7 @@ import java.nio.file.Files;
|
|||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
@ -57,6 +59,30 @@ final class PackerAssetDetailsServiceTest {
|
|||||||
assertEquals(List.of(), result.details().codecConfigurationFieldsByCodec().get(OutputCodecCatalog.NONE));
|
assertEquals(List.of(), result.details().codecConfigurationFieldsByCodec().get(OutputCodecCatalog.NONE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void exposesMetadataFieldsFromOutputMetadataContract() throws Exception {
|
||||||
|
final Path projectRoot = copyFixture("workspaces/managed-basic", tempDir.resolve("managed-with-metadata"));
|
||||||
|
final Path manifestPath = projectRoot.resolve("assets/ui/atlas/asset.json");
|
||||||
|
|
||||||
|
final ObjectMapper mapper = new ObjectMapper();
|
||||||
|
final var manifest = mapper.readTree(manifestPath.toFile());
|
||||||
|
final ObjectNode output = (ObjectNode) manifest.path("output");
|
||||||
|
final ObjectNode metadata = output.putObject("metadata");
|
||||||
|
metadata.put("tile_size", "16");
|
||||||
|
metadata.put("channels", "1");
|
||||||
|
mapper.writerWithDefaultPrettyPrinter().writeValue(manifestPath.toFile(), manifest);
|
||||||
|
|
||||||
|
final PackerAssetDetailsService service = service();
|
||||||
|
final var result = service.getAssetDetails(new GetAssetDetailsRequest(project(projectRoot), AssetReference.forAssetId(1)));
|
||||||
|
|
||||||
|
assertEquals(PackerOperationStatus.SUCCESS, result.status());
|
||||||
|
assertEquals(
|
||||||
|
Map.of("tile_size", "16", "channels", "1"),
|
||||||
|
result.details().metadataFields().stream().collect(java.util.stream.Collectors.toMap(
|
||||||
|
field -> field.key(),
|
||||||
|
field -> field.value())));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void returnsInvalidDetailsForInvalidDeclaration() throws Exception {
|
void returnsInvalidDetailsForInvalidDeclaration() throws Exception {
|
||||||
final Path projectRoot = copyFixture("workspaces/invalid-missing-fields", tempDir.resolve("invalid"));
|
final Path projectRoot = copyFixture("workspaces/invalid-missing-fields", tempDir.resolve("invalid"));
|
||||||
|
|||||||
@ -97,6 +97,7 @@ public enum I18n {
|
|||||||
ASSETS_SECTION_SUMMARY("assets.section.summary"),
|
ASSETS_SECTION_SUMMARY("assets.section.summary"),
|
||||||
ASSETS_SECTION_RUNTIME_CONTRACT("assets.section.runtimeContract"),
|
ASSETS_SECTION_RUNTIME_CONTRACT("assets.section.runtimeContract"),
|
||||||
ASSETS_SUBSECTION_CODEC_CONFIGURATION("assets.subsection.codecConfiguration"),
|
ASSETS_SUBSECTION_CODEC_CONFIGURATION("assets.subsection.codecConfiguration"),
|
||||||
|
ASSETS_SUBSECTION_METADATA("assets.subsection.metadata"),
|
||||||
ASSETS_SECTION_INPUTS_PREVIEW("assets.section.inputsPreview"),
|
ASSETS_SECTION_INPUTS_PREVIEW("assets.section.inputsPreview"),
|
||||||
ASSETS_SECTION_DIAGNOSTICS("assets.section.diagnostics"),
|
ASSETS_SECTION_DIAGNOSTICS("assets.section.diagnostics"),
|
||||||
ASSETS_SECTION_ACTIONS("assets.section.actions"),
|
ASSETS_SECTION_ACTIONS("assets.section.actions"),
|
||||||
@ -177,6 +178,7 @@ public enum I18n {
|
|||||||
ASSETS_DETAILS_READY("assets.details.ready"),
|
ASSETS_DETAILS_READY("assets.details.ready"),
|
||||||
ASSETS_DETAILS_NO_SELECTION("assets.details.noSelection"),
|
ASSETS_DETAILS_NO_SELECTION("assets.details.noSelection"),
|
||||||
ASSETS_DETAILS_CODEC_CONFIGURATION_EMPTY("assets.details.codecConfiguration.empty"),
|
ASSETS_DETAILS_CODEC_CONFIGURATION_EMPTY("assets.details.codecConfiguration.empty"),
|
||||||
|
ASSETS_DETAILS_METADATA_EMPTY("assets.details.metadata.empty"),
|
||||||
ASSETS_ADD_WIZARD_TITLE("assets.addWizard.title"),
|
ASSETS_ADD_WIZARD_TITLE("assets.addWizard.title"),
|
||||||
ASSETS_ADD_WIZARD_DESCRIPTION("assets.addWizard.description"),
|
ASSETS_ADD_WIZARD_DESCRIPTION("assets.addWizard.description"),
|
||||||
ASSETS_ADD_WIZARD_STEP_ROOT_TITLE("assets.addWizard.step.root.title"),
|
ASSETS_ADD_WIZARD_STEP_ROOT_TITLE("assets.addWizard.step.root.title"),
|
||||||
|
|||||||
@ -416,6 +416,7 @@ public final class AssetDetailsControl extends VBox implements StudioEventAware
|
|||||||
details.outputCodec(),
|
details.outputCodec(),
|
||||||
details.availableOutputCodecs(),
|
details.availableOutputCodecs(),
|
||||||
details.codecConfigurationFieldsByCodec(),
|
details.codecConfigurationFieldsByCodec(),
|
||||||
|
details.metadataFields(),
|
||||||
Map.copyOf(details.inputsByRole()));
|
Map.copyOf(details.inputsByRole()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,45 +14,60 @@ public record AssetContractDraft(
|
|||||||
boolean preload,
|
boolean preload,
|
||||||
OutputFormatCatalog bank,
|
OutputFormatCatalog bank,
|
||||||
OutputCodecCatalog selectedCodec,
|
OutputCodecCatalog selectedCodec,
|
||||||
Map<String, String> codecFieldValues) {
|
Map<String, String> codecFieldValues,
|
||||||
|
Map<String, String> metadataFieldValues) {
|
||||||
|
|
||||||
public AssetContractDraft {
|
public AssetContractDraft {
|
||||||
Objects.requireNonNull(assetReference, "assetReference");
|
Objects.requireNonNull(assetReference, "assetReference");
|
||||||
bank = Objects.requireNonNullElse(bank, OutputFormatCatalog.UNKNOWN);
|
bank = Objects.requireNonNullElse(bank, OutputFormatCatalog.UNKNOWN);
|
||||||
selectedCodec = Objects.requireNonNullElse(selectedCodec, OutputCodecCatalog.UNKNOWN);
|
selectedCodec = Objects.requireNonNullElse(selectedCodec, OutputCodecCatalog.UNKNOWN);
|
||||||
codecFieldValues = Map.copyOf(Objects.requireNonNull(codecFieldValues, "codecFieldValues"));
|
codecFieldValues = Map.copyOf(Objects.requireNonNull(codecFieldValues, "codecFieldValues"));
|
||||||
|
metadataFieldValues = Map.copyOf(Objects.requireNonNull(metadataFieldValues, "metadataFieldValues"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AssetContractDraft fromDetails(AssetWorkspaceAssetDetails details) {
|
public static AssetContractDraft fromDetails(AssetWorkspaceAssetDetails details) {
|
||||||
final Map<String, String> codecFieldValues = new LinkedHashMap<>();
|
final Map<String, String> codecFieldValues = new LinkedHashMap<>();
|
||||||
details.codecConfigurationFieldsByCodec().forEach((codec, fields) ->
|
details.codecConfigurationFieldsByCodec().forEach((codec, fields) ->
|
||||||
fields.forEach(field -> codecFieldValues.put(keyOf(codec, field.key()), field.value())));
|
fields.forEach(field -> codecFieldValues.put(keyOf(codec, field.key()), field.value())));
|
||||||
|
final Map<String, String> metadataFieldValues = new LinkedHashMap<>();
|
||||||
|
details.metadataFields().forEach(field -> metadataFieldValues.put(field.key(), field.value()));
|
||||||
return new AssetContractDraft(
|
return new AssetContractDraft(
|
||||||
details.summary().assetReference(),
|
details.summary().assetReference(),
|
||||||
details.summary().preload(),
|
details.summary().preload(),
|
||||||
details.outputFormat(),
|
details.outputFormat(),
|
||||||
details.outputCodec(),
|
details.outputCodec(),
|
||||||
codecFieldValues);
|
codecFieldValues,
|
||||||
|
metadataFieldValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AssetContractDraft withPreload(boolean preload) {
|
public AssetContractDraft withPreload(boolean preload) {
|
||||||
return new AssetContractDraft(assetReference, preload, bank, selectedCodec, codecFieldValues);
|
return new AssetContractDraft(assetReference, preload, bank, selectedCodec, codecFieldValues, metadataFieldValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AssetContractDraft withSelectedCodec(OutputCodecCatalog selectedCodec) {
|
public AssetContractDraft withSelectedCodec(OutputCodecCatalog selectedCodec) {
|
||||||
return new AssetContractDraft(assetReference, preload, bank, selectedCodec, codecFieldValues);
|
return new AssetContractDraft(assetReference, preload, bank, selectedCodec, codecFieldValues, metadataFieldValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AssetContractDraft withCodecFieldValue(OutputCodecCatalog codec, String fieldKey, String value) {
|
public AssetContractDraft withCodecFieldValue(OutputCodecCatalog codec, String fieldKey, String value) {
|
||||||
final Map<String, String> nextValues = new LinkedHashMap<>(codecFieldValues);
|
final Map<String, String> nextValues = new LinkedHashMap<>(codecFieldValues);
|
||||||
nextValues.put(keyOf(codec, fieldKey), Objects.requireNonNullElse(value, ""));
|
nextValues.put(keyOf(codec, fieldKey), Objects.requireNonNullElse(value, ""));
|
||||||
return new AssetContractDraft(assetReference, preload, bank, selectedCodec, nextValues);
|
return new AssetContractDraft(assetReference, preload, bank, selectedCodec, nextValues, metadataFieldValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssetContractDraft withMetadataFieldValue(String fieldKey, String value) {
|
||||||
|
final Map<String, String> nextValues = new LinkedHashMap<>(metadataFieldValues);
|
||||||
|
nextValues.put(fieldKey, Objects.requireNonNullElse(value, ""));
|
||||||
|
return new AssetContractDraft(assetReference, preload, bank, selectedCodec, codecFieldValues, nextValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String codecFieldValue(OutputCodecCatalog codec, String fieldKey, String fallback) {
|
public String codecFieldValue(OutputCodecCatalog codec, String fieldKey, String fallback) {
|
||||||
return codecFieldValues.getOrDefault(keyOf(codec, fieldKey), Objects.requireNonNullElse(fallback, ""));
|
return codecFieldValues.getOrDefault(keyOf(codec, fieldKey), Objects.requireNonNullElse(fallback, ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String metadataFieldValue(String fieldKey, String fallback) {
|
||||||
|
return metadataFieldValues.getOrDefault(fieldKey, Objects.requireNonNullElse(fallback, ""));
|
||||||
|
}
|
||||||
|
|
||||||
private static String keyOf(OutputCodecCatalog codec, String fieldKey) {
|
private static String keyOf(OutputCodecCatalog codec, String fieldKey) {
|
||||||
return codec.name() + ":" + fieldKey;
|
return codec.name() + ":" + fieldKey;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -105,7 +105,8 @@ public final class AssetDetailsContractControl extends VBox implements StudioCon
|
|||||||
createPreloadEditor(draft, editing)),
|
createPreloadEditor(draft, editing)),
|
||||||
AssetDetailsUiSupport.createKeyValueRow(
|
AssetDetailsUiSupport.createKeyValueRow(
|
||||||
Container.i18n().text(I18n.ASSETS_LABEL_BANK),
|
Container.i18n().text(I18n.ASSETS_LABEL_BANK),
|
||||||
draft.bank()));
|
draft.bank()),
|
||||||
|
createMetadataSection(details, draft, editing));
|
||||||
|
|
||||||
final VBox codecColumn = new VBox(10);
|
final VBox codecColumn = new VBox(10);
|
||||||
codecColumn.getStyleClass().addAll("assets-details-contract-column", "assets-details-contract-codec-column");
|
codecColumn.getStyleClass().addAll("assets-details-contract-column", "assets-details-contract-codec-column");
|
||||||
@ -220,6 +221,110 @@ public final class AssetDetailsContractControl extends VBox implements StudioCon
|
|||||||
return createCodecMetadataPane(title, content);
|
return createCodecMetadataPane(title, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Node createMetadataSection(
|
||||||
|
AssetWorkspaceAssetDetails details,
|
||||||
|
AssetContractDraft draft,
|
||||||
|
boolean editing) {
|
||||||
|
final VBox subsection = new VBox(8);
|
||||||
|
subsection.getStyleClass().add("assets-details-contract-metadata");
|
||||||
|
final Label title = new Label(Container.i18n().text(I18n.ASSETS_SUBSECTION_METADATA));
|
||||||
|
title.getStyleClass().add("assets-details-subsection-title");
|
||||||
|
final VBox content = new VBox(8);
|
||||||
|
content.getStyleClass().add("assets-details-contract-metadata-content");
|
||||||
|
|
||||||
|
if (details.metadataFields().isEmpty()) {
|
||||||
|
content.getChildren().add(AssetDetailsUiSupport.createSectionMessage(
|
||||||
|
Container.i18n().text(I18n.ASSETS_DETAILS_METADATA_EMPTY)));
|
||||||
|
return createCodecMetadataPane(title, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PackerCodecConfigurationFieldDTO field : details.metadataFields()) {
|
||||||
|
content.getChildren().add(createMetadataFieldRow(field, draft, editing));
|
||||||
|
}
|
||||||
|
return createCodecMetadataPane(title, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node createMetadataFieldRow(
|
||||||
|
PackerCodecConfigurationFieldDTO field,
|
||||||
|
AssetContractDraft draft,
|
||||||
|
boolean editing) {
|
||||||
|
final Node valueNode = switch (field.fieldType()) {
|
||||||
|
case BOOLEAN -> createMetadataBooleanField(field, draft, editing);
|
||||||
|
case ENUM -> createMetadataEnumField(field, draft, editing);
|
||||||
|
case INTEGER, TEXT -> createMetadataTextField(field, draft, editing);
|
||||||
|
};
|
||||||
|
return AssetDetailsUiSupport.createKeyValueRow(field.label(), valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node createMetadataBooleanField(
|
||||||
|
PackerCodecConfigurationFieldDTO field,
|
||||||
|
AssetContractDraft draft,
|
||||||
|
boolean editing) {
|
||||||
|
final CheckBox checkBox = new CheckBox();
|
||||||
|
checkBox.getStyleClass().add("assets-details-readonly-check");
|
||||||
|
checkBox.setSelected(Boolean.parseBoolean(currentMetadataValue(field, draft)));
|
||||||
|
if (editing) {
|
||||||
|
checkBox.selectedProperty().addListener((ignored, oldValue, newValue) -> {
|
||||||
|
if (!Objects.equals(oldValue, newValue)) {
|
||||||
|
formSession.updateDraft(current -> current.withMetadataFieldValue(
|
||||||
|
field.key(),
|
||||||
|
Boolean.toString(newValue)));
|
||||||
|
actionBar.updateState(formSession.mode(), formSession.isDirty());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
configureReadOnlyControl(checkBox);
|
||||||
|
}
|
||||||
|
return checkBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node createMetadataEnumField(
|
||||||
|
PackerCodecConfigurationFieldDTO field,
|
||||||
|
AssetContractDraft draft,
|
||||||
|
boolean editing) {
|
||||||
|
final ComboBox<String> comboBox = new ComboBox<>(FXCollections.observableArrayList(field.options()));
|
||||||
|
comboBox.getStyleClass().add("assets-details-combo");
|
||||||
|
comboBox.setMaxWidth(Double.MAX_VALUE);
|
||||||
|
comboBox.getSelectionModel().select(currentMetadataValue(field, draft));
|
||||||
|
if (editing) {
|
||||||
|
comboBox.valueProperty().addListener((ignored, oldValue, newValue) -> {
|
||||||
|
if (newValue != null && !Objects.equals(oldValue, newValue)) {
|
||||||
|
formSession.updateDraft(current -> current.withMetadataFieldValue(
|
||||||
|
field.key(),
|
||||||
|
newValue));
|
||||||
|
actionBar.updateState(formSession.mode(), formSession.isDirty());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
configureReadOnlyControl(comboBox);
|
||||||
|
}
|
||||||
|
return comboBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node createMetadataTextField(
|
||||||
|
PackerCodecConfigurationFieldDTO field,
|
||||||
|
AssetContractDraft draft,
|
||||||
|
boolean editing) {
|
||||||
|
final TextField textField = new TextField(currentMetadataValue(field, draft));
|
||||||
|
textField.getStyleClass().add("assets-workspace-search");
|
||||||
|
textField.setMaxWidth(Double.MAX_VALUE);
|
||||||
|
HBox.setHgrow(textField, Priority.ALWAYS);
|
||||||
|
if (editing) {
|
||||||
|
textField.textProperty().addListener((ignored, oldValue, newValue) -> {
|
||||||
|
if (!Objects.equals(oldValue, newValue)) {
|
||||||
|
formSession.updateDraft(current -> current.withMetadataFieldValue(
|
||||||
|
field.key(),
|
||||||
|
Objects.requireNonNullElse(newValue, "")));
|
||||||
|
actionBar.updateState(formSession.mode(), formSession.isDirty());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
textField.setEditable(false);
|
||||||
|
configureReadOnlyControl(textField);
|
||||||
|
}
|
||||||
|
return textField;
|
||||||
|
}
|
||||||
|
|
||||||
private Node createCodecMetadataPane(Label title, VBox content) {
|
private Node createCodecMetadataPane(Label title, VBox content) {
|
||||||
final ScrollPane scrollPane = new ScrollPane(content);
|
final ScrollPane scrollPane = new ScrollPane(content);
|
||||||
scrollPane.setFitToWidth(true);
|
scrollPane.setFitToWidth(true);
|
||||||
@ -320,6 +425,10 @@ public final class AssetDetailsContractControl extends VBox implements StudioCon
|
|||||||
return draft.codecFieldValue(draft.selectedCodec(), field.key(), field.value());
|
return draft.codecFieldValue(draft.selectedCodec(), field.key(), field.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String currentMetadataValue(PackerCodecConfigurationFieldDTO field, AssetContractDraft draft) {
|
||||||
|
return draft.metadataFieldValue(field.key(), field.value());
|
||||||
|
}
|
||||||
|
|
||||||
private void configureReadOnlyControl(javafx.scene.control.Control control) {
|
private void configureReadOnlyControl(javafx.scene.control.Control control) {
|
||||||
control.setMouseTransparent(true);
|
control.setMouseTransparent(true);
|
||||||
control.setFocusTraversable(false);
|
control.setFocusTraversable(false);
|
||||||
@ -344,7 +453,8 @@ public final class AssetDetailsContractControl extends VBox implements StudioCon
|
|||||||
draft.assetReference(),
|
draft.assetReference(),
|
||||||
draft.preload(),
|
draft.preload(),
|
||||||
draft.selectedCodec(),
|
draft.selectedCodec(),
|
||||||
draft.codecFieldValues());
|
draft.codecFieldValues(),
|
||||||
|
draft.metadataFieldValues());
|
||||||
try {
|
try {
|
||||||
final var response = Container.packer().workspaceService().updateAssetContract(request);
|
final var response = Container.packer().workspaceService().updateAssetContract(request);
|
||||||
if (response.success()) {
|
if (response.success()) {
|
||||||
|
|||||||
@ -16,6 +16,7 @@ public record AssetWorkspaceAssetDetails(
|
|||||||
OutputCodecCatalog outputCodec,
|
OutputCodecCatalog outputCodec,
|
||||||
List<OutputCodecCatalog> availableOutputCodecs,
|
List<OutputCodecCatalog> availableOutputCodecs,
|
||||||
Map<OutputCodecCatalog, List<PackerCodecConfigurationFieldDTO>> codecConfigurationFieldsByCodec,
|
Map<OutputCodecCatalog, List<PackerCodecConfigurationFieldDTO>> codecConfigurationFieldsByCodec,
|
||||||
|
List<PackerCodecConfigurationFieldDTO> metadataFields,
|
||||||
Map<String, List<Path>> inputsByRole) {
|
Map<String, List<Path>> inputsByRole) {
|
||||||
|
|
||||||
public AssetWorkspaceAssetDetails {
|
public AssetWorkspaceAssetDetails {
|
||||||
@ -25,6 +26,7 @@ public record AssetWorkspaceAssetDetails(
|
|||||||
outputCodec = Objects.requireNonNullElse(outputCodec, OutputCodecCatalog.UNKNOWN);
|
outputCodec = Objects.requireNonNullElse(outputCodec, OutputCodecCatalog.UNKNOWN);
|
||||||
availableOutputCodecs = List.copyOf(Objects.requireNonNull(availableOutputCodecs, "availableOutputCodecs"));
|
availableOutputCodecs = List.copyOf(Objects.requireNonNull(availableOutputCodecs, "availableOutputCodecs"));
|
||||||
codecConfigurationFieldsByCodec = Map.copyOf(Objects.requireNonNull(codecConfigurationFieldsByCodec, "codecConfigurationFieldsByCodec"));
|
codecConfigurationFieldsByCodec = Map.copyOf(Objects.requireNonNull(codecConfigurationFieldsByCodec, "codecConfigurationFieldsByCodec"));
|
||||||
|
metadataFields = List.copyOf(Objects.requireNonNull(metadataFields, "metadataFields"));
|
||||||
inputsByRole = Map.copyOf(Objects.requireNonNull(inputsByRole, "inputsByRole"));
|
inputsByRole = Map.copyOf(Objects.requireNonNull(inputsByRole, "inputsByRole"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -87,6 +87,7 @@ assets.badge.diagnostics=Diagnostics
|
|||||||
assets.section.summary=Summary
|
assets.section.summary=Summary
|
||||||
assets.section.runtimeContract=Runtime Contract
|
assets.section.runtimeContract=Runtime Contract
|
||||||
assets.subsection.codecConfiguration=Codec Configuration
|
assets.subsection.codecConfiguration=Codec Configuration
|
||||||
|
assets.subsection.metadata=Metadata
|
||||||
assets.section.inputsPreview=Inputs / Preview
|
assets.section.inputsPreview=Inputs / Preview
|
||||||
assets.section.diagnostics=Diagnostics
|
assets.section.diagnostics=Diagnostics
|
||||||
assets.section.actions=Actions
|
assets.section.actions=Actions
|
||||||
@ -168,6 +169,7 @@ assets.details.empty=Create or add assets to this project to start using the Ass
|
|||||||
assets.details.ready=Selected asset: {0}\nState: {1}\nRoot: {2}
|
assets.details.ready=Selected asset: {0}\nState: {1}\nRoot: {2}
|
||||||
assets.details.noSelection=Select an asset from the navigator once assets are available.
|
assets.details.noSelection=Select an asset from the navigator once assets are available.
|
||||||
assets.details.codecConfiguration.empty=This codec does not expose configuration fields yet.
|
assets.details.codecConfiguration.empty=This codec does not expose configuration fields yet.
|
||||||
|
assets.details.metadata.empty=This asset does not expose metadata fields yet.
|
||||||
assets.addWizard.title=Add Asset
|
assets.addWizard.title=Add Asset
|
||||||
assets.addWizard.description=Create a registered asset root through a guided flow.
|
assets.addWizard.description=Create a registered asset root through a guided flow.
|
||||||
assets.addWizard.step.root.title=Choose Asset Root
|
assets.addWizard.step.root.title=Choose Asset Root
|
||||||
|
|||||||
@ -748,6 +748,56 @@
|
|||||||
"message" : "Asset scan started",
|
"message" : "Asset scan started",
|
||||||
"severity" : "INFO",
|
"severity" : "INFO",
|
||||||
"sticky" : false
|
"sticky" : false
|
||||||
|
}, {
|
||||||
|
"source" : "Assets",
|
||||||
|
"message" : "8 assets loaded",
|
||||||
|
"severity" : "SUCCESS",
|
||||||
|
"sticky" : false
|
||||||
|
}, {
|
||||||
|
"source" : "Assets",
|
||||||
|
"message" : "Discovered asset: test",
|
||||||
|
"severity" : "INFO",
|
||||||
|
"sticky" : false
|
||||||
|
}, {
|
||||||
|
"source" : "Assets",
|
||||||
|
"message" : "Discovered asset: bla",
|
||||||
|
"severity" : "INFO",
|
||||||
|
"sticky" : false
|
||||||
|
}, {
|
||||||
|
"source" : "Assets",
|
||||||
|
"message" : "Discovered asset: one-more-atlas",
|
||||||
|
"severity" : "INFO",
|
||||||
|
"sticky" : false
|
||||||
|
}, {
|
||||||
|
"source" : "Assets",
|
||||||
|
"message" : "Discovered asset: ui_atlas",
|
||||||
|
"severity" : "INFO",
|
||||||
|
"sticky" : false
|
||||||
|
}, {
|
||||||
|
"source" : "Assets",
|
||||||
|
"message" : "Discovered asset: one-more-atlas",
|
||||||
|
"severity" : "INFO",
|
||||||
|
"sticky" : false
|
||||||
|
}, {
|
||||||
|
"source" : "Assets",
|
||||||
|
"message" : "Discovered asset: bbb2",
|
||||||
|
"severity" : "INFO",
|
||||||
|
"sticky" : false
|
||||||
|
}, {
|
||||||
|
"source" : "Assets",
|
||||||
|
"message" : "Discovered asset: ui_atlas",
|
||||||
|
"severity" : "INFO",
|
||||||
|
"sticky" : false
|
||||||
|
}, {
|
||||||
|
"source" : "Assets",
|
||||||
|
"message" : "Discovered asset: Bigode",
|
||||||
|
"severity" : "INFO",
|
||||||
|
"sticky" : false
|
||||||
|
}, {
|
||||||
|
"source" : "Assets",
|
||||||
|
"message" : "Asset scan started",
|
||||||
|
"severity" : "INFO",
|
||||||
|
"sticky" : false
|
||||||
}, {
|
}, {
|
||||||
"source" : "Assets",
|
"source" : "Assets",
|
||||||
"message" : "Asset moved: bbb2 -> recovered/bbb2",
|
"message" : "Asset moved: bbb2 -> recovered/bbb2",
|
||||||
@ -2448,54 +2498,4 @@
|
|||||||
"message" : "Discovered asset: bla",
|
"message" : "Discovered asset: bla",
|
||||||
"severity" : "INFO",
|
"severity" : "INFO",
|
||||||
"sticky" : false
|
"sticky" : false
|
||||||
}, {
|
|
||||||
"source" : "Assets",
|
|
||||||
"message" : "Discovered asset: one-more-atlas",
|
|
||||||
"severity" : "INFO",
|
|
||||||
"sticky" : false
|
|
||||||
}, {
|
|
||||||
"source" : "Assets",
|
|
||||||
"message" : "Discovered asset: ui_atlas",
|
|
||||||
"severity" : "INFO",
|
|
||||||
"sticky" : false
|
|
||||||
}, {
|
|
||||||
"source" : "Assets",
|
|
||||||
"message" : "Discovered asset: Bigode",
|
|
||||||
"severity" : "INFO",
|
|
||||||
"sticky" : false
|
|
||||||
}, {
|
|
||||||
"source" : "Assets",
|
|
||||||
"message" : "Asset scan started",
|
|
||||||
"severity" : "INFO",
|
|
||||||
"sticky" : false
|
|
||||||
}, {
|
|
||||||
"source" : "Assets",
|
|
||||||
"message" : "7 assets loaded",
|
|
||||||
"severity" : "SUCCESS",
|
|
||||||
"sticky" : false
|
|
||||||
}, {
|
|
||||||
"source" : "Assets",
|
|
||||||
"message" : "Discovered asset: test",
|
|
||||||
"severity" : "INFO",
|
|
||||||
"sticky" : false
|
|
||||||
}, {
|
|
||||||
"source" : "Assets",
|
|
||||||
"message" : "Discovered asset: one-more-atlas",
|
|
||||||
"severity" : "INFO",
|
|
||||||
"sticky" : false
|
|
||||||
}, {
|
|
||||||
"source" : "Assets",
|
|
||||||
"message" : "Discovered asset: ui_atlas",
|
|
||||||
"severity" : "INFO",
|
|
||||||
"sticky" : false
|
|
||||||
}, {
|
|
||||||
"source" : "Assets",
|
|
||||||
"message" : "Discovered asset: bla",
|
|
||||||
"severity" : "INFO",
|
|
||||||
"sticky" : false
|
|
||||||
}, {
|
|
||||||
"source" : "Assets",
|
|
||||||
"message" : "Discovered asset: one-more-atlas",
|
|
||||||
"severity" : "INFO",
|
|
||||||
"sticky" : false
|
|
||||||
} ]
|
} ]
|
||||||
Loading…
x
Reference in New Issue
Block a user