feat(editor): Evaluations frontend (no-changelog) (#15550)

Co-authored-by: Yiorgis Gozadinos <yiorgis@n8n.io>
Co-authored-by: JP van Oosten <jp@n8n.io>
Co-authored-by: Giulio Andreini <g.andreini@gmail.com>
Co-authored-by: Michael Kret <michael.k@radency.com>
This commit is contained in:
Eugene
2025-05-26 12:26:28 +02:00
committed by GitHub
parent 3ee15a8331
commit ca8f087a47
87 changed files with 3460 additions and 5103 deletions

View File

@@ -0,0 +1,106 @@
<script setup lang="ts" generic="T">
import N8nTooltip from '@n8n/design-system/components/N8nTooltip';
import type { BaseTextKey } from '@/plugins/i18n';
import type { TestTableColumn } from '@/components/Evaluations.ee/shared/TestTableBase.vue';
import { useI18n } from '@/composables/useI18n';
import { useRouter } from 'vue-router';
defineProps<{
column: TestTableColumn<T>;
row: T & { status: string };
}>();
const locale = useI18n();
const router = useRouter();
interface WithError {
errorCode: string;
}
function hasError(row: unknown): row is WithError {
return typeof row === 'object' && row !== null && 'errorCode' in row;
}
const errorTooltipMap: Record<string, BaseTextKey> = {
// Test case errors
MOCKED_NODE_NOT_FOUND: 'evaluation.runDetail.error.mockedNodeMissing',
FAILED_TO_EXECUTE_WORKFLOW: 'evaluation.runDetail.error.executionFailed',
INVALID_METRICS: 'evaluation.runDetail.error.invalidMetrics',
// Test run errors
TEST_CASES_NOT_FOUND: 'evaluation.listRuns.error.testCasesNotFound',
EVALUATION_TRIGGER_NOT_FOUND: 'evaluation.listRuns.error.evaluationTriggerNotFound',
EVALUATION_TRIGGER_NOT_CONFIGURED: 'evaluation.listRuns.error.evaluationTriggerNotConfigured',
SET_OUTPUTS_NODE_NOT_FOUND: 'evaluation.listRuns.error.setOutputsNodeNotFound',
SET_OUTPUTS_NODE_NOT_CONFIGURED: 'evaluation.listRuns.error.setOutputsNodeNotConfigured',
SET_METRICS_NODE_NOT_FOUND: 'evaluation.listRuns.error.setMetricsNodeNotFound',
SET_METRICS_NODE_NOT_CONFIGURED: 'evaluation.listRuns.error.setMetricsNodeNotConfigured',
CANT_FETCH_TEST_CASES: 'evaluation.listRuns.error.cantFetchTestCases',
};
// FIXME: move status logic to a parent component
const statusThemeMap: Record<string, string> = {
new: 'default',
running: 'warning',
evaluation_running: 'warning',
completed: 'success',
error: 'danger',
success: 'success',
warning: 'warning',
cancelled: 'default',
};
const statusLabelMap: Record<string, string> = {
new: locale.baseText('evaluation.listRuns.status.new'),
running: locale.baseText('evaluation.listRuns.status.running'),
evaluation_running: locale.baseText('evaluation.listRuns.status.evaluating'),
completed: locale.baseText('evaluation.listRuns.status.completed'),
error: locale.baseText('evaluation.listRuns.status.error'),
success: locale.baseText('evaluation.listRuns.status.success'),
warning: locale.baseText('evaluation.listRuns.status.warning'),
cancelled: locale.baseText('evaluation.listRuns.status.cancelled'),
};
function getErrorTooltip(column: TestTableColumn<T>, row: T): string | undefined {
if (hasError(row) && errorTooltipMap[row.errorCode]) {
const tooltipLinkUrl = getErrorTooltipUrl(column, row);
if (tooltipLinkUrl) {
return locale.baseText(errorTooltipMap[row.errorCode], {
interpolate: {
url: tooltipLinkUrl,
},
});
} else {
return locale.baseText(errorTooltipMap[row.errorCode]);
}
}
return undefined;
}
function getErrorTooltipUrl(column: TestTableColumn<T>, row: T): string | undefined {
if (hasError(row) && column.errorRoute?.(row)) {
return router.resolve(column.errorRoute(row)!).href;
}
return undefined;
}
</script>
<template>
<N8nTooltip
placement="right"
:show-after="300"
:disabled="getErrorTooltip(column, row) === undefined"
>
<template #content>
<div v-n8n-html="getErrorTooltip(column, row)" />
</template>
<N8nBadge :theme="statusThemeMap[row.status]" class="mr-4xs">
{{ statusLabelMap[row.status] }}
</N8nBadge>
</N8nTooltip>
</template>
<style scoped lang="scss"></style>