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");
+ });
+});