From 2355438962a86ad3f78ba0cedc888785dab57957 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 28 Dec 2025 17:45:18 +0000 Subject: [PATCH 1/9] Initial plan From 033c17552b3015f048869d7db2b86d6809867706 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 28 Dec 2025 18:01:24 +0000 Subject: [PATCH 2/9] Update plan with root cause analysis Co-authored-by: katosdev <7927609+katosdev@users.noreply.github.com> --- backend/app/api/static/docs/docs.go | 49 +++++++++++ backend/app/api/static/docs/openapi-3.json | 50 +++++++++++ backend/app/api/static/docs/openapi-3.yaml | 30 +++++++ backend/app/api/static/docs/swagger.json | 49 +++++++++++ backend/app/api/static/docs/swagger.yaml | 30 +++++++ backend/go.sum | 8 ++ docs/en/api/openapi-2.0.json | 97 +++++++++++++++++---- docs/en/api/openapi-2.0.yaml | 46 ++++++++++ docs/en/api/openapi-3.0.json | 50 +++++++++++ docs/en/api/openapi-3.0.yaml | 30 +++++++ docs/en/api/swagger-2.0.json | 49 +++++++++++ docs/en/api/swagger-2.0.yaml | 30 +++++++ frontend/components/WipeInventoryDialog.vue | 7 +- frontend/lib/api/types/data-contracts.ts | 6 ++ 14 files changed, 513 insertions(+), 18 deletions(-) diff --git a/backend/app/api/static/docs/docs.go b/backend/app/api/static/docs/docs.go index 1af68fee..d08de9b6 100644 --- a/backend/app/api/static/docs/docs.go +++ b/backend/app/api/static/docs/docs.go @@ -118,6 +118,41 @@ const docTemplate = `{ } } }, + "/v1/actions/wipe-inventory": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Deletes all items in the inventory", + "produces": [ + "application/json" + ], + "tags": [ + "Actions" + ], + "summary": "Wipe Inventory", + "parameters": [ + { + "description": "Wipe options", + "name": "options", + "in": "body", + "schema": { + "$ref": "#/definitions/v1.WipeInventoryOptions" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.ActionAmountResult" + } + } + } + } + }, "/v1/actions/zero-item-time-fields": { "post": { "security": [ @@ -5184,6 +5219,20 @@ const docTemplate = `{ } } }, + "v1.WipeInventoryOptions": { + "type": "object", + "properties": { + "wipeLabels": { + "type": "boolean" + }, + "wipeLocations": { + "type": "boolean" + }, + "wipeMaintenance": { + "type": "boolean" + } + } + }, "v1.Wrapped": { "type": "object", "properties": { diff --git a/backend/app/api/static/docs/openapi-3.json b/backend/app/api/static/docs/openapi-3.json index a80a6124..f4ce81bf 100644 --- a/backend/app/api/static/docs/openapi-3.json +++ b/backend/app/api/static/docs/openapi-3.json @@ -114,6 +114,42 @@ } } }, + "/v1/actions/wipe-inventory": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Deletes all items in the inventory", + "tags": [ + "Actions" + ], + "summary": "Wipe Inventory", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/v1.WipeInventoryOptions" + } + } + }, + "description": "Wipe options" + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/v1.ActionAmountResult" + } + } + } + } + } + } + }, "/v1/actions/zero-item-time-fields": { "post": { "security": [ @@ -5381,6 +5417,20 @@ } } }, + "v1.WipeInventoryOptions": { + "type": "object", + "properties": { + "wipeLabels": { + "type": "boolean" + }, + "wipeLocations": { + "type": "boolean" + }, + "wipeMaintenance": { + "type": "boolean" + } + } + }, "v1.Wrapped": { "type": "object", "properties": { diff --git a/backend/app/api/static/docs/openapi-3.yaml b/backend/app/api/static/docs/openapi-3.yaml index 0a6d2042..eda39cf7 100644 --- a/backend/app/api/static/docs/openapi-3.yaml +++ b/backend/app/api/static/docs/openapi-3.yaml @@ -67,6 +67,27 @@ paths: application/json: schema: $ref: "#/components/schemas/v1.ActionAmountResult" + /v1/actions/wipe-inventory: + post: + security: + - Bearer: [] + description: Deletes all items in the inventory + tags: + - Actions + summary: Wipe Inventory + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/v1.WipeInventoryOptions" + description: Wipe options + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/v1.ActionAmountResult" /v1/actions/zero-item-time-fields: post: security: @@ -3449,6 +3470,15 @@ components: type: string token: type: string + v1.WipeInventoryOptions: + type: object + properties: + wipeLabels: + type: boolean + wipeLocations: + type: boolean + wipeMaintenance: + type: boolean v1.Wrapped: type: object properties: diff --git a/backend/app/api/static/docs/swagger.json b/backend/app/api/static/docs/swagger.json index 61b8612a..cb5a49f4 100644 --- a/backend/app/api/static/docs/swagger.json +++ b/backend/app/api/static/docs/swagger.json @@ -116,6 +116,41 @@ } } }, + "/v1/actions/wipe-inventory": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Deletes all items in the inventory", + "produces": [ + "application/json" + ], + "tags": [ + "Actions" + ], + "summary": "Wipe Inventory", + "parameters": [ + { + "description": "Wipe options", + "name": "options", + "in": "body", + "schema": { + "$ref": "#/definitions/v1.WipeInventoryOptions" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.ActionAmountResult" + } + } + } + } + }, "/v1/actions/zero-item-time-fields": { "post": { "security": [ @@ -5182,6 +5217,20 @@ } } }, + "v1.WipeInventoryOptions": { + "type": "object", + "properties": { + "wipeLabels": { + "type": "boolean" + }, + "wipeLocations": { + "type": "boolean" + }, + "wipeMaintenance": { + "type": "boolean" + } + } + }, "v1.Wrapped": { "type": "object", "properties": { diff --git a/backend/app/api/static/docs/swagger.yaml b/backend/app/api/static/docs/swagger.yaml index d18a8f45..0d234331 100644 --- a/backend/app/api/static/docs/swagger.yaml +++ b/backend/app/api/static/docs/swagger.yaml @@ -1867,6 +1867,15 @@ definitions: token: type: string type: object + v1.WipeInventoryOptions: + properties: + wipeLabels: + type: boolean + wipeLocations: + type: boolean + wipeMaintenance: + type: boolean + type: object v1.Wrapped: properties: item: {} @@ -1947,6 +1956,27 @@ paths: summary: Set Primary Photos tags: - Actions + /v1/actions/wipe-inventory: + post: + description: Deletes all items in the inventory + parameters: + - description: Wipe options + in: body + name: options + schema: + $ref: '#/definitions/v1.WipeInventoryOptions' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/v1.ActionAmountResult' + security: + - Bearer: [] + summary: Wipe Inventory + tags: + - Actions /v1/actions/zero-item-time-fields: post: description: Resets all item date fields to the beginning of the day diff --git a/backend/go.sum b/backend/go.sum index 6f11d8f1..0d766402 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -325,6 +325,8 @@ 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= @@ -347,6 +349,8 @@ github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOF github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/olahol/melody v1.4.0 h1:Pa5SdeZL/zXPi1tJuMAPDbl4n3gQOThSL6G1p4qZ4SI= github.com/olahol/melody v1.4.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= @@ -389,6 +393,10 @@ github.com/shirou/gopsutil/v4 v4.25.11 h1:X53gB7muL9Gnwwo2evPSE+SfOrltMoR6V3xJAX github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU= 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.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/docs/en/api/openapi-2.0.json b/docs/en/api/openapi-2.0.json index cd4721fa..cb5a49f4 100644 --- a/docs/en/api/openapi-2.0.json +++ b/docs/en/api/openapi-2.0.json @@ -116,6 +116,41 @@ } } }, + "/v1/actions/wipe-inventory": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Deletes all items in the inventory", + "produces": [ + "application/json" + ], + "tags": [ + "Actions" + ], + "summary": "Wipe Inventory", + "parameters": [ + { + "description": "Wipe options", + "name": "options", + "in": "body", + "schema": { + "$ref": "#/definitions/v1.WipeInventoryOptions" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.ActionAmountResult" + } + } + } + } + }, "/v1/actions/zero-item-time-fields": { "post": { "security": [ @@ -4032,7 +4067,8 @@ "properties": { "defaultDescription": { "type": "string", - "maxLength": 1000 + "maxLength": 1000, + "x-nullable": true }, "defaultInsured": { "type": "boolean" @@ -4041,34 +4077,41 @@ "type": "array", "items": { "type": "string" - } + }, + "x-nullable": true }, "defaultLifetimeWarranty": { "type": "boolean" }, "defaultLocationId": { "description": "Default location and labels", - "type": "string" + "type": "string", + "x-nullable": true }, "defaultManufacturer": { "type": "string", - "maxLength": 255 + "maxLength": 255, + "x-nullable": true }, "defaultModelNumber": { "type": "string", - "maxLength": 255 + "maxLength": 255, + "x-nullable": true }, "defaultName": { "type": "string", - "maxLength": 255 + "maxLength": 255, + "x-nullable": true }, "defaultQuantity": { "description": "Default values for items", - "type": "integer" + "type": "integer", + "x-nullable": true }, "defaultWarrantyDetails": { "type": "string", - "maxLength": 1000 + "maxLength": 1000, + "x-nullable": true }, "description": { "type": "string", @@ -4209,7 +4252,8 @@ "properties": { "defaultDescription": { "type": "string", - "maxLength": 1000 + "maxLength": 1000, + "x-nullable": true }, "defaultInsured": { "type": "boolean" @@ -4218,34 +4262,41 @@ "type": "array", "items": { "type": "string" - } + }, + "x-nullable": true }, "defaultLifetimeWarranty": { "type": "boolean" }, "defaultLocationId": { "description": "Default location and labels", - "type": "string" + "type": "string", + "x-nullable": true }, "defaultManufacturer": { "type": "string", - "maxLength": 255 + "maxLength": 255, + "x-nullable": true }, "defaultModelNumber": { "type": "string", - "maxLength": 255 + "maxLength": 255, + "x-nullable": true }, "defaultName": { "type": "string", - "maxLength": 255 + "maxLength": 255, + "x-nullable": true }, "defaultQuantity": { "description": "Default values for items", - "type": "integer" + "type": "integer", + "x-nullable": true }, "defaultWarrantyDetails": { "type": "string", - "maxLength": 1000 + "maxLength": 1000, + "x-nullable": true }, "description": { "type": "string", @@ -5166,6 +5217,20 @@ } } }, + "v1.WipeInventoryOptions": { + "type": "object", + "properties": { + "wipeLabels": { + "type": "boolean" + }, + "wipeLocations": { + "type": "boolean" + }, + "wipeMaintenance": { + "type": "boolean" + } + } + }, "v1.Wrapped": { "type": "object", "properties": { diff --git a/docs/en/api/openapi-2.0.yaml b/docs/en/api/openapi-2.0.yaml index 8926c617..0d234331 100644 --- a/docs/en/api/openapi-2.0.yaml +++ b/docs/en/api/openapi-2.0.yaml @@ -1084,32 +1084,40 @@ definitions: defaultDescription: maxLength: 1000 type: string + x-nullable: true defaultInsured: type: boolean defaultLabelIds: items: type: string type: array + x-nullable: true defaultLifetimeWarranty: type: boolean defaultLocationId: description: Default location and labels type: string + x-nullable: true defaultManufacturer: maxLength: 255 type: string + x-nullable: true defaultModelNumber: maxLength: 255 type: string + x-nullable: true defaultName: maxLength: 255 type: string + x-nullable: true defaultQuantity: description: Default values for items type: integer + x-nullable: true defaultWarrantyDetails: maxLength: 1000 type: string + x-nullable: true description: maxLength: 1000 type: string @@ -1205,32 +1213,40 @@ definitions: defaultDescription: maxLength: 1000 type: string + x-nullable: true defaultInsured: type: boolean defaultLabelIds: items: type: string type: array + x-nullable: true defaultLifetimeWarranty: type: boolean defaultLocationId: description: Default location and labels type: string + x-nullable: true defaultManufacturer: maxLength: 255 type: string + x-nullable: true defaultModelNumber: maxLength: 255 type: string + x-nullable: true defaultName: maxLength: 255 type: string + x-nullable: true defaultQuantity: description: Default values for items type: integer + x-nullable: true defaultWarrantyDetails: maxLength: 1000 type: string + x-nullable: true description: maxLength: 1000 type: string @@ -1851,6 +1867,15 @@ definitions: token: type: string type: object + v1.WipeInventoryOptions: + properties: + wipeLabels: + type: boolean + wipeLocations: + type: boolean + wipeMaintenance: + type: boolean + type: object v1.Wrapped: properties: item: {} @@ -1931,6 +1956,27 @@ paths: summary: Set Primary Photos tags: - Actions + /v1/actions/wipe-inventory: + post: + description: Deletes all items in the inventory + parameters: + - description: Wipe options + in: body + name: options + schema: + $ref: '#/definitions/v1.WipeInventoryOptions' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/v1.ActionAmountResult' + security: + - Bearer: [] + summary: Wipe Inventory + tags: + - Actions /v1/actions/zero-item-time-fields: post: description: Resets all item date fields to the beginning of the day diff --git a/docs/en/api/openapi-3.0.json b/docs/en/api/openapi-3.0.json index a80a6124..f4ce81bf 100644 --- a/docs/en/api/openapi-3.0.json +++ b/docs/en/api/openapi-3.0.json @@ -114,6 +114,42 @@ } } }, + "/v1/actions/wipe-inventory": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Deletes all items in the inventory", + "tags": [ + "Actions" + ], + "summary": "Wipe Inventory", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/v1.WipeInventoryOptions" + } + } + }, + "description": "Wipe options" + }, + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/v1.ActionAmountResult" + } + } + } + } + } + } + }, "/v1/actions/zero-item-time-fields": { "post": { "security": [ @@ -5381,6 +5417,20 @@ } } }, + "v1.WipeInventoryOptions": { + "type": "object", + "properties": { + "wipeLabels": { + "type": "boolean" + }, + "wipeLocations": { + "type": "boolean" + }, + "wipeMaintenance": { + "type": "boolean" + } + } + }, "v1.Wrapped": { "type": "object", "properties": { diff --git a/docs/en/api/openapi-3.0.yaml b/docs/en/api/openapi-3.0.yaml index 0a6d2042..eda39cf7 100644 --- a/docs/en/api/openapi-3.0.yaml +++ b/docs/en/api/openapi-3.0.yaml @@ -67,6 +67,27 @@ paths: application/json: schema: $ref: "#/components/schemas/v1.ActionAmountResult" + /v1/actions/wipe-inventory: + post: + security: + - Bearer: [] + description: Deletes all items in the inventory + tags: + - Actions + summary: Wipe Inventory + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/v1.WipeInventoryOptions" + description: Wipe options + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/v1.ActionAmountResult" /v1/actions/zero-item-time-fields: post: security: @@ -3449,6 +3470,15 @@ components: type: string token: type: string + v1.WipeInventoryOptions: + type: object + properties: + wipeLabels: + type: boolean + wipeLocations: + type: boolean + wipeMaintenance: + type: boolean v1.Wrapped: type: object properties: diff --git a/docs/en/api/swagger-2.0.json b/docs/en/api/swagger-2.0.json index 61b8612a..cb5a49f4 100644 --- a/docs/en/api/swagger-2.0.json +++ b/docs/en/api/swagger-2.0.json @@ -116,6 +116,41 @@ } } }, + "/v1/actions/wipe-inventory": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "Deletes all items in the inventory", + "produces": [ + "application/json" + ], + "tags": [ + "Actions" + ], + "summary": "Wipe Inventory", + "parameters": [ + { + "description": "Wipe options", + "name": "options", + "in": "body", + "schema": { + "$ref": "#/definitions/v1.WipeInventoryOptions" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/v1.ActionAmountResult" + } + } + } + } + }, "/v1/actions/zero-item-time-fields": { "post": { "security": [ @@ -5182,6 +5217,20 @@ } } }, + "v1.WipeInventoryOptions": { + "type": "object", + "properties": { + "wipeLabels": { + "type": "boolean" + }, + "wipeLocations": { + "type": "boolean" + }, + "wipeMaintenance": { + "type": "boolean" + } + } + }, "v1.Wrapped": { "type": "object", "properties": { diff --git a/docs/en/api/swagger-2.0.yaml b/docs/en/api/swagger-2.0.yaml index d18a8f45..0d234331 100644 --- a/docs/en/api/swagger-2.0.yaml +++ b/docs/en/api/swagger-2.0.yaml @@ -1867,6 +1867,15 @@ definitions: token: type: string type: object + v1.WipeInventoryOptions: + properties: + wipeLabels: + type: boolean + wipeLocations: + type: boolean + wipeMaintenance: + type: boolean + type: object v1.Wrapped: properties: item: {} @@ -1947,6 +1956,27 @@ paths: summary: Set Primary Photos tags: - Actions + /v1/actions/wipe-inventory: + post: + description: Deletes all items in the inventory + parameters: + - description: Wipe options + in: body + name: options + schema: + $ref: '#/definitions/v1.WipeInventoryOptions' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/v1.ActionAmountResult' + security: + - Bearer: [] + summary: Wipe Inventory + tags: + - Actions /v1/actions/zero-item-time-fields: post: description: Resets all item date fields to the beginning of the day diff --git a/frontend/components/WipeInventoryDialog.vue b/frontend/components/WipeInventoryDialog.vue index 64bf33c2..7fc9502d 100644 --- a/frontend/components/WipeInventoryDialog.vue +++ b/frontend/components/WipeInventoryDialog.vue @@ -82,12 +82,14 @@ const wipeLabels = ref(false); const wipeLocations = ref(false); const wipeMaintenance = ref(false); + const isConfirming = ref(false); registerOpenDialogCallback(DialogID.WipeInventory, () => { dialog.value = true; wipeLabels.value = false; wipeLocations.value = false; wipeMaintenance.value = false; + isConfirming.value = false; }); watch( @@ -103,7 +105,7 @@ ); function handleOpenChange(open: boolean) { - if (!open) { + if (!open && !isConfirming.value) { close(); } } @@ -114,12 +116,13 @@ } function confirm() { - dialog.value = false; + isConfirming.value = true; const result = { wipeLabels: wipeLabels.value, wipeLocations: wipeLocations.value, wipeMaintenance: wipeMaintenance.value, }; + dialog.value = false; closeDialog(DialogID.WipeInventory, result); } diff --git a/frontend/lib/api/types/data-contracts.ts b/frontend/lib/api/types/data-contracts.ts index 10414206..3f7e283c 100644 --- a/frontend/lib/api/types/data-contracts.ts +++ b/frontend/lib/api/types/data-contracts.ts @@ -1150,6 +1150,12 @@ export interface TokenResponse { token: string; } +export interface WipeInventoryOptions { + wipeLabels: boolean; + wipeLocations: boolean; + wipeMaintenance: boolean; +} + export interface Wrapped { item: any; } From d82c52df260c3ea6bd3a640dd9f0c3ff35523060 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 28 Dec 2025 18:02:08 +0000 Subject: [PATCH 3/9] Fix wipe inventory by replacing AlertDialogAction with Button Co-authored-by: katosdev <7927609+katosdev@users.noreply.github.com> --- frontend/components/WipeInventoryDialog.vue | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/frontend/components/WipeInventoryDialog.vue b/frontend/components/WipeInventoryDialog.vue index 7fc9502d..c4264fe5 100644 --- a/frontend/components/WipeInventoryDialog.vue +++ b/frontend/components/WipeInventoryDialog.vue @@ -54,9 +54,9 @@ {{ $t("global.cancel") }} - + @@ -67,7 +67,6 @@ import { useDialog } from "~/components/ui/dialog-provider"; import { AlertDialog, - AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, @@ -75,6 +74,7 @@ AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; + import { Button } from "@/components/ui/button"; const { registerOpenDialogCallback, closeDialog, addAlert, removeAlert } = useDialog(); @@ -82,14 +82,12 @@ const wipeLabels = ref(false); const wipeLocations = ref(false); const wipeMaintenance = ref(false); - const isConfirming = ref(false); registerOpenDialogCallback(DialogID.WipeInventory, () => { dialog.value = true; wipeLabels.value = false; wipeLocations.value = false; wipeMaintenance.value = false; - isConfirming.value = false; }); watch( @@ -105,7 +103,7 @@ ); function handleOpenChange(open: boolean) { - if (!open && !isConfirming.value) { + if (!open) { close(); } } @@ -116,7 +114,6 @@ } function confirm() { - isConfirming.value = true; const result = { wipeLabels: wipeLabels.value, wipeLocations: wipeLocations.value, From 5cd7792701c2d389c477950d960778e95389abea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 28 Dec 2025 18:05:29 +0000 Subject: [PATCH 4/9] Fix callback order and restore isConfirming flag Co-authored-by: katosdev <7927609+katosdev@users.noreply.github.com> --- frontend/components/WipeInventoryDialog.vue | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/components/WipeInventoryDialog.vue b/frontend/components/WipeInventoryDialog.vue index c4264fe5..fe082cef 100644 --- a/frontend/components/WipeInventoryDialog.vue +++ b/frontend/components/WipeInventoryDialog.vue @@ -82,12 +82,14 @@ const wipeLabels = ref(false); const wipeLocations = ref(false); const wipeMaintenance = ref(false); + const isConfirming = ref(false); registerOpenDialogCallback(DialogID.WipeInventory, () => { dialog.value = true; wipeLabels.value = false; wipeLocations.value = false; wipeMaintenance.value = false; + isConfirming.value = false; }); watch( @@ -103,7 +105,7 @@ ); function handleOpenChange(open: boolean) { - if (!open) { + if (!open && !isConfirming.value) { close(); } } @@ -114,12 +116,13 @@ } function confirm() { + isConfirming.value = true; const result = { wipeLabels: wipeLabels.value, wipeLocations: wipeLocations.value, wipeMaintenance: wipeMaintenance.value, }; - dialog.value = false; closeDialog(DialogID.WipeInventory, result); + dialog.value = false; } From ec8703114f536029711ca2704ccb9c0e9aec25ae Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 28 Dec 2025 18:08:54 +0000 Subject: [PATCH 5/9] Reset isConfirming flag after dialog closes Co-authored-by: katosdev <7927609+katosdev@users.noreply.github.com> --- frontend/components/WipeInventoryDialog.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/components/WipeInventoryDialog.vue b/frontend/components/WipeInventoryDialog.vue index fe082cef..29eca418 100644 --- a/frontend/components/WipeInventoryDialog.vue +++ b/frontend/components/WipeInventoryDialog.vue @@ -124,5 +124,6 @@ }; closeDialog(DialogID.WipeInventory, result); dialog.value = false; + isConfirming.value = false; } From 1f6782f8beff67c8b55be634c105f634906776a6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 28 Dec 2025 18:12:23 +0000 Subject: [PATCH 6/9] Final documentation update Co-authored-by: katosdev <7927609+katosdev@users.noreply.github.com> --- .scaffold/go.sum | 4 ++-- backend/go.sum | 8 -------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/.scaffold/go.sum b/.scaffold/go.sum index 40d03dd1..36f3018c 100644 --- a/.scaffold/go.sum +++ b/.scaffold/go.sum @@ -8,7 +8,7 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/sysadminsmedia/homebox/backend v0.0.0-20251228163253-2bd6ff580a7f h1:+5m3FRu/Ja3kH2XgFn0GYCWOKIe4O+7PbLawLXvb4gA= -github.com/sysadminsmedia/homebox/backend v0.0.0-20251228163253-2bd6ff580a7f/go.mod h1:9zHHw5TNttw5Kn4Wks+SxwXmJPz6PgGNbnB4BtF1Z4c= +github.com/sysadminsmedia/homebox/backend v0.0.0-20251228172914-2a6773d1d610 h1:kNLtnxaPaOryBUZ7RgUHPQVWxIExXYR/q9pYCbum5Vk= +github.com/sysadminsmedia/homebox/backend v0.0.0-20251228172914-2a6773d1d610/go.mod h1:9zHHw5TNttw5Kn4Wks+SxwXmJPz6PgGNbnB4BtF1Z4c= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/go.sum b/backend/go.sum index 0d766402..6f11d8f1 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -325,8 +325,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= @@ -349,8 +347,6 @@ github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOF github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/olahol/melody v1.4.0 h1:Pa5SdeZL/zXPi1tJuMAPDbl4n3gQOThSL6G1p4qZ4SI= github.com/olahol/melody v1.4.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= @@ -393,10 +389,6 @@ github.com/shirou/gopsutil/v4 v4.25.11 h1:X53gB7muL9Gnwwo2evPSE+SfOrltMoR6V3xJAX github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU= 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.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= From 94f0123d9c35e8adf87cfa4d908a4ae7379033a6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 28 Dec 2025 18:19:00 +0000 Subject: [PATCH 7/9] Co-authored-by: katosdev <7927609+katosdev@users.noreply.github.com> --- backend/go.sum | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backend/go.sum b/backend/go.sum index 6f11d8f1..0d766402 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -325,6 +325,8 @@ 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= @@ -347,6 +349,8 @@ github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOF github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/olahol/melody v1.4.0 h1:Pa5SdeZL/zXPi1tJuMAPDbl4n3gQOThSL6G1p4qZ4SI= github.com/olahol/melody v1.4.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= @@ -389,6 +393,10 @@ github.com/shirou/gopsutil/v4 v4.25.11 h1:X53gB7muL9Gnwwo2evPSE+SfOrltMoR6V3xJAX github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU= 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.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= From 4ba1a263c88e6ba3ac716a9a0191d26fb24b6256 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 28 Dec 2025 19:06:04 +0000 Subject: [PATCH 8/9] Publish mutation events when wiping labels and locations Co-authored-by: tonyaellie <46281725+tonyaellie@users.noreply.github.com> --- backend/app/api/handlers/v1/v1_ctrl_actions.go | 11 +++++++++++ backend/go.sum | 8 -------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/backend/app/api/handlers/v1/v1_ctrl_actions.go b/backend/app/api/handlers/v1/v1_ctrl_actions.go index 9766ed96..9f3ccd3b 100644 --- a/backend/app/api/handlers/v1/v1_ctrl_actions.go +++ b/backend/app/api/handlers/v1/v1_ctrl_actions.go @@ -10,6 +10,7 @@ import ( "github.com/hay-kot/httpkit/server" "github.com/rs/zerolog/log" "github.com/sysadminsmedia/homebox/backend/internal/core/services" + "github.com/sysadminsmedia/homebox/backend/internal/core/services/reporting/eventbus" "github.com/sysadminsmedia/homebox/backend/internal/sys/validate" ) @@ -143,6 +144,16 @@ func (ctrl *V1Controller) HandleWipeInventory() errchain.HandlerFunc { return validate.NewRequestError(err, http.StatusInternalServerError) } + // Publish mutation events for wiped resources + if ctrl.bus != nil { + if options.WipeLabels { + ctrl.bus.Publish(eventbus.EventLabelMutation, eventbus.GroupMutationEvent{GID: ctx.GID}) + } + if options.WipeLocations { + ctrl.bus.Publish(eventbus.EventLocationMutation, eventbus.GroupMutationEvent{GID: ctx.GID}) + } + } + return server.JSON(w, http.StatusOK, ActionAmountResult{Completed: totalCompleted}) } } diff --git a/backend/go.sum b/backend/go.sum index 0d766402..6f11d8f1 100644 --- a/backend/go.sum +++ b/backend/go.sum @@ -325,8 +325,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= @@ -349,8 +347,6 @@ github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOF github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/olahol/melody v1.4.0 h1:Pa5SdeZL/zXPi1tJuMAPDbl4n3gQOThSL6G1p4qZ4SI= github.com/olahol/melody v1.4.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= @@ -393,10 +389,6 @@ github.com/shirou/gopsutil/v4 v4.25.11 h1:X53gB7muL9Gnwwo2evPSE+SfOrltMoR6V3xJAX github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU= 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.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= From 1003223b47fbc23405514bba5ac3b0e4db9ade3e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 28 Dec 2025 19:24:14 +0000 Subject: [PATCH 9/9] Add E2E test for wipe inventory functionality Co-authored-by: katosdev <7927609+katosdev@users.noreply.github.com> --- .../test/e2e/wipe-inventory.browser.spec.ts | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 frontend/test/e2e/wipe-inventory.browser.spec.ts diff --git a/frontend/test/e2e/wipe-inventory.browser.spec.ts b/frontend/test/e2e/wipe-inventory.browser.spec.ts new file mode 100644 index 00000000..d7952466 --- /dev/null +++ b/frontend/test/e2e/wipe-inventory.browser.spec.ts @@ -0,0 +1,129 @@ +import { expect, test } from "@playwright/test"; + +test.describe("Wipe Inventory E2E Test", () => { + test.beforeEach(async ({ page }) => { + // Login as demo user (owner with permissions) + await page.goto("/"); + await page.fill("input[type='text']", "demo@example.com"); + await page.fill("input[type='password']", "demo"); + await page.click("button[type='submit']"); + await expect(page).toHaveURL("/home"); + }); + + test("should open wipe inventory dialog with all options", async ({ page }) => { + // Navigate to Tools page + await page.goto("/tools"); + await page.waitForLoadState("networkidle"); + + // Scroll to the bottom where wipe inventory is located + await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)); + await page.waitForTimeout(500); + + // Find and click the Wipe Inventory button + const wipeButton = page.locator("button", { hasText: "Wipe Inventory" }).last(); + await expect(wipeButton).toBeVisible(); + await wipeButton.click(); + + // Wait for dialog to appear + await page.waitForTimeout(1000); + + // Verify dialog title is visible + await expect(page.locator("text=Wipe Inventory").first()).toBeVisible(); + + // Verify all checkboxes are present + await expect(page.locator("input#wipe-labels-checkbox")).toBeVisible(); + await expect(page.locator("input#wipe-locations-checkbox")).toBeVisible(); + await expect(page.locator("input#wipe-maintenance-checkbox")).toBeVisible(); + + // Verify labels for checkboxes + await expect(page.locator("label[for='wipe-labels-checkbox']")).toBeVisible(); + await expect(page.locator("label[for='wipe-locations-checkbox']")).toBeVisible(); + await expect(page.locator("label[for='wipe-maintenance-checkbox']")).toBeVisible(); + + // Verify both Cancel and Confirm buttons are present + await expect(page.locator("button", { hasText: "Cancel" })).toBeVisible(); + const confirmButton = page.locator("button", { hasText: "Confirm" }); + await expect(confirmButton).toBeVisible(); + + // Take screenshot of the modal + await page.screenshot({ + path: "/tmp/playwright-logs/wipe-inventory-modal-initial.png", + }); + console.log("✅ Screenshot saved: wipe-inventory-modal-initial.png"); + + // Check all three options + await page.check("input#wipe-labels-checkbox"); + await page.check("input#wipe-locations-checkbox"); + await page.check("input#wipe-maintenance-checkbox"); + await page.waitForTimeout(500); + + // Verify checkboxes are checked + await expect(page.locator("input#wipe-labels-checkbox")).toBeChecked(); + await expect(page.locator("input#wipe-locations-checkbox")).toBeChecked(); + await expect(page.locator("input#wipe-maintenance-checkbox")).toBeChecked(); + + // Take screenshot with all options checked + await page.screenshot({ + path: "/tmp/playwright-logs/wipe-inventory-modal-options-checked.png", + }); + console.log("✅ Screenshot saved: wipe-inventory-modal-options-checked.png"); + + // Click Confirm button + await confirmButton.click(); + await page.waitForTimeout(2000); + + // Wait for the dialog to close (verify button is no longer visible) + await expect(confirmButton).not.toBeVisible({ timeout: 5000 }); + + // Check for success toast notification + // The toast should contain text about items being deleted + const toastLocator = page.locator("[role='status'], [class*='toast'], [class*='sonner']"); + await expect(toastLocator.first()).toBeVisible({ timeout: 10000 }); + + // Take screenshot of the page after confirmation + await page.screenshot({ + path: "/tmp/playwright-logs/after-wipe-confirmation.png", + fullPage: true, + }); + console.log("✅ Screenshot saved: after-wipe-confirmation.png"); + + console.log("✅ Test completed successfully!"); + console.log("✅ Wipe Inventory dialog opened correctly"); + console.log("✅ All three options (labels, locations, maintenance) are available"); + console.log("✅ Confirm button triggers the action"); + console.log("✅ Dialog closes after confirmation"); + }); + + test("should cancel wipe inventory operation", async ({ page }) => { + // Navigate to Tools page + await page.goto("/tools"); + await page.waitForLoadState("networkidle"); + + // Scroll to wipe inventory section + await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)); + await page.waitForTimeout(500); + + // Click Wipe Inventory button + const wipeButton = page.locator("button", { hasText: "Wipe Inventory" }).last(); + await wipeButton.click(); + await page.waitForTimeout(1000); + + // Verify dialog is open + await expect(page.locator("text=Wipe Inventory").first()).toBeVisible(); + + // Click Cancel button + const cancelButton = page.locator("button", { hasText: "Cancel" }); + await cancelButton.click(); + await page.waitForTimeout(1000); + + // Verify dialog is closed + await expect(page.locator("text=Wipe Inventory").first()).not.toBeVisible({ timeout: 5000 }); + + // Take screenshot after cancel + await page.screenshot({ + path: "/tmp/playwright-logs/after-cancel.png", + }); + console.log("✅ Screenshot saved: after-cancel.png"); + console.log("✅ Cancel button works correctly"); + }); +});