n8n-editor-ui
Version:
Workflow Editor UI for n8n
394 lines (393 loc) • 18.2 kB
JavaScript
import { o as __toESM } from "./chunk-6z4oVpB-.js";
import { C as computed, Cn as toDisplayString, D as createElementBlock, E as createCommentVNode, Gt as unref, It as ref, M as createVNode, P as defineComponent, T as createBlock, Z as onMounted, _ as Fragment, bt as withCtx, et as openBlock, h as withModifiers, it as renderList, j as createTextVNode, vn as normalizeClass, w as createBaseVNode } from "./vue.runtime.esm-bundler-tP5dCd7J.js";
import { _t as useI18n } from "./_MapCache-ficiegRb.js";
import { G as N8nExternalLink_default, Ht as ElScrollbar, at as N8nLoading_default, bn as N8nCallout_default, ht as N8nTooltip_default, l as TableHeaderControlsButton_default, wn as N8nIcon_default, xn as N8nText_default, xt as N8nIconButton_default, yn as N8nHeading_default } from "./src-DgvumQTi.js";
import "./en-CF30SCh2.js";
import "./preload-helper-CR0ecmWK.js";
import { t as __plugin_vue_export_helper_default } from "./_plugin-vue_export-helper-BwBpWJRZ.js";
import { y as useRouter } from "./truncate-B1HVeveJ.js";
import "./_initCloneObject-Al9ZJ6PX.js";
import "./table-DzZuElSR.js";
import { Ft as useEvaluationStore, N as useWorkflowsStore, v as useToast } from "./builder.store-sBTWwxRU.js";
import "./empty-BuGRxzl4.js";
import "./sanitize-html-Cc45ZKm8.js";
import "./CalendarDate-zWqgZMlk.js";
import "./path-browserify-BtCDmZ3_.js";
import { Ro as VIEWS } from "./constants-BbpucWL4.js";
import "./merge-k8vSyyXH.js";
import "./_baseOrderBy-B_6CV8x6.js";
import "./dateformat-CM9k0--B.js";
import "./useDebounce-Bnb8W2LR.js";
import { t as convertToDisplayDate } from "./dateFormatter-DDfPHI9I.js";
import { t as require_orderBy } from "./orderBy-EuatZUAl.js";
import { t as useWorkflowSettingsCache } from "./useWorkflowsCache-K84an3SQ.js";
import { a as applyCachedVisibility, c as getTestTableHeaders, i as applyCachedSortOrder, n as statusDictionary, o as getDefaultOrderedColumns, r as TestTableBase_default, s as getTestCasesColumns, t as getErrorBaseKey } from "./evaluation.constants-CJqUkQ3G.js";
var import_orderBy = /* @__PURE__ */ __toESM(require_orderBy());
var _hoisted_1 = { style: { "display": "flex" } };
var _hoisted_2 = { style: {
"display": "flex",
"justify-content": "space-between",
"gap": "10px"
} };
var _hoisted_3 = { style: {
"display": "inline-flex",
"gap": "12px",
"align-items": "center",
"max-width": "100%"
} };
var TestRunDetailView_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "TestRunDetailView",
setup(__props) {
const router = useRouter();
const toast = useToast();
const evaluationStore = useEvaluationStore();
const workflowsStore = useWorkflowsStore();
const locale = useI18n();
const workflowsCache = useWorkflowSettingsCache();
const isLoading = ref(true);
const testCases = ref([]);
const hasFailedTestCases = ref(false);
const runId = computed(() => router.currentRoute.value.params.runId);
const workflowId = computed(() => router.currentRoute.value.params.name);
const workflowName = computed(() => workflowsStore.getWorkflowById(workflowId.value)?.name ?? "");
const cachedUserPreferences = ref();
const expandedRows = ref(/* @__PURE__ */ new Set());
const run = computed(() => evaluationStore.testRunsById[runId.value]);
const runErrorDetails = computed(() => {
return run.value?.errorDetails;
});
const filteredTestCases = computed(() => (0, import_orderBy.default)(testCases.value, (record) => record.runAt, ["asc"]).map((record, index) => Object.assign(record, { index: index + 1 })));
const isAllExpanded = computed(() => expandedRows.value.size === filteredTestCases.value.length);
const testRunIndex = computed(() => Object.values((0, import_orderBy.default)(evaluationStore.testRunsById, (record) => new Date(record.runAt), ["asc"]).filter(({ workflowId: wId }) => wId === workflowId.value) ?? {}).findIndex(({ id }) => id === runId.value));
const formattedTime = computed(() => convertToDisplayDate(new Date(run.value?.runAt).getTime()));
const openRelatedExecution = (row) => {
const executionId = row.executionId;
if (executionId) {
const { href } = router.resolve({
name: VIEWS.EXECUTION_PREVIEW,
params: {
name: workflowId.value,
executionId
}
});
window.open(href, "_blank");
}
};
const inputColumns = computed(() => getTestCasesColumns(filteredTestCases.value, "inputs"));
const orderedColumns = computed(() => {
return applyCachedVisibility(applyCachedSortOrder(getDefaultOrderedColumns(run.value, filteredTestCases.value), cachedUserPreferences.value?.order), cachedUserPreferences.value?.visibility);
});
const columns = computed(() => [
{
prop: "index",
width: 100,
label: locale.baseText("evaluation.runDetail.testCase"),
sortable: true
},
{
prop: "status",
label: locale.baseText("evaluation.listRuns.status"),
minWidth: 125
},
...getTestTableHeaders(orderedColumns.value, filteredTestCases.value)
]);
const metrics = computed(() => run.value?.metrics ?? {});
const fetchExecutionTestCases = async () => {
if (!runId.value || !workflowId.value) return;
isLoading.value = true;
try {
const testRun = await evaluationStore.getTestRun({
workflowId: workflowId.value,
runId: runId.value
});
const testCaseEvaluationExecutions = await evaluationStore.fetchTestCaseExecutions({
workflowId: workflowId.value,
runId: testRun.id
});
testCases.value = testCaseEvaluationExecutions ?? [];
hasFailedTestCases.value = testCaseEvaluationExecutions?.some((testCase) => testCase.status === "error");
await evaluationStore.fetchTestRuns(run.value.workflowId);
} catch (error) {
toast.showError(error, locale.baseText("evaluation.listRuns.toast.error.fetchTestCases"));
} finally {
isLoading.value = false;
}
};
async function loadCachedUserPreferences() {
cachedUserPreferences.value = await workflowsCache.getEvaluationPreferences(workflowId.value);
}
async function saveCachedUserPreferences() {
if (cachedUserPreferences.value) await workflowsCache.saveEvaluationPreferences(workflowId.value, cachedUserPreferences.value);
}
async function handleColumnVisibilityUpdate(columnKey, visibility) {
cachedUserPreferences.value ??= {
order: [],
visibility: {}
};
cachedUserPreferences.value.visibility[columnKey] = visibility;
await saveCachedUserPreferences();
}
async function handleColumnOrderUpdate(newOrder) {
cachedUserPreferences.value ??= {
order: [],
visibility: {}
};
cachedUserPreferences.value.order = newOrder;
await saveCachedUserPreferences();
}
function toggleRowExpansion(row) {
if (expandedRows.value.has(row.id)) expandedRows.value.delete(row.id);
else expandedRows.value.add(row.id);
}
function toggleAllExpansion() {
if (isAllExpanded.value) expandedRows.value.clear();
else expandedRows.value = new Set(filteredTestCases.value.map((row) => row.id));
}
onMounted(async () => {
await fetchExecutionTestCases();
await loadCachedUserPreferences();
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", {
class: normalizeClass(_ctx.$style.container),
"data-test-id": "test-definition-run-detail"
}, [
createBaseVNode("div", { class: normalizeClass(_ctx.$style.header) }, [
createBaseVNode("button", {
class: normalizeClass(_ctx.$style.backButton),
onClick: _cache[0] || (_cache[0] = ($event) => unref(router).back())
}, [createVNode(unref(N8nIcon_default), { icon: "arrow-left" }), createVNode(unref(N8nHeading_default), {
size: "large",
bold: true
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(locale).baseText("evaluation.listRuns.runListHeader", { interpolate: { name: workflowName.value } })), 1)]),
_: 1
})], 2),
createBaseVNode("span", { class: normalizeClass(_ctx.$style.headerSeparator) }, "/", 2),
createVNode(unref(N8nHeading_default), {
size: "large",
bold: true
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(locale).baseText("evaluation.listRuns.testCasesListHeader", { interpolate: { index: testRunIndex.value + 1 } })), 1)]),
_: 1
})
], 2),
run.value?.status === "error" ? (openBlock(), createBlock(unref(N8nCallout_default), {
key: 0,
theme: "danger",
icon: "triangle-alert",
class: "mb-s"
}, {
default: withCtx(() => [createVNode(unref(N8nText_default), {
size: "small",
class: normalizeClass(_ctx.$style.capitalized)
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(locale).baseText(`${unref(getErrorBaseKey)(run.value?.errorCode)}`, runErrorDetails.value ? { interpolate: runErrorDetails.value } : {}) ?? unref(locale).baseText(`${unref(getErrorBaseKey)("UNKNOWN_ERROR")}`)), 1)]),
_: 1
}, 8, ["class"])]),
_: 1
})) : createCommentVNode("", true),
createVNode(unref(ElScrollbar), {
always: "",
class: normalizeClass([_ctx.$style.scrollableSummary, "mb-m"])
}, {
default: withCtx(() => [createBaseVNode("div", _hoisted_1, [
createBaseVNode("div", { class: normalizeClass(_ctx.$style.summaryCard) }, [createVNode(unref(N8nText_default), {
size: "small",
class: normalizeClass(_ctx.$style.summaryCardTitle)
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(locale).baseText("evaluation.runDetail.totalCases")), 1)]),
_: 1
}, 8, ["class"]), createVNode(unref(N8nText_default), {
size: "xlarge",
class: normalizeClass(_ctx.$style.summaryCardContentLargeNumber),
bold: ""
}, {
default: withCtx(() => [createTextVNode(toDisplayString(testCases.value.length), 1)]),
_: 1
}, 8, ["class"])], 2),
createBaseVNode("div", { class: normalizeClass(_ctx.$style.summaryCard) }, [createVNode(unref(N8nText_default), {
size: "small",
class: normalizeClass(_ctx.$style.summaryCardTitle)
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(locale).baseText("evaluation.runDetail.ranAt")), 1)]),
_: 1
}, 8, ["class"]), createBaseVNode("div", null, [createVNode(unref(N8nText_default), { size: "medium" }, {
default: withCtx(() => [createTextVNode(toDisplayString(formattedTime.value.date) + " " + toDisplayString(formattedTime.value.time), 1)]),
_: 1
})])], 2),
createBaseVNode("div", { class: normalizeClass(_ctx.$style.summaryCard) }, [createVNode(unref(N8nText_default), {
size: "small",
class: normalizeClass(_ctx.$style.summaryCardTitle)
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(locale).baseText("evaluation.listRuns.status")), 1)]),
_: 1
}, 8, ["class"]), run.value?.status === "completed" && hasFailedTestCases.value ? (openBlock(), createBlock(unref(N8nText_default), {
key: 0,
size: "medium",
color: "warning"
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(locale).baseText(`evaluation.runDetail.error.partialCasesFailed`)), 1)]),
_: 1
})) : (openBlock(), createBlock(unref(N8nText_default), {
key: 1,
color: unref(statusDictionary)[run.value?.status]?.color,
size: "medium",
class: normalizeClass(run.value?.status.toLowerCase()),
style: { "text-transform": "capitalize" }
}, {
default: withCtx(() => [createTextVNode(toDisplayString(run.value?.status), 1)]),
_: 1
}, 8, ["color", "class"]))], 2),
(openBlock(true), createElementBlock(Fragment, null, renderList(metrics.value, (value, key) => {
return openBlock(), createElementBlock("div", {
key,
class: normalizeClass(_ctx.$style.summaryCard)
}, [createVNode(unref(N8nTooltip_default), {
content: key,
placement: "top"
}, {
default: withCtx(() => [createVNode(unref(N8nText_default), {
size: "small",
class: normalizeClass(_ctx.$style.summaryCardTitle),
style: {
"text-overflow": "ellipsis",
"overflow": "hidden"
}
}, {
default: withCtx(() => [createTextVNode(toDisplayString(key), 1)]),
_: 2
}, 1032, ["class"])]),
_: 2
}, 1032, ["content"]), createVNode(unref(N8nText_default), {
size: "xlarge",
class: normalizeClass(_ctx.$style.summaryCardContentLargeNumber),
bold: ""
}, {
default: withCtx(() => [createTextVNode(toDisplayString(value.toFixed(2)), 1)]),
_: 2
}, 1032, ["class"])], 2);
}), 128))
])]),
_: 1
}, 8, ["class"]),
createBaseVNode("div", { class: normalizeClass(["mb-s", _ctx.$style.runsHeader]) }, [createBaseVNode("div", null, [createVNode(unref(N8nHeading_default), {
size: "large",
bold: true
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(locale).baseText("evaluation.listRuns.allTestCases", { interpolate: { count: filteredTestCases.value.length } })), 1)]),
_: 1
})]), createBaseVNode("div", { class: normalizeClass(_ctx.$style.runsHeaderButtons) }, [createVNode(unref(N8nIconButton_default), {
icon: isAllExpanded.value ? "chevrons-down-up" : "chevrons-up-down",
type: "secondary",
size: "medium",
onClick: toggleAllExpansion
}, null, 8, ["icon"]), createVNode(unref(TableHeaderControlsButton_default), {
size: "medium",
"icon-size": "small",
columns: orderedColumns.value,
"onUpdate:columnVisibility": handleColumnVisibilityUpdate,
"onUpdate:columnOrder": handleColumnOrderUpdate
}, null, 8, ["columns"])], 2)], 2),
!isLoading.value && !inputColumns.value.length && run.value?.status === "completed" && run.value?.finalResult === "success" ? (openBlock(), createBlock(unref(N8nCallout_default), {
key: 1,
theme: "secondary",
icon: "info",
class: "mb-s"
}, {
default: withCtx(() => [createVNode(unref(N8nText_default), {
size: "small",
class: normalizeClass(_ctx.$style.capitalized)
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(locale).baseText("evaluation.runDetail.notice.useSetInputs")), 1)]),
_: 1
}, 8, ["class"])]),
_: 1
})) : createCommentVNode("", true),
isLoading.value ? (openBlock(), createElementBlock("div", {
key: 2,
class: normalizeClass(_ctx.$style.loading)
}, [createVNode(unref(N8nLoading_default), {
loading: true,
rows: 5
})], 2)) : (openBlock(), createBlock(TestTableBase_default, {
key: 3,
data: filteredTestCases.value,
columns: columns.value,
"default-sort": {
prop: "id",
order: "descending"
},
"expanded-rows": expandedRows.value,
onRowClick: toggleRowExpansion
}, {
id: withCtx(({ row }) => [createBaseVNode("div", _hoisted_2, toDisplayString(row.id), 1)]),
index: withCtx(({ row }) => [createBaseVNode("div", null, [row.executionId ? (openBlock(), createBlock(unref(N8nExternalLink_default), {
key: 0,
class: "open-execution-link",
onClick: withModifiers(($event) => openRelatedExecution(row), ["stop", "prevent"])
}, {
default: withCtx(() => [createTextVNode(" #" + toDisplayString(row.index), 1)]),
_: 2
}, 1032, ["onClick"])) : (openBlock(), createElementBlock("span", {
key: 1,
class: normalizeClass(_ctx.$style.deletedExecutionRowIndex)
}, "#" + toDisplayString(row.index), 3))])]),
status: withCtx(({ row }) => [createBaseVNode("div", _hoisted_3, [createVNode(unref(N8nIcon_default), {
icon: unref(statusDictionary)[row.status].icon,
color: unref(statusDictionary)[row.status].color
}, null, 8, ["icon", "color"]), row.status === "error" ? (openBlock(), createBlock(unref(N8nTooltip_default), {
key: 0,
placement: "top",
"show-after": 300
}, {
content: withCtx(() => [createTextVNode(toDisplayString(unref(locale).baseText(`${unref(getErrorBaseKey)(row.errorCode)}`) || row.status), 1)]),
default: withCtx(() => [createVNode(unref(N8nText_default), {
color: "danger",
class: normalizeClass(_ctx.$style.capitalized)
}, {
default: withCtx(() => [createTextVNode(toDisplayString(unref(locale).baseText(`${unref(getErrorBaseKey)(row.errorCode)}`) || row.status), 1)]),
_: 2
}, 1032, ["class"])]),
_: 2
}, 1024)) : (openBlock(), createBlock(unref(N8nText_default), {
key: 1,
class: normalizeClass(_ctx.$style.capitalized)
}, {
default: withCtx(() => [createTextVNode(toDisplayString(row.status), 1)]),
_: 2
}, 1032, ["class"]))])]),
_: 1
}, 8, [
"data",
"columns",
"expanded-rows"
]))
], 2);
};
}
});
var TestRunDetailView_vue_vue_type_style_index_1_lang_module_default = {
container: "_container_8z68v_123",
header: "_header_8z68v_130",
timestamp: "_timestamp_8z68v_136",
backButton: "_backButton_8z68v_141",
headerSeparator: "_headerSeparator_8z68v_156",
summary: "_summary_8z68v_161",
summaryStats: "_summaryStats_8z68v_164",
stat: "_stat_8z68v_169",
controls: "_controls_8z68v_174",
downloadButton: "_downloadButton_8z68v_180",
runsHeader: "_runsHeader_8z68v_184",
runsHeaderButtons: "_runsHeaderButtons_8z68v_191",
loading: "_loading_8z68v_196",
scrollableSummary: "_scrollableSummary_8z68v_203",
summaryCard: "_summaryCard_8z68v_218",
capitalized: "_capitalized_8z68v_235",
summaryCardTitle: "_summaryCardTitle_8z68v_243",
summaryCardContentLargeNumber: "_summaryCardContentLargeNumber_8z68v_254",
alertText: "_alertText_8z68v_259",
deletedExecutionRowIndex: "_deletedExecutionRowIndex_8z68v_274"
};
var TestRunDetailView_default = /* @__PURE__ */ __plugin_vue_export_helper_default(TestRunDetailView_vue_vue_type_script_setup_true_lang_default, [["__cssModules", { "$style": TestRunDetailView_vue_vue_type_style_index_1_lang_module_default }], ["__scopeId", "data-v-fd115f6f"]]);
export { TestRunDetailView_default as default };