diff --git a/packages/frontend/editor-ui/src/components/MainSidebar.vue b/packages/frontend/editor-ui/src/components/MainSidebar.vue index 7bf0fe220c0..5d85a80e514 100644 --- a/packages/frontend/editor-ui/src/components/MainSidebar.vue +++ b/packages/frontend/editor-ui/src/components/MainSidebar.vue @@ -111,7 +111,9 @@ const mainMenuItems = computed(() => [ customIconSize: 'medium', position: 'bottom', route: { to: { name: VIEWS.INSIGHTS } }, - available: hasPermission(['rbac'], { rbac: { scope: 'insights:list' } }), + available: + settingsStore.settings.insights.enabled && + hasPermission(['rbac'], { rbac: { scope: 'insights:list' } }), }, { id: 'help', diff --git a/packages/frontend/editor-ui/src/components/WorkflowSettings.vue b/packages/frontend/editor-ui/src/components/WorkflowSettings.vue index c08b51bf421..f4995de52c4 100644 --- a/packages/frontend/editor-ui/src/components/WorkflowSettings.vue +++ b/packages/frontend/editor-ui/src/components/WorkflowSettings.vue @@ -380,7 +380,11 @@ const toggleTimeout = () => { const updateTimeSavedPerExecution = (value: string) => { const numValue = parseInt(value, 10); - workflowSettings.value.timeSavedPerExecution = isNaN(numValue) ? undefined : numValue; + workflowSettings.value.timeSavedPerExecution = isNaN(numValue) + ? undefined + : numValue < 0 + ? 0 + : numValue; }; onMounted(async () => { @@ -826,6 +830,7 @@ onMounted(async () => { :disabled="readOnlyEnv || !workflowPermissions.update" data-test-id="workflow-settings-time-saved-per-execution" type="number" + min="0" @update:model-value="updateTimeSavedPerExecution" /> {{ i18n.baseText('workflowSettings.timeSavedPerExecution.hint') }} diff --git a/packages/frontend/editor-ui/src/features/insights/chartjs.utils.ts b/packages/frontend/editor-ui/src/features/insights/chartjs.utils.ts index cb733576d9e..feed42f377b 100644 --- a/packages/frontend/editor-ui/src/features/insights/chartjs.utils.ts +++ b/packages/frontend/editor-ui/src/features/insights/chartjs.utils.ts @@ -52,7 +52,7 @@ export const generateLineChartOptions = ( callbacks: { label(context: ScriptableContext<'line'>) { const label = context.dataset.label ?? ''; - return `${label} ${smartDecimal(context.parsed.y)}`; + return `${label} ${smartDecimal(context.parsed.y).toLocaleString('en-US')}`; }, labelColor(context: ScriptableContext<'line'>) { return { diff --git a/packages/frontend/editor-ui/src/features/insights/components/InsightsSummary.test.ts b/packages/frontend/editor-ui/src/features/insights/components/InsightsSummary.test.ts index 36b870739b2..437063bf6f2 100644 --- a/packages/frontend/editor-ui/src/features/insights/components/InsightsSummary.test.ts +++ b/packages/frontend/editor-ui/src/features/insights/components/InsightsSummary.test.ts @@ -36,38 +36,50 @@ describe('InsightsSummary', () => { [[]], [ [ - { id: 'total', value: 525, deviation: 85, unit: '' }, - { id: 'failed', value: 14, deviation: 3, unit: '' }, - { id: 'failureRate', value: 1.9, deviation: -0.8, unit: '%' }, - { id: 'timeSaved', value: 55.55555555555556, deviation: -5.164722222222222, unit: 'h' }, - { id: 'averageRunTime', value: 2.5, deviation: -0.5, unit: 's' }, + { id: 'total', value: 525, deviation: 85, unit: '', deviationUnit: '%' }, + { id: 'failed', value: 14, deviation: 3, unit: '', deviationUnit: '%' }, + { id: 'failureRate', value: 1.9, deviation: -0.8, unit: '%', deviationUnit: 'pp' }, + { + id: 'timeSaved', + value: 55.55555555555556, + deviation: -5.164722222222222, + unit: 'h', + deviationUnit: 'h', + }, + { id: 'averageRunTime', value: 2.5, deviation: -0.5, unit: 's', deviationUnit: 's' }, ], ], [ [ - { id: 'total', value: 525, deviation: 85, unit: '' }, - { id: 'failed', value: 14, deviation: 3, unit: '' }, - { id: 'failureRate', value: 1.9, deviation: -0.8, unit: '%' }, - { id: 'timeSaved', value: 0, deviation: 0, unit: 'h' }, - { id: 'averageRunTime', value: 2.5, deviation: -0.5, unit: 's' }, + { id: 'total', value: 525, deviation: 85, unit: '', deviationUnit: '%' }, + { id: 'failed', value: 14, deviation: 3, unit: '', deviationUnit: '%' }, + { id: 'failureRate', value: 1.9, deviation: -0.8, unit: '%', deviationUnit: 'pp' }, + { id: 'timeSaved', value: 0, deviation: 0, unit: 'h', deviationUnit: 'h' }, + { id: 'averageRunTime', value: 2.5, deviation: -0.5, unit: 's', deviationUnit: 's' }, ], ], [ [ - { id: 'total', value: 525, deviation: -2, unit: '' }, - { id: 'failed', value: 14, deviation: -3, unit: '' }, - { id: 'failureRate', value: 1.9, deviation: 0.8, unit: '%' }, - { id: 'timeSaved', value: 55.55555555555556, deviation: 0, unit: 'h' }, - { id: 'averageRunTime', value: 2.5, deviation: 0.5, unit: 's' }, + { id: 'total', value: 525, deviation: -2, unit: '', deviationUnit: '%' }, + { id: 'failed', value: 14, deviation: -3, unit: '', deviationUnit: '%' }, + { id: 'failureRate', value: 1.9, deviation: 0.8, unit: '%', deviationUnit: 'pp' }, + { id: 'timeSaved', value: 55.55555555555556, deviation: 0, unit: 'h', deviationUnit: 'h' }, + { id: 'averageRunTime', value: 2.5, deviation: 0.5, unit: 's', deviationUnit: 's' }, ], ], [ [ - { id: 'total', value: 525, deviation: null, unit: '' }, - { id: 'failed', value: 14, deviation: null, unit: '' }, - { id: 'failureRate', value: 1.9, deviation: null, unit: '%' }, - { id: 'timeSaved', value: 55.55555555555556, deviation: null, unit: 'h' }, - { id: 'averageRunTime', value: 2.5, deviation: null, unit: 's' }, + { id: 'total', value: 525, deviation: null, unit: '', deviationUnit: '%' }, + { id: 'failed', value: 14, deviation: null, unit: '', deviationUnit: '%' }, + { id: 'failureRate', value: 1.9, deviation: null, unit: '%', deviationUnit: 'pp' }, + { + id: 'timeSaved', + value: 55.55555555555556, + deviation: null, + unit: 'h', + deviationUnit: 'h', + }, + { id: 'averageRunTime', value: 2.5, deviation: null, unit: 's', deviationUnit: 's' }, ], ], ])('should render the summary correctly', (summary) => { diff --git a/packages/frontend/editor-ui/src/features/insights/components/InsightsSummary.vue b/packages/frontend/editor-ui/src/features/insights/components/InsightsSummary.vue index 3c2c3bd2530..4f6037cece5 100644 --- a/packages/frontend/editor-ui/src/features/insights/components/InsightsSummary.vue +++ b/packages/frontend/editor-ui/src/features/insights/components/InsightsSummary.vue @@ -8,7 +8,7 @@ import { import type { InsightsSummaryDisplay } from '@/features/insights/insights.types'; import type { InsightsSummary } from '@n8n/api-types'; import { smartDecimal } from '@n8n/utils/number/smartDecimal'; -import { computed, useCssModule } from 'vue'; +import { computed, ref, useCssModule } from 'vue'; import { useRoute } from 'vue-router'; const props = defineProps<{ @@ -20,6 +20,8 @@ const i18n = useI18n(); const route = useRoute(); const $style = useCssModule(); +const lastNDays = ref(7); + const summaryTitles = computed>(() => ({ total: i18n.baseText('insights.banner.title.total'), failed: i18n.baseText('insights.banner.title.failed'), @@ -35,7 +37,6 @@ const summaryWithRouteLocations = computed(() => })), ); -const getSign = (n: number) => (n > 0 ? '+' : undefined); const getImpactStyle = (id: keyof InsightsSummary, value: number) => { const impact = INSIGHTS_UNIT_IMPACT_MAPPING[id]; if (value === 0 || impact === INSIGHT_IMPACT_TYPES.NEUTRAL) { @@ -53,18 +54,25 @@ const getImpactStyle = (id: keyof InsightsSummary, value: number) => {