diff --git a/backend/go.mod b/backend/go.mod index d80ed397..56cbd1a9 100644 --- a/backend/go.mod +++ b/backend/go.mod @@ -30,7 +30,7 @@ require ( github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/stretchr/testify v1.10.0 github.com/swaggo/http-swagger/v2 v2.0.2 - github.com/swaggo/swag v1.16.6 + github.com/swaggo/swag/v2 v2.0.0-rc4 github.com/yeqown/go-qrcode/v2 v2.2.5 github.com/yeqown/go-qrcode/writer/standard v1.3.0 github.com/zeebo/blake3 v0.2.4 @@ -165,7 +165,9 @@ require ( github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/sethvargo/go-retry v0.3.0 // indirect github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect + github.com/sv-tools/openapi v0.2.1 // indirect github.com/swaggo/files/v2 v2.0.2 // indirect + github.com/swaggo/swag v1.8.1 // indirect github.com/tetratelabs/wazero v1.9.0 // indirect github.com/tinylib/msgp v1.3.0 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect @@ -200,6 +202,7 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a // indirect google.golang.org/grpc v1.74.2 // indirect google.golang.org/protobuf v1.36.7 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/libc v1.66.7 // indirect modernc.org/mathutil v1.7.1 // indirect diff --git a/backend/go.sum b/backend/go.sum index eb731dab..3c18f9e9 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -75,6 +75,8 @@ github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs= +github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/ardanlabs/conf/v3 v3.8.0 h1:Mvv2wZJz8tIl705m5BU3ZRCP1V6TKY6qebA8i4sykrY= @@ -317,8 +319,6 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.14.32 h1:JD12Ag3oLy1zQA+BNn74xRgaBbdhbNIDYvQUEuuErjs= github.com/mattn/go-sqlite3 v1.14.32/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY= @@ -341,12 +341,12 @@ github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdh github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/olahol/melody v1.3.0 h1:n7UlKiQnxVrgxKoM0d7usZiN+Z0y2lVENtYLgKtXS6s= github.com/olahol/melody v1.3.0/go.mod h1:GgkTl6Y7yWj/HtfD48Q5vLKPVoZOH+Qqgfa7CvJgJM4= -github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= -github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU= github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts= github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE= +github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U= github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= @@ -385,10 +385,6 @@ github.com/shirou/gopsutil/v4 v4.25.7 h1:bNb2JuqKuAu3tRlPv5piSmBZyMfecwQ+t/ILq+1 github.com/shirou/gopsutil/v4 v4.25.7/go.mod h1:XV/egmwJtd3ZQjBpJVY5kndsiOO4IRqy9TQnmm6VP7U= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -402,12 +398,16 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/sv-tools/openapi v0.2.1 h1:ES1tMQMJFGibWndMagvdoo34T1Vllxr1Nlm5wz6b1aA= +github.com/sv-tools/openapi v0.2.1/go.mod h1:k5VuZamTw1HuiS9p2Wl5YIDWzYnHG6/FgPOSFXLAhGg= github.com/swaggo/files/v2 v2.0.2 h1:Bq4tgS/yxLB/3nwOMcul5oLEUKa877Ykgz3CJMVbQKU= github.com/swaggo/files/v2 v2.0.2/go.mod h1:TVqetIzZsO9OhHX1Am9sRf9LdrFZqoK49N37KON/jr0= github.com/swaggo/http-swagger/v2 v2.0.2 h1:FKCdLsl+sFCx60KFsyM0rDarwiUSZ8DqbfSyIKC9OBg= github.com/swaggo/http-swagger/v2 v2.0.2/go.mod h1:r7/GBkAWIfK6E/OLnE8fXnviHiDeAHmgIyooa4xm3AQ= -github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI= -github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg= +github.com/swaggo/swag v1.8.1 h1:JuARzFX1Z1njbCGz+ZytBR15TFJwF2Q7fu8puJHhQYI= +github.com/swaggo/swag v1.8.1/go.mod h1:ugemnJsPZm/kRwFUnzBlbHRd0JY9zE1M4F+uy2pAaPQ= +github.com/swaggo/swag/v2 v2.0.0-rc4 h1:SZ8cK68gcV6cslwrJMIOqPkJELRwq4gmjvk77MrvHvY= +github.com/swaggo/swag/v2 v2.0.0-rc4/go.mod h1:Ow7Y8gF16BTCDn8YxZbyKn8FkMLRUHekv1kROJZpbvE= github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I= github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM= github.com/tinylib/msgp v1.3.0 h1:ULuf7GPooDaIlbyvgAxBV/FI7ynli6LZ1/nVUNu+0ww= diff --git a/backend/internal/data/migrations/migrations.go b/backend/internal/data/migrations/migrations.go index 838ba5eb..ca43b375 100644 --- a/backend/internal/data/migrations/migrations.go +++ b/backend/internal/data/migrations/migrations.go @@ -30,5 +30,4 @@ func Migrations(dialect string) (embed.FS, error) { return embed.FS{}, fmt.Errorf("unknown sql dialect: %s", dialect) } // This should never get hit, but just in case - return sqliteFiles, nil } diff --git a/backend/internal/data/repo/repo_entities.go b/backend/internal/data/repo/repo_entities.go index 5736352d..f44db33c 100644 --- a/backend/internal/data/repo/repo_entities.go +++ b/backend/internal/data/repo/repo_entities.go @@ -74,6 +74,6 @@ type ( // Edges Attachments []EntityAttachment `json:"attachments,omitempty" extensions:"x-nullable,x-omitempty"` - Fields []EntityField `json:"fields,omitempty" extensions:"x-nullable,x-omitempty"` + Fields []EntityField `json:"fields,omitempty" extensions:"x-nullable,x-omitempty"` } ) diff --git a/backend/internal/data/repo/repo_entity_types.go b/backend/internal/data/repo/repo_entity_types.go index c04c6f79..e2586c39 100644 --- a/backend/internal/data/repo/repo_entity_types.go +++ b/backend/internal/data/repo/repo_entity_types.go @@ -20,23 +20,23 @@ type ( Name string `json:"name"` IsLocation bool `json:"isLocation"` Description string `json:"description" extension:"x-nullable"` - Icon string `json:"icon" extension:"x-nullable"` - Color string `json:"color" extension:"x-nullable"` + Icon string `json:"icon" extension:"x-nullable"` + Color string `json:"color" extension:"x-nullable"` } EntityTypeCreate struct { - Name string `json:"name" validate:"required"` - IsLocation bool `json:"isLocation" validate:"required"` + Name string `json:"name" validate:"required"` + IsLocation bool `json:"isLocation" validate:"required"` Description string `json:"description" extension:"x-nullable"` - Icon string `json:"icon" extension:"x-nullable"` - Color string `json:"color" extension:"x-nullable"` + Icon string `json:"icon" extension:"x-nullable"` + Color string `json:"color" extension:"x-nullable"` } EntityTypeUpdate struct { - Name string `json:"name" validate:"omitempty,min=1"` + Name string `json:"name" validate:"omitempty,min=1"` Description string `json:"description" extension:"x-nullable"` - Icon string `json:"icon" extension:"x-nullable"` - Color string `json:"color" extension:"x-nullable"` + Icon string `json:"icon" extension:"x-nullable"` + Color string `json:"color" extension:"x-nullable"` } ) diff --git a/backend/internal/data/repo/repo_items_search_test.go b/backend/internal/data/repo/repo_items_search_test.go index cb7accf3..76019a61 100644 --- a/backend/internal/data/repo/repo_items_search_test.go +++ b/backend/internal/data/repo/repo_items_search_test.go @@ -3,18 +3,18 @@ package repo import ( "testing" - "github.com/sysadminsmedia/homebox/backend/pkgs/textutils" "github.com/stretchr/testify/assert" + "github.com/sysadminsmedia/homebox/backend/pkgs/textutils" ) func TestItemsRepository_AccentInsensitiveSearch(t *testing.T) { // Test cases for accent-insensitive search testCases := []struct { - name string - itemName string - searchQuery string - shouldMatch bool - description string + name string + itemName string + searchQuery string + shouldMatch bool + description string }{ { name: "Spanish accented item, search without accents", @@ -155,25 +155,25 @@ func TestItemsRepository_AccentInsensitiveSearch(t *testing.T) { t.Run(tc.name, func(t *testing.T) { // Test the normalization logic used in the repository normalizedSearch := textutils.NormalizeSearchQuery(tc.searchQuery) - + // This simulates what happens in the repository // The original search would find exact matches (case-insensitive) // The normalized search would find accent-insensitive matches - + // Test that our normalization works as expected if tc.shouldMatch { // If it should match, then either the original query should match // or the normalized query should match when applied to the stored data - assert.NotEqual(t, "", normalizedSearch, "Normalized search should not be empty") - + assert.NotEmpty(t, normalizedSearch, "Normalized search should not be empty") + // The key insight is that we're searching with both the original and normalized queries // So "electrónica" will be found when searching for "electronica" because: // 1. Original search: "electronica" doesn't match "electrónica" // 2. Normalized search: "electronica" matches the normalized version - t.Logf("✓ %s: Item '%s' should be found with search '%s' (normalized: '%s')", + t.Logf("✓ %s: Item '%s' should be found with search '%s' (normalized: '%s')", tc.description, tc.itemName, tc.searchQuery, normalizedSearch) } else { - t.Logf("✗ %s: Item '%s' should NOT be found with search '%s' (normalized: '%s')", + t.Logf("✗ %s: Item '%s' should NOT be found with search '%s' (normalized: '%s')", tc.description, tc.itemName, tc.searchQuery, normalizedSearch) } }) diff --git a/backend/internal/sys/config/conf.go b/backend/internal/sys/config/conf.go index bad0ccf0..a2b52351 100644 --- a/backend/internal/sys/config/conf.go +++ b/backend/internal/sys/config/conf.go @@ -61,14 +61,14 @@ type WebConfig struct { } type LabelMakerConf struct { - Width int64 `yaml:"width" conf:"default:526"` - Height int64 `yaml:"height" conf:"default:200"` - Padding int64 `yaml:"padding" conf:"default:32"` - Margin int64 `yaml:"margin" conf:"default:32"` - FontSize float64 `yaml:"font_size" conf:"default:32.0"` + Width int64 `yaml:"width" conf:"default:526"` + Height int64 `yaml:"height" conf:"default:200"` + Padding int64 `yaml:"padding" conf:"default:32"` + Margin int64 `yaml:"margin" conf:"default:32"` + FontSize float64 `yaml:"font_size" conf:"default:32.0"` PrintCommand *string `yaml:"string"` AdditionalInformation *string `yaml:"string"` - DynamicLength bool `yaml:"bool" conf:"default:true"` + DynamicLength bool `yaml:"bool" conf:"default:true"` LabelServiceUrl *string `yaml:"label_service_url"` LabelServiceTimeout *time.Duration `yaml:"label_service_timeout"` } diff --git a/backend/pkgs/textutils/normalize.go b/backend/pkgs/textutils/normalize.go index 4e86235d..f484f4d6 100644 --- a/backend/pkgs/textutils/normalize.go +++ b/backend/pkgs/textutils/normalize.go @@ -22,13 +22,13 @@ func RemoveAccents(text string) string { // 2. Removes diacritical marks (combining characters) // 3. Normalizes back to NFC (canonical composition) t := transform.Chain(norm.NFD, runes.Remove(runes.In(unicode.Mn)), norm.NFC) - + result, _, err := transform.String(t, text) if err != nil { // If transformation fails, return the original text return text } - + return result } diff --git a/frontend/components/global/DetailsSection/DetailsSection.vue b/frontend/components/global/DetailsSection/DetailsSection.vue index fa65d84b..5ab63d87 100644 --- a/frontend/components/global/DetailsSection/DetailsSection.vue +++ b/frontend/components/global/DetailsSection/DetailsSection.vue @@ -147,6 +147,4 @@ overflow-wrap: break-word; } } - - diff --git a/frontend/lib/api/__test__/user/items.test.ts b/frontend/lib/api/__test__/user/items.test.ts index 87c3e894..01c7903f 100644 --- a/frontend/lib/api/__test__/user/items.test.ts +++ b/frontend/lib/api/__test__/user/items.test.ts @@ -1,6 +1,6 @@ import { faker } from "@faker-js/faker"; import { describe, expect, test } from "vitest"; -import type { ItemField, ItemUpdate, LocationOut } from "../../types/data-contracts"; +import type {EntityType, ItemField, ItemUpdate, LocationOut} from "../../types/data-contracts"; import { AttachmentTypes } from "../../types/non-generated"; import type { UserClient } from "../../user"; import { factories } from "../factories"; @@ -8,6 +8,7 @@ import { sharedUserClient } from "../test-utils"; describe("user should be able to create an item and add an attachment", () => { let increment = 0; + /** * useLocation sets up a location resource for testing, and returns a function * that can be used to delete the location from the backend server. @@ -29,6 +30,11 @@ describe("user should be able to create an item and add an attachment", () => { return [data, cleanup]; } + async function useEntityType(api: UserClient): Promise<[EntityType, () => Promise]> { + const { response, data } = await api. + } + } + test("user should be able to create an item and add an attachment", async () => { const api = await sharedUserClient(); const [location, cleanup] = await useLocation(api); diff --git a/frontend/lib/api/classes/items.ts b/frontend/lib/api/classes/items.ts index 3639b79e..1ab08f65 100644 --- a/frontend/lib/api/classes/items.ts +++ b/frontend/lib/api/classes/items.ts @@ -1,7 +1,7 @@ import { BaseAPI, route } from "../base"; import { parseDate } from "../base/base-api"; import type { - ItemAttachmentUpdate, + EntityAttachmentUpdate, ItemCreate, ItemOut, ItemPatch, @@ -53,8 +53,8 @@ export class AttachmentsAPI extends BaseAPI { return this.http.delete({ url: route(`/items/${id}/attachments/${attachmentId}`) }); } - update(id: string, attachmentId: string, data: ItemAttachmentUpdate) { - return this.http.put({ + update(id: string, attachmentId: string, data: EntityAttachmentUpdate) { + return this.http.put({ url: route(`/items/${id}/attachments/${attachmentId}`), body: data, });