mirror of
https://github.com/n8n-io/n8n.git
synced 2024-11-14 16:44:07 -08:00
Implement feature flag for workflow evaluation experiment
- Add feature flag check - Update UI to show/hide evaluation tab - Fetch tags for test definitions - Handle routing when feature is disabled - Cleanup console logs
This commit is contained in:
parent
7adfbd236c
commit
44b8fab493
|
@ -9,6 +9,7 @@ import {
|
|||
PLACEHOLDER_EMPTY_WORKFLOW_ID,
|
||||
STICKY_NODE_TYPE,
|
||||
VIEWS,
|
||||
WORKFLOW_EVALUATION_EXPERIMENT,
|
||||
} from '@/constants';
|
||||
import { useI18n } from '@/composables/useI18n';
|
||||
import { useNDVStore } from '@/stores/ndv.store';
|
||||
|
@ -17,6 +18,7 @@ import { useUIStore } from '@/stores/ui.store';
|
|||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||
import { useExecutionsStore } from '@/stores/executions.store';
|
||||
import { usePushConnection } from '@/composables/usePushConnection';
|
||||
import { usePostHog } from '@/stores/posthog.store';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
@ -27,17 +29,24 @@ const uiStore = useUIStore();
|
|||
const sourceControlStore = useSourceControlStore();
|
||||
const workflowsStore = useWorkflowsStore();
|
||||
const executionsStore = useExecutionsStore();
|
||||
const posthogStore = usePostHog();
|
||||
|
||||
const activeHeaderTab = ref(MAIN_HEADER_TABS.WORKFLOW);
|
||||
const workflowToReturnTo = ref('');
|
||||
const executionToReturnTo = ref('');
|
||||
const dirtyState = ref(false);
|
||||
|
||||
const tabBarItems = computed(() => [
|
||||
{ value: MAIN_HEADER_TABS.WORKFLOW, label: locale.baseText('generic.editor') },
|
||||
{ value: MAIN_HEADER_TABS.EXECUTIONS, label: locale.baseText('generic.executions') },
|
||||
{ value: MAIN_HEADER_TABS.EVALUATION, label: locale.baseText('generic.tests') },
|
||||
]);
|
||||
const tabBarItems = computed(() => {
|
||||
const items = [
|
||||
{ value: MAIN_HEADER_TABS.WORKFLOW, label: locale.baseText('generic.editor') },
|
||||
{ value: MAIN_HEADER_TABS.EXECUTIONS, label: locale.baseText('generic.executions') },
|
||||
];
|
||||
|
||||
if (posthogStore.isFeatureEnabled(WORKFLOW_EVALUATION_EXPERIMENT)) {
|
||||
items.push({ value: MAIN_HEADER_TABS.EVALUATION, label: locale.baseText('generic.tests') });
|
||||
}
|
||||
return items;
|
||||
});
|
||||
|
||||
const activeNode = computed(() => ndvStore.activeNode);
|
||||
const hideMenuBar = computed(() =>
|
||||
|
@ -68,7 +77,6 @@ onMounted(async () => {
|
|||
});
|
||||
|
||||
function syncTabsWithRoute(to: RouteLocation, from?: RouteLocation): void {
|
||||
console.log('🚀 ~ syncTabsWithRoute ~ to.name:', to.name);
|
||||
if (to.name === VIEWS.WORKFLOW_EVALUATION) {
|
||||
activeHeaderTab.value = MAIN_HEADER_TABS.EVALUATION;
|
||||
}
|
||||
|
|
|
@ -702,6 +702,8 @@ export const EXPERIMENTS_TO_TRACK = [
|
|||
CREDENTIAL_DOCS_EXPERIMENT.name,
|
||||
];
|
||||
|
||||
export const WORKFLOW_EVALUATION_EXPERIMENT = '025_workflow_evaluation';
|
||||
|
||||
export const MFA_FORM = {
|
||||
MFA_TOKEN: 'MFA_TOKEN',
|
||||
MFA_RECOVERY_CODE: 'MFA_RECOVERY_CODE',
|
||||
|
|
|
@ -3,6 +3,8 @@ import { computed, ref } from 'vue';
|
|||
import { useRootStore } from './root.store';
|
||||
import { createTestDefinitionsApi } from '@/api/evaluations.ee';
|
||||
import type { ITestDefinition } from '@/api/evaluations.ee';
|
||||
import { usePostHog } from './posthog.store';
|
||||
import { WORKFLOW_EVALUATION_EXPERIMENT } from '@/constants';
|
||||
|
||||
export const useEvaluationsStore = defineStore(
|
||||
'evaluations',
|
||||
|
@ -13,6 +15,7 @@ export const useEvaluationsStore = defineStore(
|
|||
const fetchedAll = ref(false);
|
||||
|
||||
// Store instances
|
||||
const posthogStore = usePostHog();
|
||||
const rootStore = useRootStore();
|
||||
const testDefinitionsApi = createTestDefinitionsApi();
|
||||
|
||||
|
@ -21,13 +24,17 @@ export const useEvaluationsStore = defineStore(
|
|||
return Object.values(testDefinitionsById.value).sort((a, b) => a.name.localeCompare(b.name));
|
||||
});
|
||||
|
||||
// Enable with `window.featureFlags.override('025_workflow_evaluation', true)`
|
||||
const isFeatureEnabled = computed(() =>
|
||||
posthogStore.isFeatureEnabled(WORKFLOW_EVALUATION_EXPERIMENT),
|
||||
);
|
||||
|
||||
const isLoading = computed(() => loading.value);
|
||||
|
||||
const hasTestDefinitions = computed(() => Object.keys(testDefinitionsById.value).length > 0);
|
||||
|
||||
// Methods
|
||||
const setAllTestDefinitions = (definitions: ITestDefinition[]) => {
|
||||
console.log('🚀 ~ setAllTestDefinitions ~ definitions:', definitions);
|
||||
testDefinitionsById.value = definitions.reduce(
|
||||
(acc: Record<number, ITestDefinition>, def: ITestDefinition) => {
|
||||
acc[def.id] = def;
|
||||
|
@ -76,7 +83,7 @@ export const useEvaluationsStore = defineStore(
|
|||
rootStore.restApiContext,
|
||||
{ includeScopes },
|
||||
);
|
||||
console.log('🚀 ~ fetchAll ~ retrievedDefinitions:', retrievedDefinitions);
|
||||
|
||||
setAllTestDefinitions(retrievedDefinitions.testDefinitions);
|
||||
return retrievedDefinitions;
|
||||
} finally {
|
||||
|
@ -131,6 +138,7 @@ export const useEvaluationsStore = defineStore(
|
|||
allTestDefinitions,
|
||||
isLoading,
|
||||
hasTestDefinitions,
|
||||
isFeatureEnabled,
|
||||
|
||||
// Methods
|
||||
fetchAll,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue';
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { VIEWS } from '@/constants';
|
||||
import { useEvaluationsStore } from '@/stores/evaluations.store.ee';
|
||||
|
@ -8,8 +8,10 @@ import { useI18n } from '@/composables/useI18n';
|
|||
import EmptyState from '@/components/WorkflowEvaluation/ListEvaluation/EmptyState.vue';
|
||||
import TestsList from '@/components/WorkflowEvaluation/ListEvaluation/TestsList.vue';
|
||||
import type { TestExecution, TestListItem } from '@/components/WorkflowEvaluation/types';
|
||||
import { useAnnotationTagsStore } from '@/stores/tags.store';
|
||||
|
||||
const router = useRouter();
|
||||
const tagsStore = useAnnotationTagsStore();
|
||||
const evaluationsStore = useEvaluationsStore();
|
||||
const isLoading = ref(false);
|
||||
const toast = useToast();
|
||||
|
@ -20,25 +22,21 @@ const tests = computed<TestListItem[]>(() => {
|
|||
id: test.id,
|
||||
name: test.name,
|
||||
tagName: test.annotationTagId ? getTagName(test.annotationTagId) : '',
|
||||
testCases: 0, // This should come from the API
|
||||
testCases: 0, // TODO: This should come from the API
|
||||
execution: getTestExecution(test.id),
|
||||
}));
|
||||
});
|
||||
const hasTests = computed(() => tests.value.length > 0);
|
||||
const allTags = computed(() => tagsStore.allTags);
|
||||
|
||||
// Mock function to get tag name - replace with actual tag lookup
|
||||
function getTagName(tagId: string) {
|
||||
const tags = {
|
||||
tag1: 'marketing',
|
||||
tag2: 'SupportOps',
|
||||
};
|
||||
return tags[tagId] || '';
|
||||
const matchingTag = allTags.value.find((t) => t.id === tagId);
|
||||
|
||||
return matchingTag?.name ?? '';
|
||||
}
|
||||
|
||||
// Mock function to get test execution data - replace with actual API call
|
||||
function getTestExecution(testId: number): TestExecution {
|
||||
console.log('🚀 ~ getTestExecution ~ testId:', testId);
|
||||
// Mock data - replace with actual data from your API
|
||||
// TODO: Replace with actual API call once implemented
|
||||
function getTestExecution(_testId: number): TestExecution {
|
||||
const mockExecutions = {
|
||||
12: {
|
||||
lastRun: 'an hour ago',
|
||||
|
@ -63,24 +61,18 @@ function onCreateTest() {
|
|||
|
||||
function onRunTest(testId: number) {
|
||||
console.log('Running test:', testId);
|
||||
// Implement test run logic
|
||||
// TODO: Implement test run logic
|
||||
}
|
||||
|
||||
function onViewDetails(testId: number) {
|
||||
console.log('Viewing details for test:', testId);
|
||||
void router.push({ name: VIEWS.WORKFLOW_EVALUATION_EDIT, params: { testId } });
|
||||
// Implement navigation to test details
|
||||
}
|
||||
|
||||
function onEditTest(testId: number) {
|
||||
console.log('Editing test:', testId);
|
||||
void router.push({ name: VIEWS.WORKFLOW_EVALUATION_EDIT, params: { testId } });
|
||||
// Implement edit navigation
|
||||
}
|
||||
|
||||
async function onDeleteTest(testId: number) {
|
||||
console.log('Deleting test:', testId);
|
||||
// Implement delete logic
|
||||
await evaluationsStore.deleteById(testId);
|
||||
|
||||
toast.showMessage({
|
||||
|
@ -90,17 +82,30 @@ async function onDeleteTest(testId: number) {
|
|||
}
|
||||
|
||||
// Load initial data
|
||||
async function loadTests() {
|
||||
async function loadInitialData() {
|
||||
isLoading.value = true;
|
||||
try {
|
||||
await tagsStore.fetchAll();
|
||||
await evaluationsStore.fetchAll();
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Load tests on mount
|
||||
void loadTests();
|
||||
onMounted(() => {
|
||||
if (!evaluationsStore.isFeatureEnabled) {
|
||||
toast.showMessage({
|
||||
// message: "Feature not enabled",
|
||||
title: 'Feature not enabled',
|
||||
type: 'error',
|
||||
});
|
||||
void router.push({
|
||||
name: VIEWS.WORKFLOW,
|
||||
params: { name: router.currentRoute.value.params.name },
|
||||
});
|
||||
}
|
||||
void loadInitialData();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
Loading…
Reference in a new issue