diff --git a/src/main/java/be/seeseepuff/pcinv/controllers/WebController.java b/src/main/java/be/seeseepuff/pcinv/controllers/WebController.java index 2ae1425..3650d26 100644 --- a/src/main/java/be/seeseepuff/pcinv/controllers/WebController.java +++ b/src/main/java/be/seeseepuff/pcinv/controllers/WebController.java @@ -2,6 +2,7 @@ package be.seeseepuff.pcinv.controllers; import be.seeseepuff.pcinv.models.WorkLogEntry; import be.seeseepuff.pcinv.services.AssetService; +import be.seeseepuff.pcinv.services.BuildService; import lombok.RequiredArgsConstructor; import org.springframework.data.repository.query.Param; import org.springframework.http.MediaType; @@ -42,6 +43,7 @@ public class WebController { private static final String INPUT_LIST = "inputLists"; /// The name of the model attribute that holds the current work log entries. private static final String WORKLOG = "worklog"; + private static final String BUILDS = "builds"; /// The name of the input field for the current size of the work log. private static final String WORKLOG_SIZE = "worklog_size"; @@ -49,6 +51,7 @@ public class WebController { private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("dd MMM yyyy 'at' HH:mm"); private final AssetService assetService; + private final BuildService buildService; /** * Handles the root URL and returns the index page with asset descriptors and asset count. @@ -202,6 +205,7 @@ public class WebController { model.addAttribute(DESCRIPTORS, assetService.getAssetDescriptorTree(type)); model.addAttribute(DESCRIPTOR, assetService.getAssetDescriptor(type)); model.addAttribute(INPUT_LIST, assetService.getInputList(type)); + model.addAttribute(BUILDS, buildService.getAllBuilds()); return "create_asset"; } diff --git a/src/main/java/be/seeseepuff/pcinv/meta/AssetProperty.java b/src/main/java/be/seeseepuff/pcinv/meta/AssetProperty.java index 1415eb5..b137ec9 100644 --- a/src/main/java/be/seeseepuff/pcinv/meta/AssetProperty.java +++ b/src/main/java/be/seeseepuff/pcinv/meta/AssetProperty.java @@ -1,12 +1,8 @@ package be.seeseepuff.pcinv.meta; -import be.seeseepuff.pcinv.models.Asset; -import be.seeseepuff.pcinv.models.AssetCondition; -import be.seeseepuff.pcinv.models.GenericAsset; -import be.seeseepuff.pcinv.models.ReadWrite; +import be.seeseepuff.pcinv.models.*; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; -import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.Singular; @@ -28,7 +24,7 @@ public class AssetProperty { /// The name of the property as it should be displayed, e.g., "Brand", "Model", etc. private final String displayName; /// The type of the property, which can be a string or an integer. - private final Type type; + private final PropertyType type; /// Whether the property is required for the asset. private final boolean required; /// A set of options for the property, used for enum types. @@ -49,31 +45,6 @@ public class AssetProperty { /// A description of the property, if any. private final String description; - /** - * Enum representing the possible types of asset properties. - */ - @AllArgsConstructor - public enum Type { - STRING(false), - INTEGER(false), - BOOLEAN(false), - CAPACITY(false), - CONDITION(true), - READWRITE(true), - ; - /// Set to `true` if the type is an enum, `false` otherwise. - public final boolean isEnum; - - /** - * Returns the name of the type, or "enum" if it is an enum type. - * - * @return The name of the type or "enum" if it is an enum. - */ - public String nameOrEnum() { - return isEnum ? "enum" : name(); - } - } - /** * Loads an AssetProperty from a given field. * @@ -131,7 +102,7 @@ public class AssetProperty { builder.option(option); } } - if (type == Type.CAPACITY) { + if (type == PropertyType.CAPACITY) { var capacityAnnotation = property.getAnnotation(Capacity.class); builder.capacityAsSI(capacityAnnotation.si()); builder.capacityAsIEC(capacityAnnotation.iec()); @@ -146,19 +117,21 @@ public class AssetProperty { * @return The type of the property. * @throws IllegalArgumentException if the property type is unsupported. */ - private static Type determineType(Field property) { + private static PropertyType determineType(Field property) { if (property.getType() == String.class) { - return Type.STRING; + return PropertyType.STRING; } else if (property.isAnnotationPresent(Capacity.class)) { - return Type.CAPACITY; + return PropertyType.CAPACITY; } else if (property.getType() == Integer.class || property.getType() == int.class || property.getType() == Long.class || property.getType() == long.class) { - return Type.INTEGER; + return PropertyType.INTEGER; } else if (property.getType() == Boolean.class || property.getType() == boolean.class) { - return Type.BOOLEAN; + return PropertyType.BOOLEAN; } else if (property.getType() == AssetCondition.class) { - return Type.CONDITION; + return PropertyType.CONDITION; } else if (property.getType() == ReadWrite.class) { - return Type.READWRITE; + return PropertyType.READWRITE; + } else if (property.getType() == Build.class) { + return PropertyType.BUILD; } else { throw new IllegalArgumentException("Unsupported property type: " + property.getType()); } @@ -204,11 +177,11 @@ public class AssetProperty { var value = getValue(asset); if (value == null) { return "?"; - } else if (type == Type.BOOLEAN) { + } else if (type == PropertyType.BOOLEAN) { return (boolean) value ? "Yes" : "No"; - } else if (type == Type.INTEGER || type == Type.STRING) { + } else if (type == PropertyType.INTEGER || type == PropertyType.STRING) { return value.toString(); - } else if (type == Type.CAPACITY) { + } else if (type == PropertyType.CAPACITY) { return convertCapacity((Long) value).toString(); } else if (type.isEnum) { if (value instanceof AssetEnum assetEnum) { @@ -224,7 +197,7 @@ public class AssetProperty { if (value == null) { return null; } - if (type != Type.CAPACITY) { + if (type != PropertyType.CAPACITY) { throw new IllegalStateException("Property '" + name + "' is not a capacity type."); } return CapacityInfo.of(value, capacityAsIEC, capacityAsSI); diff --git a/src/main/java/be/seeseepuff/pcinv/meta/PropertyType.java b/src/main/java/be/seeseepuff/pcinv/meta/PropertyType.java new file mode 100644 index 0000000..697c491 --- /dev/null +++ b/src/main/java/be/seeseepuff/pcinv/meta/PropertyType.java @@ -0,0 +1,31 @@ +package be.seeseepuff.pcinv.meta; + +import lombok.AllArgsConstructor; + +/** + * Enum representing the possible types of asset properties. + */ +@AllArgsConstructor +public enum PropertyType +{ + STRING(false), + INTEGER(false), + BOOLEAN(false), + CAPACITY(false), + CONDITION(true), + READWRITE(true), + BUILD(false), + ; + /// Set to `true` if the type is an enum, `false` otherwise. + public final boolean isEnum; + + /** + * Returns the name of the type, or "enum" if it is an enum type. + * + * @return The name of the type or "enum" if it is an enum. + */ + public String nameOrEnum() + { + return isEnum ? "enum" : name(); + } +} diff --git a/src/main/java/be/seeseepuff/pcinv/models/Build.java b/src/main/java/be/seeseepuff/pcinv/models/Build.java new file mode 100644 index 0000000..5a6d74f --- /dev/null +++ b/src/main/java/be/seeseepuff/pcinv/models/Build.java @@ -0,0 +1,30 @@ +package be.seeseepuff.pcinv.models; + +import jakarta.persistence.*; +import lombok.*; + +import java.util.List; + +@Getter +@Setter +@Builder +@Entity +@NoArgsConstructor +@AllArgsConstructor +@Table( + name = "builds", + uniqueConstraints = @UniqueConstraint(columnNames = "name") +) +public class Build +{ + @Id + @GeneratedValue + private long id; + + private String name; + + private String description; + + @OneToMany(cascade = CascadeType.ALL) + private List parts; +} diff --git a/src/main/java/be/seeseepuff/pcinv/models/GenericAsset.java b/src/main/java/be/seeseepuff/pcinv/models/GenericAsset.java index 2cf7c2a..9b517f2 100644 --- a/src/main/java/be/seeseepuff/pcinv/models/GenericAsset.java +++ b/src/main/java/be/seeseepuff/pcinv/models/GenericAsset.java @@ -73,4 +73,9 @@ public class GenericAsset @OneToMany(mappedBy = "asset", cascade = CascadeType.ALL, orphanRemoval = true) private List workLog; + + @ManyToOne + @Property("Part of build") + @Description("Select which build this asset is placed in.") + private Build build; } diff --git a/src/main/java/be/seeseepuff/pcinv/repositories/BuildRepository.java b/src/main/java/be/seeseepuff/pcinv/repositories/BuildRepository.java new file mode 100644 index 0000000..cb895c3 --- /dev/null +++ b/src/main/java/be/seeseepuff/pcinv/repositories/BuildRepository.java @@ -0,0 +1,10 @@ +package be.seeseepuff.pcinv.repositories; + +import be.seeseepuff.pcinv.models.Build; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface BuildRepository extends JpaRepository +{ +} diff --git a/src/main/java/be/seeseepuff/pcinv/services/AssetService.java b/src/main/java/be/seeseepuff/pcinv/services/AssetService.java index bf07927..b592a4a 100644 --- a/src/main/java/be/seeseepuff/pcinv/services/AssetService.java +++ b/src/main/java/be/seeseepuff/pcinv/services/AssetService.java @@ -1,13 +1,12 @@ package be.seeseepuff.pcinv.services; -import be.seeseepuff.pcinv.meta.AssetDescriptor; -import be.seeseepuff.pcinv.meta.AssetDescriptors; -import be.seeseepuff.pcinv.meta.AssetInfo; -import be.seeseepuff.pcinv.meta.AssetProperty; +import be.seeseepuff.pcinv.meta.*; import be.seeseepuff.pcinv.models.Asset; +import be.seeseepuff.pcinv.models.Build; import be.seeseepuff.pcinv.models.GenericAsset; import be.seeseepuff.pcinv.models.WorkLogEntry; import be.seeseepuff.pcinv.repositories.AssetRepository; +import be.seeseepuff.pcinv.repositories.BuildRepository; import be.seeseepuff.pcinv.repositories.GenericAssetRepository; import be.seeseepuff.pcinv.repositories.WorkLogRepository; import jakarta.persistence.EntityManager; @@ -225,7 +224,7 @@ public class AssetService { * @return The parsed value as an Object. */ private Object parseValue(AssetDescriptor descriptor, AssetProperty property, Map values) { - if (property.getType() == AssetProperty.Type.CAPACITY) { + if (property.getType() == PropertyType.CAPACITY) { var value = values.get(descriptor.asString(property) + "-value"); var unit = values.get(descriptor.asString(property) + "-unit"); if (value == null || value.isBlank() || unit == null || unit.isBlank()) { @@ -244,11 +243,11 @@ public class AssetService { return null; } - if (property.getType() == AssetProperty.Type.INTEGER) { + if (property.getType() == PropertyType.INTEGER) { return Integer.parseInt(stringValue); - } else if (property.getType() == AssetProperty.Type.STRING) { + } else if (property.getType() == PropertyType.STRING) { return stringValue; - } else if (property.getType() == AssetProperty.Type.BOOLEAN) { + } else if (property.getType() == PropertyType.BOOLEAN) { return switch (stringValue.toLowerCase()) { case "true" -> true; case "false" -> false; diff --git a/src/main/java/be/seeseepuff/pcinv/services/BuildService.java b/src/main/java/be/seeseepuff/pcinv/services/BuildService.java new file mode 100644 index 0000000..bef09c6 --- /dev/null +++ b/src/main/java/be/seeseepuff/pcinv/services/BuildService.java @@ -0,0 +1,45 @@ +package be.seeseepuff.pcinv.services; + +import be.seeseepuff.pcinv.models.Build; +import be.seeseepuff.pcinv.repositories.BuildRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +/** + * A service that manages computer builds. + */ +@Service +@RequiredArgsConstructor +public class BuildService +{ + private final BuildRepository buildRepository; + public static final Build EMPTY = Build.builder() + .id(0) + .name("(None)") + .description("A meta build used to indicate that the part is not being used by anything") + .build(); + + /** + * Gets a list of all computer builds, including meta builds. + * + * @return A list of all builds. + */ + public List getAllBuilds() { + var build = new ArrayList(); + build.add(EMPTY); + build.addAll(getAllRealBuilds()); + return build; + } + + /** + * Gets a list of all computer builds, excluding meta builds. + * + * @return A list of all builds. + */ + public List getAllRealBuilds() { + return buildRepository.findAll(); + } +} diff --git a/src/main/resources/templates/create_asset.html b/src/main/resources/templates/create_asset.html index 9997df4..b5b4ba1 100644 --- a/src/main/resources/templates/create_asset.html +++ b/src/main/resources/templates/create_asset.html @@ -8,6 +8,7 @@ + + - + @@ -27,9 +29,11 @@ + + + + + + Bad input type for diff --git a/src/main/resources/templates/fragments.html b/src/main/resources/templates/fragments.html index edde0fb..ad34ce8 100644 --- a/src/main/resources/templates/fragments.html +++ b/src/main/resources/templates/fragments.html @@ -10,6 +10,7 @@ Home Browse Create + Builds