Files
homebox/backend/internal/data/ent/itemtemplate/itemtemplate.go
Logan Miller cc66330a74 feat: Add item templates feature (#435) (#1099)
* feat: Add item templates feature (#435)

   Add ability to create and manage item templates for quick item creation.
   Templates store default values and custom fields that can be applied
   when creating new items.

   Backend changes:
   - New ItemTemplate and TemplateField Ent schemas
   - Template CRUD API endpoints
   - Create item from template endpoint

   Frontend changes:
   - Templates management page with create/edit/delete
   - Template selector in item creation modal
   - 'Use as Template' action on item detail page
   - Templates link in navigation menu

* refactor: Improve template item creation with a single query

- Add `CreateFromTemplate` method to ItemsRepository that creates items with all template data (including custom fields) in a single atomic transaction, replacing the previous two-phase create-then-update pattern
- Fix `GetOne` to require group ID parameter so templates can only be accessed by users in the owning group (security fix)
- Simplify `HandleItemTemplatesCreateItem` handler using the new transactional method

* Refactor item template types and formatting

Updated type annotations in CreateModal.vue to use specific ItemTemplate types instead of 'any'. Improved code formatting for template fields and manufacturer display. Also refactored warranty field logic in item details page for better readability. This resolves the linter issues as well that the bot in github keeps nagging at.

* Add 'id' property to template fields

Introduces an 'id' property to each field object in CreateModal.vue and item details page to support unique identification of fields. This change prepares the codebase for future enhancements that may require field-level identification.

* Removed redundant SQL migrations.

Removed redundant SQL migrations per @tankerkiller125's findings.

* Updates to PR #1099.

Regarding pull #1099. Fixed an issue causing some conflict with GUIDs and old rows in the migration files.

* Add new fields and location edge to ItemTemplate

Addresses recommendations from @tonyaellie.

* Relocated add template button
* Added more default fields to the template
* Added translation of all strings (think so?)
* Make oval buttons round
* Added duplicate button to the template (this required a rewrite of the migration files, I made sure only 1 exists per DB type)
* Added a Save as template button to a item detail view (this creates a template with all the current data of that item)
* Changed all occurrences of space to gap and flex where applicable.
* Made template selection persistent after item created.
* Collapsible template info on creation view.

* Updates to translation and fix for labels/locations

I also added a test in here because I keep missing small function tests. That should prevent that from happening again.

* Linted

* Bring up to date with main, fix some lint/type check issues

* In theory fix playwright tests

* Fix defaults being unable to be nullable/empty (and thus limiting flexibility)

* Last few fixes I think

* Forgot to fix the golang tests

---------

Co-authored-by: Matthew Kilgore <matthew@kilgore.dev>
2025-12-06 16:21:43 -05:00

302 lines
13 KiB
Go
Generated

// Code generated by ent, DO NOT EDIT.
package itemtemplate
import (
"time"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"github.com/google/uuid"
)
const (
// Label holds the string label denoting the itemtemplate type in the database.
Label = "item_template"
// FieldID holds the string denoting the id field in the database.
FieldID = "id"
// FieldCreatedAt holds the string denoting the created_at field in the database.
FieldCreatedAt = "created_at"
// FieldUpdatedAt holds the string denoting the updated_at field in the database.
FieldUpdatedAt = "updated_at"
// FieldName holds the string denoting the name field in the database.
FieldName = "name"
// FieldDescription holds the string denoting the description field in the database.
FieldDescription = "description"
// FieldNotes holds the string denoting the notes field in the database.
FieldNotes = "notes"
// FieldDefaultQuantity holds the string denoting the default_quantity field in the database.
FieldDefaultQuantity = "default_quantity"
// FieldDefaultInsured holds the string denoting the default_insured field in the database.
FieldDefaultInsured = "default_insured"
// FieldDefaultName holds the string denoting the default_name field in the database.
FieldDefaultName = "default_name"
// FieldDefaultDescription holds the string denoting the default_description field in the database.
FieldDefaultDescription = "default_description"
// FieldDefaultManufacturer holds the string denoting the default_manufacturer field in the database.
FieldDefaultManufacturer = "default_manufacturer"
// FieldDefaultModelNumber holds the string denoting the default_model_number field in the database.
FieldDefaultModelNumber = "default_model_number"
// FieldDefaultLifetimeWarranty holds the string denoting the default_lifetime_warranty field in the database.
FieldDefaultLifetimeWarranty = "default_lifetime_warranty"
// FieldDefaultWarrantyDetails holds the string denoting the default_warranty_details field in the database.
FieldDefaultWarrantyDetails = "default_warranty_details"
// FieldIncludeWarrantyFields holds the string denoting the include_warranty_fields field in the database.
FieldIncludeWarrantyFields = "include_warranty_fields"
// FieldIncludePurchaseFields holds the string denoting the include_purchase_fields field in the database.
FieldIncludePurchaseFields = "include_purchase_fields"
// FieldIncludeSoldFields holds the string denoting the include_sold_fields field in the database.
FieldIncludeSoldFields = "include_sold_fields"
// FieldDefaultLabelIds holds the string denoting the default_label_ids field in the database.
FieldDefaultLabelIds = "default_label_ids"
// EdgeGroup holds the string denoting the group edge name in mutations.
EdgeGroup = "group"
// EdgeFields holds the string denoting the fields edge name in mutations.
EdgeFields = "fields"
// EdgeLocation holds the string denoting the location edge name in mutations.
EdgeLocation = "location"
// Table holds the table name of the itemtemplate in the database.
Table = "item_templates"
// GroupTable is the table that holds the group relation/edge.
GroupTable = "item_templates"
// GroupInverseTable is the table name for the Group entity.
// It exists in this package in order to avoid circular dependency with the "group" package.
GroupInverseTable = "groups"
// GroupColumn is the table column denoting the group relation/edge.
GroupColumn = "group_item_templates"
// FieldsTable is the table that holds the fields relation/edge.
FieldsTable = "template_fields"
// FieldsInverseTable is the table name for the TemplateField entity.
// It exists in this package in order to avoid circular dependency with the "templatefield" package.
FieldsInverseTable = "template_fields"
// FieldsColumn is the table column denoting the fields relation/edge.
FieldsColumn = "item_template_fields"
// LocationTable is the table that holds the location relation/edge.
LocationTable = "item_templates"
// LocationInverseTable is the table name for the Location entity.
// It exists in this package in order to avoid circular dependency with the "location" package.
LocationInverseTable = "locations"
// LocationColumn is the table column denoting the location relation/edge.
LocationColumn = "item_template_location"
)
// Columns holds all SQL columns for itemtemplate fields.
var Columns = []string{
FieldID,
FieldCreatedAt,
FieldUpdatedAt,
FieldName,
FieldDescription,
FieldNotes,
FieldDefaultQuantity,
FieldDefaultInsured,
FieldDefaultName,
FieldDefaultDescription,
FieldDefaultManufacturer,
FieldDefaultModelNumber,
FieldDefaultLifetimeWarranty,
FieldDefaultWarrantyDetails,
FieldIncludeWarrantyFields,
FieldIncludePurchaseFields,
FieldIncludeSoldFields,
FieldDefaultLabelIds,
}
// ForeignKeys holds the SQL foreign-keys that are owned by the "item_templates"
// table and are not defined as standalone fields in the schema.
var ForeignKeys = []string{
"group_item_templates",
"item_template_location",
}
// ValidColumn reports if the column name is valid (part of the table columns).
func ValidColumn(column string) bool {
for i := range Columns {
if column == Columns[i] {
return true
}
}
for i := range ForeignKeys {
if column == ForeignKeys[i] {
return true
}
}
return false
}
var (
// DefaultCreatedAt holds the default value on creation for the "created_at" field.
DefaultCreatedAt func() time.Time
// DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
DefaultUpdatedAt func() time.Time
// UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field.
UpdateDefaultUpdatedAt func() time.Time
// NameValidator is a validator for the "name" field. It is called by the builders before save.
NameValidator func(string) error
// DescriptionValidator is a validator for the "description" field. It is called by the builders before save.
DescriptionValidator func(string) error
// NotesValidator is a validator for the "notes" field. It is called by the builders before save.
NotesValidator func(string) error
// DefaultDefaultQuantity holds the default value on creation for the "default_quantity" field.
DefaultDefaultQuantity int
// DefaultDefaultInsured holds the default value on creation for the "default_insured" field.
DefaultDefaultInsured bool
// DefaultNameValidator is a validator for the "default_name" field. It is called by the builders before save.
DefaultNameValidator func(string) error
// DefaultDescriptionValidator is a validator for the "default_description" field. It is called by the builders before save.
DefaultDescriptionValidator func(string) error
// DefaultManufacturerValidator is a validator for the "default_manufacturer" field. It is called by the builders before save.
DefaultManufacturerValidator func(string) error
// DefaultModelNumberValidator is a validator for the "default_model_number" field. It is called by the builders before save.
DefaultModelNumberValidator func(string) error
// DefaultDefaultLifetimeWarranty holds the default value on creation for the "default_lifetime_warranty" field.
DefaultDefaultLifetimeWarranty bool
// DefaultWarrantyDetailsValidator is a validator for the "default_warranty_details" field. It is called by the builders before save.
DefaultWarrantyDetailsValidator func(string) error
// DefaultIncludeWarrantyFields holds the default value on creation for the "include_warranty_fields" field.
DefaultIncludeWarrantyFields bool
// DefaultIncludePurchaseFields holds the default value on creation for the "include_purchase_fields" field.
DefaultIncludePurchaseFields bool
// DefaultIncludeSoldFields holds the default value on creation for the "include_sold_fields" field.
DefaultIncludeSoldFields bool
// DefaultID holds the default value on creation for the "id" field.
DefaultID func() uuid.UUID
)
// OrderOption defines the ordering options for the ItemTemplate queries.
type OrderOption func(*sql.Selector)
// ByID orders the results by the id field.
func ByID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldID, opts...).ToFunc()
}
// ByCreatedAt orders the results by the created_at field.
func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
}
// ByUpdatedAt orders the results by the updated_at field.
func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc()
}
// ByName orders the results by the name field.
func ByName(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldName, opts...).ToFunc()
}
// ByDescription orders the results by the description field.
func ByDescription(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDescription, opts...).ToFunc()
}
// ByNotes orders the results by the notes field.
func ByNotes(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldNotes, opts...).ToFunc()
}
// ByDefaultQuantity orders the results by the default_quantity field.
func ByDefaultQuantity(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDefaultQuantity, opts...).ToFunc()
}
// ByDefaultInsured orders the results by the default_insured field.
func ByDefaultInsured(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDefaultInsured, opts...).ToFunc()
}
// ByDefaultName orders the results by the default_name field.
func ByDefaultName(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDefaultName, opts...).ToFunc()
}
// ByDefaultDescription orders the results by the default_description field.
func ByDefaultDescription(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDefaultDescription, opts...).ToFunc()
}
// ByDefaultManufacturer orders the results by the default_manufacturer field.
func ByDefaultManufacturer(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDefaultManufacturer, opts...).ToFunc()
}
// ByDefaultModelNumber orders the results by the default_model_number field.
func ByDefaultModelNumber(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDefaultModelNumber, opts...).ToFunc()
}
// ByDefaultLifetimeWarranty orders the results by the default_lifetime_warranty field.
func ByDefaultLifetimeWarranty(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDefaultLifetimeWarranty, opts...).ToFunc()
}
// ByDefaultWarrantyDetails orders the results by the default_warranty_details field.
func ByDefaultWarrantyDetails(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDefaultWarrantyDetails, opts...).ToFunc()
}
// ByIncludeWarrantyFields orders the results by the include_warranty_fields field.
func ByIncludeWarrantyFields(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldIncludeWarrantyFields, opts...).ToFunc()
}
// ByIncludePurchaseFields orders the results by the include_purchase_fields field.
func ByIncludePurchaseFields(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldIncludePurchaseFields, opts...).ToFunc()
}
// ByIncludeSoldFields orders the results by the include_sold_fields field.
func ByIncludeSoldFields(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldIncludeSoldFields, opts...).ToFunc()
}
// ByGroupField orders the results by group field.
func ByGroupField(field string, opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborTerms(s, newGroupStep(), sql.OrderByField(field, opts...))
}
}
// ByFieldsCount orders the results by fields count.
func ByFieldsCount(opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborsCount(s, newFieldsStep(), opts...)
}
}
// ByFields orders the results by fields terms.
func ByFields(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborTerms(s, newFieldsStep(), append([]sql.OrderTerm{term}, terms...)...)
}
}
// ByLocationField orders the results by location field.
func ByLocationField(field string, opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborTerms(s, newLocationStep(), sql.OrderByField(field, opts...))
}
}
func newGroupStep() *sqlgraph.Step {
return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(GroupInverseTable, FieldID),
sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn),
)
}
func newFieldsStep() *sqlgraph.Step {
return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(FieldsInverseTable, FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, FieldsTable, FieldsColumn),
)
}
func newLocationStep() *sqlgraph.Step {
return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(LocationInverseTable, FieldID),
sqlgraph.Edge(sqlgraph.M2O, false, LocationTable, LocationColumn),
)
}