From b8073c70fb370a6dfc75a9d72728cd8eb49066a2 Mon Sep 17 00:00:00 2001 From: Oleg Ivaniv Date: Tue, 12 Nov 2024 19:19:39 +0100 Subject: [PATCH] Refactor evaluation form and improve error handling in workflow evaluation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit • Remove dependency on tagsStore • Add field-specific error handling • Simplify loadTestData and saveTest methods • Update EvaluationEditView component • Improve UI feedback for form errors --- .../composables/useEvaluationForm.ts | 43 ++++++++----------- .../WorkflowEvaluation/EvaluationEditView.vue | 39 +++++++++++------ 2 files changed, 45 insertions(+), 37 deletions(-) diff --git a/packages/editor-ui/src/components/WorkflowEvaluation/composables/useEvaluationForm.ts b/packages/editor-ui/src/components/WorkflowEvaluation/composables/useEvaluationForm.ts index 3db71634a0..5809a596cb 100644 --- a/packages/editor-ui/src/components/WorkflowEvaluation/composables/useEvaluationForm.ts +++ b/packages/editor-ui/src/components/WorkflowEvaluation/composables/useEvaluationForm.ts @@ -1,7 +1,6 @@ import { ref, computed } from 'vue'; import type { ComponentPublicInstance } from 'vue'; import type { INodeParameterResourceLocator } from 'n8n-workflow'; -import { useAnnotationTagsStore } from '@/stores/tags.store'; import { useEvaluationsStore } from '@/stores/evaluations.store.ee'; import type AnnotationTagsDropdownEe from '@/components/AnnotationTagsDropdown.ee.vue'; import type { N8nInput } from 'n8n-design-system'; @@ -28,9 +27,8 @@ type FormRefs = { tagsInput: ComponentPublicInstance; }; -export function useEvaluationForm(testId?: number) { +export function useEvaluationForm() { // Stores - const tagsStore = useAnnotationTagsStore(); const evaluationsStore = useEvaluationsStore(); // Form state @@ -55,20 +53,16 @@ export function useEvaluationForm(testId?: number) { // Loading states const isSaving = ref(false); - const isLoading = computed(() => tagsStore.isLoading); + const fieldsIssues = ref>([]); // Computed - const isEditing = computed(() => !!testId); - const allTags = computed(() => tagsStore.allTags); - const tagsById = computed(() => tagsStore.tagsById); + // const isEditing = computed(() => !!testId); // Field refs const fields = ref({} as FormRefs); // Methods - const loadTestData = async () => { - if (!testId) return; - + const loadTestData = async (testId: number) => { try { await evaluationsStore.fetchAll({ force: true }); const testDefinition = evaluationsStore.testDefinitionsById[testId]; @@ -99,11 +93,16 @@ export function useEvaluationForm(testId?: number) { } }; - const saveTest = async () => { + const saveTest = async (testId?: number) => { if (isSaving.value) return; isSaving.value = true; + fieldsIssues.value = []; try { + if (!state.value.evaluationWorkflow.value) { + addFieldIssue('evaluationWorkflow', 'Evaluation workflow is required'); + } + const params = { name: state.value.name.value, ...(state.value.tags.appliedTagIds[0] && { @@ -114,7 +113,7 @@ export function useEvaluationForm(testId?: number) { }), }; - if (isEditing.value && testId) { + if (testId) { await evaluationsStore.update({ id: testId, ...params, @@ -132,6 +131,10 @@ export function useEvaluationForm(testId?: number) { } }; + const addFieldIssue = (field: string, message: string) => { + fieldsIssues.value.push({ field, message }); + }; + const startEditing = async (field: string) => { if (field === 'name') { state.value.name.tempValue = state.value.name.value; @@ -167,22 +170,12 @@ export function useEvaluationForm(testId?: number) { } }; - const init = async () => { - await tagsStore.fetchAll(); - if (testId) { - await loadTestData(); - } - }; - return { state, fields, - isEditing, - isLoading, - isSaving, - allTags, - tagsById, - init, + isSaving: computed(() => isSaving.value), + fieldsIssues: computed(() => fieldsIssues.value), + loadTestData, saveTest, startEditing, saveChanges, diff --git a/packages/editor-ui/src/views/WorkflowEvaluation/EvaluationEditView.vue b/packages/editor-ui/src/views/WorkflowEvaluation/EvaluationEditView.vue index 9b29fb1468..05bb4e5a13 100644 --- a/packages/editor-ui/src/views/WorkflowEvaluation/EvaluationEditView.vue +++ b/packages/editor-ui/src/views/WorkflowEvaluation/EvaluationEditView.vue @@ -10,6 +10,7 @@ import WorkflowSelector from '@/components/WorkflowEvaluation/EditEvaluation/Wor import MetricsInput from '@/components/WorkflowEvaluation/EditEvaluation/MetricsInput.vue'; import { useEvaluationForm } from '@/components/WorkflowEvaluation/composables/useEvaluationForm'; import { useI18n } from '@/composables/useI18n'; +import { useAnnotationTagsStore } from '@/stores/tags.store'; const props = defineProps<{ testId?: number; @@ -20,33 +21,36 @@ const route = useRoute(); const locale = useI18n(); const testId = computed(() => props.testId ?? (route.params.testId as unknown as number)); const buttonLabel = computed(() => - isEditing.value + // No testId means we're creating a new one + testId.value ? locale.baseText('workflowEvaluation.edit.updateTest') : locale.baseText('workflowEvaluation.edit.saveTest'), ); const toast = useToast(); const { state, - isEditing, - isLoading, + fieldsIssues, isSaving, - allTags, - tagsById, - init, + loadTestData, saveTest, startEditing, saveChanges, cancelEditing, handleKeydown, -} = useEvaluationForm(testId.value); +} = useEvaluationForm(); -onMounted(() => { - void init(); +const { isLoading, allTags, tagsById, fetchAll } = useAnnotationTagsStore(); + +onMounted(async () => { + await fetchAll(); + if (testId.value) { + await loadTestData(testId.value); + } }); async function onSaveTest() { try { - await saveTest(); + await saveTest(testId.value); toast.showMessage({ title: locale.baseText('workflowEvaluation.edit.testSaved'), type: 'success', @@ -56,12 +60,19 @@ async function onSaveTest() { toast.showError(e, locale.baseText('workflowEvaluation.edit.testSaveFailed')); } } + +function hasIssues(key: string) { + const result = fieldsIssues.value.some((issue) => issue.field === key); + + return result; +}