From 2cb3a9479323c18e1fd6293c1bf909a3798c4462 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Oct 2025 21:47:31 +0000 Subject: [PATCH 1/6] Initial plan From 474b0c5ce0c5881c260e0f8e5deeb53a8b8b0880 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Oct 2025 21:53:45 +0000 Subject: [PATCH 2/6] Add _uploadErrored method and onUploadError lifecycle hook with tests Co-authored-by: grantcopley <1197835+grantcopley@users.noreply.github.com> --- models/Component.cfc | 16 ++++++++++++ test-harness/tests/specs/CBWIRESpec.cfc | 25 +++++++++++++++++++ test-harness/wires/OnUploadError.cfc | 13 ++++++++++ test-harness/wires/OnUploadError.cfm | 6 +++++ .../wires/test/should_call_onuploaderror.cfm | 20 +++++++++++++++ 5 files changed, 80 insertions(+) create mode 100644 test-harness/wires/OnUploadError.cfc create mode 100644 test-harness/wires/OnUploadError.cfm create mode 100644 test-harness/wires/test/should_call_onuploaderror.cfm diff --git a/models/Component.cfc b/models/Component.cfc index 127a63f..93c7936 100644 --- a/models/Component.cfc +++ b/models/Component.cfc @@ -924,6 +924,22 @@ component output="true" accessors="true" { ); } + /** + * Method that is invoked when a file upload errors. + * + * @prop string | The property for the file input. + * @errors any | The errors that occurred during upload. + * @self boolean | Whether to dispatch to self. + * + * @return void + */ + function _uploadErrored( prop, errors, self ) { + // Check if the component has an onUploadError method and invoke it + if ( structKeyExists( this, "onUploadError" ) ) { + invoke( this, "onUploadError", { name: arguments.prop } ); + } + } + /** * Fires when missing methods are called. * Handles computed properties. diff --git a/test-harness/tests/specs/CBWIRESpec.cfc b/test-harness/tests/specs/CBWIRESpec.cfc index 37a4ae4..5d441ba 100644 --- a/test-harness/tests/specs/CBWIRESpec.cfc +++ b/test-harness/tests/specs/CBWIRESpec.cfc @@ -1060,6 +1060,31 @@ component extends="coldbox.system.testing.BaseTestCase" { expect( response.components[1].effects.html ).toInclude( "Hydrated Property: true" ); } ); + it( "should call onUploadError() if it exists when _uploadErrored is called", function() { + var payload = incomingRequest( + memo = { + "name": "test.should_call_onuploaderror", + "id": "Z1Ruz1tGMPXSfw7osBW2", + "children": [] + }, + data = { + "uploadErrored": false, + "erroredPropertyName": "" + }, + calls = [ + { + "path": "", + "method": "_uploadErrored", + "params": [ "photo", null, false ] + } + ], + updates = {} + ); + var response = cbwireController.handleRequest( payload, event ); + expect( response.components[1].effects.html ).toInclude( "Upload Errored: true" ); + expect( response.components[1].effects.html ).toInclude( "Errored Property Name: photo" ); + } ); + it( "should be able to return javascript to return", () => { var payload = incomingRequest( memo = { diff --git a/test-harness/wires/OnUploadError.cfc b/test-harness/wires/OnUploadError.cfc new file mode 100644 index 0000000..63bdaf2 --- /dev/null +++ b/test-harness/wires/OnUploadError.cfc @@ -0,0 +1,13 @@ +component extends="cbwire.models.Component" { + + data = { + "uploadErrored": false, + "erroredPropertyName": "" + }; + + function onUploadError( name ) { + data.uploadErrored = true; + data.erroredPropertyName = arguments.name; + } + +} diff --git a/test-harness/wires/OnUploadError.cfm b/test-harness/wires/OnUploadError.cfm new file mode 100644 index 0000000..a436b3a --- /dev/null +++ b/test-harness/wires/OnUploadError.cfm @@ -0,0 +1,6 @@ + +
+
Upload Errored: #uploadErrored#
+
Errored Property Name: #erroredPropertyName#
+
+
diff --git a/test-harness/wires/test/should_call_onuploaderror.cfm b/test-harness/wires/test/should_call_onuploaderror.cfm new file mode 100644 index 0000000..8488617 --- /dev/null +++ b/test-harness/wires/test/should_call_onuploaderror.cfm @@ -0,0 +1,20 @@ + + // @startWire + data = { + "uploadErrored": false, + "erroredPropertyName": "" + }; + + function onUploadError( name ) { + data.uploadErrored = true; + data.erroredPropertyName = arguments.name; + } + // @endWire + + + +
+
Upload Errored: #uploadErrored#
+
Errored Property Name: #erroredPropertyName#
+
+
From 2c583402caa876c71fa3e8d57cae5425b2d83e08 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Oct 2025 21:57:23 +0000 Subject: [PATCH 3/6] Pass all parameters (errors, multiple) to onUploadError lifecycle method Co-authored-by: grantcopley <1197835+grantcopley@users.noreply.github.com> --- models/Component.cfc | 6 +++++- test-harness/tests/specs/CBWIRESpec.cfc | 6 +++++- test-harness/wires/OnUploadError.cfc | 8 ++++++-- test-harness/wires/OnUploadError.cfm | 2 ++ test-harness/wires/test/should_call_onuploaderror.cfm | 10 ++++++++-- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/models/Component.cfc b/models/Component.cfc index 93c7936..1cb105d 100644 --- a/models/Component.cfc +++ b/models/Component.cfc @@ -936,7 +936,11 @@ component output="true" accessors="true" { function _uploadErrored( prop, errors, self ) { // Check if the component has an onUploadError method and invoke it if ( structKeyExists( this, "onUploadError" ) ) { - invoke( this, "onUploadError", { name: arguments.prop } ); + invoke( this, "onUploadError", { + name: arguments.prop, + errors: arguments.errors, + multiple: arguments.self + } ); } } diff --git a/test-harness/tests/specs/CBWIRESpec.cfc b/test-harness/tests/specs/CBWIRESpec.cfc index 5d441ba..158e5fb 100644 --- a/test-harness/tests/specs/CBWIRESpec.cfc +++ b/test-harness/tests/specs/CBWIRESpec.cfc @@ -1069,7 +1069,9 @@ component extends="coldbox.system.testing.BaseTestCase" { }, data = { "uploadErrored": false, - "erroredPropertyName": "" + "erroredPropertyName": "", + "errorInfo": "", + "isMultiple": false }, calls = [ { @@ -1083,6 +1085,8 @@ component extends="coldbox.system.testing.BaseTestCase" { var response = cbwireController.handleRequest( payload, event ); expect( response.components[1].effects.html ).toInclude( "Upload Errored: true" ); expect( response.components[1].effects.html ).toInclude( "Errored Property Name: photo" ); + expect( response.components[1].effects.html ).toInclude( "Error Info: null" ); + expect( response.components[1].effects.html ).toInclude( "Is Multiple: false" ); } ); it( "should be able to return javascript to return", () => { diff --git a/test-harness/wires/OnUploadError.cfc b/test-harness/wires/OnUploadError.cfc index 63bdaf2..2e4139a 100644 --- a/test-harness/wires/OnUploadError.cfc +++ b/test-harness/wires/OnUploadError.cfc @@ -2,12 +2,16 @@ component extends="cbwire.models.Component" { data = { "uploadErrored": false, - "erroredPropertyName": "" + "erroredPropertyName": "", + "errorInfo": "", + "isMultiple": false }; - function onUploadError( name ) { + function onUploadError( name, errors, multiple ) { data.uploadErrored = true; data.erroredPropertyName = arguments.name; + data.errorInfo = isNull( arguments.errors ) ? "null" : "has errors"; + data.isMultiple = arguments.multiple; } } diff --git a/test-harness/wires/OnUploadError.cfm b/test-harness/wires/OnUploadError.cfm index a436b3a..b78dbf4 100644 --- a/test-harness/wires/OnUploadError.cfm +++ b/test-harness/wires/OnUploadError.cfm @@ -2,5 +2,7 @@
Upload Errored: #uploadErrored#
Errored Property Name: #erroredPropertyName#
+
Error Info: #errorInfo#
+
Is Multiple: #isMultiple#
diff --git a/test-harness/wires/test/should_call_onuploaderror.cfm b/test-harness/wires/test/should_call_onuploaderror.cfm index 8488617..aacaae4 100644 --- a/test-harness/wires/test/should_call_onuploaderror.cfm +++ b/test-harness/wires/test/should_call_onuploaderror.cfm @@ -2,12 +2,16 @@ // @startWire data = { "uploadErrored": false, - "erroredPropertyName": "" + "erroredPropertyName": "", + "errorInfo": "", + "isMultiple": false }; - function onUploadError( name ) { + function onUploadError( name, errors, multiple ) { data.uploadErrored = true; data.erroredPropertyName = arguments.name; + data.errorInfo = isNull( arguments.errors ) ? "null" : "has errors"; + data.isMultiple = arguments.multiple; } // @endWire @@ -16,5 +20,7 @@
Upload Errored: #uploadErrored#
Errored Property Name: #erroredPropertyName#
+
Error Info: #errorInfo#
+
Is Multiple: #isMultiple#
From 82cc3c4706f13e035e4c0e1631d1260fc9abb703 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Oct 2025 21:59:03 +0000 Subject: [PATCH 4/6] Fix parameter name: rename 'self' to 'multiple' for clarity Co-authored-by: grantcopley <1197835+grantcopley@users.noreply.github.com> --- models/Component.cfc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/models/Component.cfc b/models/Component.cfc index 1cb105d..0c9d9b8 100644 --- a/models/Component.cfc +++ b/models/Component.cfc @@ -929,17 +929,17 @@ component output="true" accessors="true" { * * @prop string | The property for the file input. * @errors any | The errors that occurred during upload. - * @self boolean | Whether to dispatch to self. + * @multiple boolean | Whether multiple files are being uploaded. * * @return void */ - function _uploadErrored( prop, errors, self ) { + function _uploadErrored( prop, errors, multiple ) { // Check if the component has an onUploadError method and invoke it if ( structKeyExists( this, "onUploadError" ) ) { invoke( this, "onUploadError", { name: arguments.prop, errors: arguments.errors, - multiple: arguments.self + multiple: arguments.multiple } ); } } From 80c0aab7978efb4cca082efb1eb394d0071e0efc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Oct 2025 14:54:14 +0000 Subject: [PATCH 5/6] Rename 'name' parameter to 'property' in onUploadError lifecycle method Co-authored-by: grantcopley <1197835+grantcopley@users.noreply.github.com> --- models/Component.cfc | 2 +- test-harness/wires/OnUploadError.cfc | 4 ++-- test-harness/wires/test/should_call_onuploaderror.cfm | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/models/Component.cfc b/models/Component.cfc index 0c9d9b8..2b20797 100644 --- a/models/Component.cfc +++ b/models/Component.cfc @@ -937,7 +937,7 @@ component output="true" accessors="true" { // Check if the component has an onUploadError method and invoke it if ( structKeyExists( this, "onUploadError" ) ) { invoke( this, "onUploadError", { - name: arguments.prop, + property: arguments.prop, errors: arguments.errors, multiple: arguments.multiple } ); diff --git a/test-harness/wires/OnUploadError.cfc b/test-harness/wires/OnUploadError.cfc index 2e4139a..e5df5b5 100644 --- a/test-harness/wires/OnUploadError.cfc +++ b/test-harness/wires/OnUploadError.cfc @@ -7,9 +7,9 @@ component extends="cbwire.models.Component" { "isMultiple": false }; - function onUploadError( name, errors, multiple ) { + function onUploadError( property, errors, multiple ) { data.uploadErrored = true; - data.erroredPropertyName = arguments.name; + data.erroredPropertyName = arguments.property; data.errorInfo = isNull( arguments.errors ) ? "null" : "has errors"; data.isMultiple = arguments.multiple; } diff --git a/test-harness/wires/test/should_call_onuploaderror.cfm b/test-harness/wires/test/should_call_onuploaderror.cfm index aacaae4..247f311 100644 --- a/test-harness/wires/test/should_call_onuploaderror.cfm +++ b/test-harness/wires/test/should_call_onuploaderror.cfm @@ -7,9 +7,9 @@ "isMultiple": false }; - function onUploadError( name, errors, multiple ) { + function onUploadError( property, errors, multiple ) { data.uploadErrored = true; - data.erroredPropertyName = arguments.name; + data.erroredPropertyName = arguments.property; data.errorInfo = isNull( arguments.errors ) ? "null" : "has errors"; data.isMultiple = arguments.multiple; } From d2ace047d2e23ad33fa4121bcdbd4ee7042ae96b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 10 Oct 2025 15:01:03 +0000 Subject: [PATCH 6/6] Dispatch upload:errored event to trigger JavaScript error handler Co-authored-by: grantcopley <1197835+grantcopley@users.noreply.github.com> --- models/Component.cfc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/models/Component.cfc b/models/Component.cfc index 2b20797..84e0267 100644 --- a/models/Component.cfc +++ b/models/Component.cfc @@ -934,6 +934,13 @@ component output="true" accessors="true" { * @return void */ function _uploadErrored( prop, errors, multiple ) { + // Dispatch the upload errored event + dispatchSelf( + event="upload:errored", + params=[ + "name"=arguments.prop + ] + ); // Check if the component has an onUploadError method and invoke it if ( structKeyExists( this, "onUploadError" ) ) { invoke( this, "onUploadError", {