mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 01:56:46 +00:00
fix(editor): Hide Evaluations setup wizard if protected instance (#18055)
This commit is contained in:
@@ -3295,6 +3295,7 @@
|
|||||||
"evaluation.executions.toast.addedTo.title": "Execution added to test ",
|
"evaluation.executions.toast.addedTo.title": "Execution added to test ",
|
||||||
"evaluation.executions.toast.closeTab": "Close this tab",
|
"evaluation.executions.toast.closeTab": "Close this tab",
|
||||||
"evaluation.executions.toast.removedFrom.title": "Execution removed from test ",
|
"evaluation.executions.toast.removedFrom.title": "Execution removed from test ",
|
||||||
|
"evaluations.readOnlyNotice": "Evaluations can't be built in read-only mode. Build your evaluation on your development environment.",
|
||||||
"evaluations.paywall.title": "Register to enable evaluation",
|
"evaluations.paywall.title": "Register to enable evaluation",
|
||||||
"evaluations.paywall.description": "Register your Community instance to unlock the evaluation feature",
|
"evaluations.paywall.description": "Register your Community instance to unlock the evaluation feature",
|
||||||
"evaluations.paywall.cta": "Register instance",
|
"evaluations.paywall.cta": "Register instance",
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ import { useToast } from '@/composables/useToast';
|
|||||||
import { useI18n } from '@n8n/i18n';
|
import { useI18n } from '@n8n/i18n';
|
||||||
import { useEvaluationStore } from '@/stores/evaluation.store.ee';
|
import { useEvaluationStore } from '@/stores/evaluation.store.ee';
|
||||||
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
import { useNodeTypesStore } from '@/stores/nodeTypes.store';
|
||||||
|
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
||||||
|
|
||||||
import { computed, watch } from 'vue';
|
import { computed, watch } from 'vue';
|
||||||
import { N8nLink, N8nText } from '@n8n/design-system';
|
import { N8nCallout, N8nLink, N8nText } from '@n8n/design-system';
|
||||||
import EvaluationsPaywall from '@/components/Evaluations.ee/Paywall/EvaluationsPaywall.vue';
|
import EvaluationsPaywall from '@/components/Evaluations.ee/Paywall/EvaluationsPaywall.vue';
|
||||||
import SetupWizard from '@/components/Evaluations.ee/SetupWizard/SetupWizard.vue';
|
import SetupWizard from '@/components/Evaluations.ee/SetupWizard/SetupWizard.vue';
|
||||||
|
|
||||||
@@ -26,6 +27,7 @@ const nodeTypesStore = useNodeTypesStore();
|
|||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const locale = useI18n();
|
const locale = useI18n();
|
||||||
|
const sourceControlStore = useSourceControlStore();
|
||||||
|
|
||||||
const { initializeWorkspace } = useCanvasOperations();
|
const { initializeWorkspace } = useCanvasOperations();
|
||||||
|
|
||||||
@@ -33,6 +35,10 @@ const evaluationsLicensed = computed(() => {
|
|||||||
return usageStore.workflowsWithEvaluationsLimit !== 0;
|
return usageStore.workflowsWithEvaluationsLimit !== 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isProtectedEnvironment = computed(() => {
|
||||||
|
return sourceControlStore.preferences.branchReadOnly;
|
||||||
|
});
|
||||||
|
|
||||||
const runs = computed(() => {
|
const runs = computed(() => {
|
||||||
return Object.values(evaluationStore.testRunsById ?? {}).filter(
|
return Object.values(evaluationStore.testRunsById ?? {}).filter(
|
||||||
({ workflowId }) => workflowId === props.name,
|
({ workflowId }) => workflowId === props.name,
|
||||||
@@ -142,7 +148,10 @@ watch(
|
|||||||
</N8nText>
|
</N8nText>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div :class="$style.config">
|
<N8nCallout v-if="isProtectedEnvironment" theme="info" icon="info">
|
||||||
|
{{ locale.baseText('evaluations.readOnlyNotice') }}
|
||||||
|
</N8nCallout>
|
||||||
|
<div v-else :class="$style.config">
|
||||||
<iframe
|
<iframe
|
||||||
style="min-width: 500px"
|
style="min-width: 500px"
|
||||||
width="500"
|
width="500"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import EvaluationRootView from '../EvaluationsRootView.vue';
|
|||||||
import { useWorkflowsStore } from '@/stores/workflows.store';
|
import { useWorkflowsStore } from '@/stores/workflows.store';
|
||||||
import { useEvaluationStore } from '@/stores/evaluation.store.ee';
|
import { useEvaluationStore } from '@/stores/evaluation.store.ee';
|
||||||
import { useUsageStore } from '@/stores/usage.store';
|
import { useUsageStore } from '@/stores/usage.store';
|
||||||
|
import { useSourceControlStore } from '@/stores/sourceControl.store';
|
||||||
import { mockedStore } from '@/__tests__/utils';
|
import { mockedStore } from '@/__tests__/utils';
|
||||||
import type { IWorkflowDb } from '@/Interface';
|
import type { IWorkflowDb } from '@/Interface';
|
||||||
import { waitFor } from '@testing-library/vue';
|
import { waitFor } from '@testing-library/vue';
|
||||||
@@ -15,6 +16,7 @@ import { PLACEHOLDER_EMPTY_WORKFLOW_ID } from '@/constants';
|
|||||||
import { useTelemetry } from '@/composables/useTelemetry';
|
import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
import { EVALUATION_NODE_TYPE, EVALUATION_TRIGGER_NODE_TYPE, NodeHelpers } from 'n8n-workflow';
|
import { EVALUATION_NODE_TYPE, EVALUATION_TRIGGER_NODE_TYPE, NodeHelpers } from 'n8n-workflow';
|
||||||
import { mockNodeTypeDescription } from '@/__tests__/mocks';
|
import { mockNodeTypeDescription } from '@/__tests__/mocks';
|
||||||
|
import type { SourceControlPreferences } from '@/types/sourceControl.types';
|
||||||
|
|
||||||
vi.mock('@/composables/useTelemetry', () => {
|
vi.mock('@/composables/useTelemetry', () => {
|
||||||
const track = vi.fn();
|
const track = vi.fn();
|
||||||
@@ -32,6 +34,15 @@ vi.mock('@/stores/nodeTypes.store', () => ({
|
|||||||
})),
|
})),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
vi.mock('@n8n/i18n', async (importOriginal) => {
|
||||||
|
return {
|
||||||
|
...(await importOriginal()),
|
||||||
|
useI18n: () => ({
|
||||||
|
baseText: vi.fn((key: string) => `mocked-${key}`),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
describe('EvaluationsRootView', () => {
|
describe('EvaluationsRootView', () => {
|
||||||
const renderComponent = createComponentRenderer(EvaluationRootView);
|
const renderComponent = createComponentRenderer(EvaluationRootView);
|
||||||
|
|
||||||
@@ -127,6 +138,21 @@ describe('EvaluationsRootView', () => {
|
|||||||
await waitFor(() => expect(container.querySelector('.setupContent')).toBeTruthy());
|
await waitFor(() => expect(container.querySelector('.setupContent')).toBeTruthy());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should render read-only callout when in protected environment', async () => {
|
||||||
|
const workflowsStore = mockedStore(useWorkflowsStore);
|
||||||
|
const sourceControlStore = mockedStore(useSourceControlStore);
|
||||||
|
workflowsStore.fetchWorkflow.mockResolvedValue(mockWorkflow);
|
||||||
|
sourceControlStore.preferences = mock<SourceControlPreferences>({ branchReadOnly: true });
|
||||||
|
|
||||||
|
const { container } = renderComponent({ props: { name: mockWorkflow.id } });
|
||||||
|
|
||||||
|
await waitFor(() => {
|
||||||
|
const callout = container.querySelector('[role="alert"]');
|
||||||
|
expect(callout).toBeTruthy();
|
||||||
|
expect(callout?.textContent).toContain('mocked-evaluations.readOnlyNotice');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('telemetry', () => {
|
describe('telemetry', () => {
|
||||||
it('should send telemetry event on mount with setup view when no test runs exist', async () => {
|
it('should send telemetry event on mount with setup view when no test runs exist', async () => {
|
||||||
const workflowsStore = mockedStore(useWorkflowsStore);
|
const workflowsStore = mockedStore(useWorkflowsStore);
|
||||||
|
|||||||
Reference in New Issue
Block a user