From e17657ab7ef12b10ff33a3396c67324c575904b0 Mon Sep 17 00:00:00 2001 From: Gustavo Carvalho Date: Fri, 23 Jan 2026 07:02:58 -0300 Subject: [PATCH 1/4] fix: use correct endpoints and batch processing Signed-off-by: Gustavo Carvalho --- .../component-definitions/CapabilityCreateForm.vue | 6 +++--- .../component-definitions/ComponentCreateForm.vue | 4 ++-- src/stores/component-definitions.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/component-definitions/CapabilityCreateForm.vue b/src/components/component-definitions/CapabilityCreateForm.vue index 0efeee8b..ff5b9bcb 100644 --- a/src/components/component-definitions/CapabilityCreateForm.vue +++ b/src/components/component-definitions/CapabilityCreateForm.vue @@ -104,8 +104,8 @@ const capability = ref({ // controlImplementations: [], }); -const { data: newCapability, execute } = useDataApi( - `/api/oscal/component-definitions/${props.componentDefinitionId}/capability`, +const { data: newCapability, execute } = useDataApi( + `/api/oscal/component-definitions/${props.componentDefinitionId}/capabilities`, { method: 'POST', transformRequest: [decamelizeKeys], @@ -142,7 +142,7 @@ async function createCapability(): Promise { await execute({ data: capabilityData, }); - emit('created', newCapability.value!); + emit('created', newCapability.value![0]); } catch (error) { toast.add({ severity: 'error', diff --git a/src/components/component-definitions/ComponentCreateForm.vue b/src/components/component-definitions/ComponentCreateForm.vue index 62f196fa..2791bf9b 100644 --- a/src/components/component-definitions/ComponentCreateForm.vue +++ b/src/components/component-definitions/ComponentCreateForm.vue @@ -116,7 +116,7 @@ const component = ref({ // controlImplementations: [], }); -const { data: createdComponent, execute } = useDataApi( +const { data: createdComponent, execute } = useDataApi( `/api/oscal/component-definitions/${props.componentDefinitionId}/components`, { method: 'POST', transformRequest: [decamelizeKeys] }, { immediate: false }, @@ -164,7 +164,7 @@ async function createComponent(): Promise { detail: `Component ${component.value.title} has been created.`, life: 3000, }); - emit('created', createdComponent.value!); + emit('created', createdComponent.value![0]); } catch (error) { const errorResponse = error as AxiosError>; const errorText = diff --git a/src/stores/component-definitions.ts b/src/stores/component-definitions.ts index f90d669e..a7b92d7c 100644 --- a/src/stores/component-definitions.ts +++ b/src/stores/component-definitions.ts @@ -332,7 +332,7 @@ export const useComponentDefinitionStore = defineStore( const config = await configStore.getConfig(); const payload = decamelizeKeys(capability, { separator: '-' }); const response = await fetch( - `${config.API_URL}/api/oscal/component-definitions/${id}/capability`, + `${config.API_URL}/api/oscal/component-definitions/${id}/capabilities`, { method: 'POST', headers: { From 80b90e6b2f31480e4a0b5f77792bfb96c37c4ee7 Mon Sep 17 00:00:00 2001 From: Gustavo Carvalho Date: Fri, 23 Jan 2026 07:21:34 -0300 Subject: [PATCH 2/4] fix: copilot issues Signed-off-by: Gustavo Carvalho --- .../CapabilityCreateForm.vue | 19 ++++++++++++++++--- .../ComponentCreateForm.vue | 19 ++++++++++++++++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/components/component-definitions/CapabilityCreateForm.vue b/src/components/component-definitions/CapabilityCreateForm.vue index ff5b9bcb..0bb0bf8d 100644 --- a/src/components/component-definitions/CapabilityCreateForm.vue +++ b/src/components/component-definitions/CapabilityCreateForm.vue @@ -104,7 +104,7 @@ const capability = ref({ // controlImplementations: [], }); -const { data: newCapability, execute } = useDataApi( +const { execute } = useDataApi( `/api/oscal/component-definitions/${props.componentDefinitionId}/capabilities`, { method: 'POST', @@ -139,10 +139,23 @@ async function createCapability(): Promise { // Skip incorporatesComponents, controlImplementations - they may not exist in DB schema }; - await execute({ + const response = await execute({ data: capabilityData, }); - emit('created', newCapability.value![0]); + + // Validate response before accessing the first element + if (!response.data.value?.data || response.data.value.data.length === 0) { + throw new Error('No capability was created. Please try again.'); + } + + const createdCapabilityData = response.data.value.data[0]; + + // Validate that the created capability has a UUID + if (!createdCapabilityData.uuid) { + throw new Error('Created capability is missing UUID. Please try again.'); + } + + emit('created', createdCapabilityData); } catch (error) { toast.add({ severity: 'error', diff --git a/src/components/component-definitions/ComponentCreateForm.vue b/src/components/component-definitions/ComponentCreateForm.vue index 2791bf9b..1a342bff 100644 --- a/src/components/component-definitions/ComponentCreateForm.vue +++ b/src/components/component-definitions/ComponentCreateForm.vue @@ -116,7 +116,7 @@ const component = ref({ // controlImplementations: [], }); -const { data: createdComponent, execute } = useDataApi( +const { execute } = useDataApi( `/api/oscal/component-definitions/${props.componentDefinitionId}/components`, { method: 'POST', transformRequest: [decamelizeKeys] }, { immediate: false }, @@ -155,16 +155,29 @@ async function createComponent(): Promise { // Skip responsibleRoles, protocols, controlImplementations - they don't exist in DB schema }; - await execute({ + const response = await execute({ data: [componentData], }); + + // Validate response before accessing the first element + if (!response.data.value?.data || response.data.value.data.length === 0) { + throw new Error('No component was created. Please try again.'); + } + + const createdComponentData = response.data.value.data[0]; + + // Validate that the created component has a UUID + if (!createdComponentData.uuid) { + throw new Error('Created component is missing UUID. Please try again.'); + } + toast.add({ severity: 'success', summary: 'Component created successfully', detail: `Component ${component.value.title} has been created.`, life: 3000, }); - emit('created', createdComponent.value![0]); + emit('created', createdComponentData); } catch (error) { const errorResponse = error as AxiosError>; const errorText = From 11992b364d838ed6c064307523f6fd39d1f896f9 Mon Sep 17 00:00:00 2001 From: Gustavo Carvalho Date: Fri, 23 Jan 2026 07:29:25 -0300 Subject: [PATCH 3/4] fix: copilot issues Signed-off-by: Gustavo Carvalho --- .../CapabilityCreateForm.vue | 10 ++++---- .../ComponentCreateForm.vue | 25 +++++++++++-------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/components/component-definitions/CapabilityCreateForm.vue b/src/components/component-definitions/CapabilityCreateForm.vue index 0bb0bf8d..7f9cca5e 100644 --- a/src/components/component-definitions/CapabilityCreateForm.vue +++ b/src/components/component-definitions/CapabilityCreateForm.vue @@ -104,7 +104,7 @@ const capability = ref({ // controlImplementations: [], }); -const { execute } = useDataApi( +const { data: newCapability, execute } = useDataApi( `/api/oscal/component-definitions/${props.componentDefinitionId}/capabilities`, { method: 'POST', @@ -139,16 +139,16 @@ async function createCapability(): Promise { // Skip incorporatesComponents, controlImplementations - they may not exist in DB schema }; - const response = await execute({ + await execute({ data: capabilityData, }); - // Validate response before accessing the first element - if (!response.data.value?.data || response.data.value.data.length === 0) { + // Wait for the data ref to be updated and validate it + if (!newCapability.value || newCapability.value.length === 0) { throw new Error('No capability was created. Please try again.'); } - const createdCapabilityData = response.data.value.data[0]; + const createdCapabilityData = newCapability.value[0]; // Validate that the created capability has a UUID if (!createdCapabilityData.uuid) { diff --git a/src/components/component-definitions/ComponentCreateForm.vue b/src/components/component-definitions/ComponentCreateForm.vue index 1a342bff..58c617c5 100644 --- a/src/components/component-definitions/ComponentCreateForm.vue +++ b/src/components/component-definitions/ComponentCreateForm.vue @@ -90,8 +90,7 @@ import { BIconArrowRepeat } from 'bootstrap-icons-vue'; import { v4 as uuidv4 } from 'uuid'; import { useToast } from 'primevue/usetoast'; import { useDataApi, decamelizeKeys } from '@/composables/axios'; -import type { AxiosError } from 'axios'; -import type { ErrorBody, ErrorResponse } from '@/stores/types'; +import { AxiosError } from 'axios'; const toast = useToast(); @@ -116,7 +115,7 @@ const component = ref({ // controlImplementations: [], }); -const { execute } = useDataApi( +const { data: createdComponent, execute } = useDataApi( `/api/oscal/component-definitions/${props.componentDefinitionId}/components`, { method: 'POST', transformRequest: [decamelizeKeys] }, { immediate: false }, @@ -155,16 +154,16 @@ async function createComponent(): Promise { // Skip responsibleRoles, protocols, controlImplementations - they don't exist in DB schema }; - const response = await execute({ + await execute({ data: [componentData], }); - // Validate response before accessing the first element - if (!response.data.value?.data || response.data.value.data.length === 0) { + // Wait for the data ref to be updated and validate it + if (!createdComponent.value || createdComponent.value.length === 0) { throw new Error('No component was created. Please try again.'); } - const createdComponentData = response.data.value.data[0]; + const createdComponentData = createdComponent.value[0]; // Validate that the created component has a UUID if (!createdComponentData.uuid) { @@ -179,10 +178,14 @@ async function createComponent(): Promise { }); emit('created', createdComponentData); } catch (error) { - const errorResponse = error as AxiosError>; - const errorText = - errorResponse.response?.data.errors.body || - 'An error occurred while creating the component.'; + let errorText = 'An error occurred while creating the component.'; + + if (error instanceof AxiosError) { + errorText = error.response?.data.errors.body || errorText; + } else if (error instanceof Error) { + errorText = error.message; + } + toast.add({ severity: 'error', summary: 'Error creating component', From 7724ff372265a6424aaf77361cb1b2d67d84d706 Mon Sep 17 00:00:00 2001 From: Gustavo Carvalho Date: Fri, 23 Jan 2026 07:40:18 -0300 Subject: [PATCH 4/4] fix: this time copilot was dumb and told us to reimplement ffs Signed-off-by: Gustavo Carvalho --- .../CapabilityCreateForm.vue | 10 +++++----- .../ComponentCreateForm.vue | 16 ++++++++++------ 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/components/component-definitions/CapabilityCreateForm.vue b/src/components/component-definitions/CapabilityCreateForm.vue index 7f9cca5e..d12bb4b4 100644 --- a/src/components/component-definitions/CapabilityCreateForm.vue +++ b/src/components/component-definitions/CapabilityCreateForm.vue @@ -104,7 +104,7 @@ const capability = ref({ // controlImplementations: [], }); -const { data: newCapability, execute } = useDataApi( +const { execute } = useDataApi( `/api/oscal/component-definitions/${props.componentDefinitionId}/capabilities`, { method: 'POST', @@ -139,16 +139,16 @@ async function createCapability(): Promise { // Skip incorporatesComponents, controlImplementations - they may not exist in DB schema }; - await execute({ + const response = await execute({ data: capabilityData, }); - // Wait for the data ref to be updated and validate it - if (!newCapability.value || newCapability.value.length === 0) { + // Use response data directly to avoid race condition with data ref updates + if (!response.data.value?.data || response.data.value.data.length === 0) { throw new Error('No capability was created. Please try again.'); } - const createdCapabilityData = newCapability.value[0]; + const createdCapabilityData = response.data.value.data[0]; // Validate that the created capability has a UUID if (!createdCapabilityData.uuid) { diff --git a/src/components/component-definitions/ComponentCreateForm.vue b/src/components/component-definitions/ComponentCreateForm.vue index 58c617c5..7c02e9c7 100644 --- a/src/components/component-definitions/ComponentCreateForm.vue +++ b/src/components/component-definitions/ComponentCreateForm.vue @@ -115,7 +115,7 @@ const component = ref({ // controlImplementations: [], }); -const { data: createdComponent, execute } = useDataApi( +const { execute } = useDataApi( `/api/oscal/component-definitions/${props.componentDefinitionId}/components`, { method: 'POST', transformRequest: [decamelizeKeys] }, { immediate: false }, @@ -154,16 +154,16 @@ async function createComponent(): Promise { // Skip responsibleRoles, protocols, controlImplementations - they don't exist in DB schema }; - await execute({ + const response = await execute({ data: [componentData], }); - // Wait for the data ref to be updated and validate it - if (!createdComponent.value || createdComponent.value.length === 0) { + // Use response data directly to avoid race condition with data ref updates + if (!response.data.value?.data || response.data.value.data.length === 0) { throw new Error('No component was created. Please try again.'); } - const createdComponentData = createdComponent.value[0]; + const createdComponentData = response.data.value.data[0]; // Validate that the created component has a UUID if (!createdComponentData.uuid) { @@ -181,7 +181,11 @@ async function createComponent(): Promise { let errorText = 'An error occurred while creating the component.'; if (error instanceof AxiosError) { - errorText = error.response?.data.errors.body || errorText; + const axiosError = error as AxiosError<{ errors?: { body?: string } }>; + const bodyMessage = axiosError.response?.data?.errors?.body; + if (typeof bodyMessage === 'string' && bodyMessage.trim().length > 0) { + errorText = bodyMessage; + } } else if (error instanceof Error) { errorText = error.message; }