From 3130d205331124d08299c54db5a31a0a6781e5b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ir=C3=A9n=C3=A9e?= Date: Tue, 25 Nov 2025 11:28:27 +0000 Subject: [PATCH] fix: Show correct date range in insight overview --- .../insights/components/InsightsDashboard.vue | 8 +- .../components/InsightsDataRangePicker.vue | 18 +- .../components/InsightsSummary.test.ts | 101 ++++- .../insights/components/InsightsSummary.vue | 31 +- .../InsightsSummary.test.ts.snap | 405 ++++++++++++++++++ .../execution/insights/insights.utils.test.ts | 94 ++++ .../execution/insights/insights.utils.ts | 57 ++- 7 files changed, 678 insertions(+), 36 deletions(-) diff --git a/packages/frontend/editor-ui/src/features/execution/insights/components/InsightsDashboard.vue b/packages/frontend/editor-ui/src/features/execution/insights/components/InsightsDashboard.vue index 2f314c8d6f1..1957391172c 100644 --- a/packages/frontend/editor-ui/src/features/execution/insights/components/InsightsDashboard.vue +++ b/packages/frontend/editor-ui/src/features/execution/insights/components/InsightsDashboard.vue @@ -7,7 +7,7 @@ import InsightsSummary from '@/features/execution/insights/components/InsightsSu import { useInsightsStore } from '@/features/execution/insights/insights.store'; import type { DateValue } from '@internationalized/date'; import { getLocalTimeZone, now, toCalendarDateTime, today } from '@internationalized/date'; -import type { InsightsDateRange, InsightsSummaryType } from '@n8n/api-types'; +import type { InsightsSummaryType } from '@n8n/api-types'; import { useI18n } from '@n8n/i18n'; import { computed, @@ -80,7 +80,6 @@ const transformFilter = ({ id, desc }: { id: string; desc: boolean }) => { const sortTableBy = ref([{ id: props.insightType, desc: true }]); -const selectedDateRange = ref('week'); const granularity = computed(() => { const { start, end } = range.value; if (!start || !end) return 'day'; @@ -164,7 +163,7 @@ const fetchPaginatedTableData = ({ }; watch( - () => [props.insightType, selectedDateRange.value, selectedProject.value, range.value], + () => [props.insightType, selectedProject.value, range.value], () => { sortTableBy.value = [{ id: props.insightType, desc: true }]; @@ -244,7 +243,8 @@ const projects = computed(() => v-if="insightsStore.isSummaryEnabled" :summary="insightsStore.summary.state" :loading="insightsStore.summary.isLoading" - :time-range="selectedDateRange" + :start-date="range.start" + :end-date="range.end" :class="$style.insightsBanner" />
diff --git a/packages/frontend/editor-ui/src/features/execution/insights/components/InsightsDataRangePicker.vue b/packages/frontend/editor-ui/src/features/execution/insights/components/InsightsDataRangePicker.vue index 31b354e6fd6..9ab507c9a5f 100644 --- a/packages/frontend/editor-ui/src/features/execution/insights/components/InsightsDataRangePicker.vue +++ b/packages/frontend/editor-ui/src/features/execution/insights/components/InsightsDataRangePicker.vue @@ -8,13 +8,10 @@ import type { N8nDateRangePickerRootEmits, } from '@n8n/design-system'; import { N8nButton, N8nDateRangePicker, N8nIcon } from '@n8n/design-system'; -import dateformat from 'dateformat'; import { computed, ref, shallowRef, watch } from 'vue'; +import { formatDateRange } from '../insights.utils'; import InsightsUpgradeModal from './InsightsUpgradeModal.vue'; -const DATE_FORMAT_DAY_MONTH_YEAR = 'd mmm, yyyy'; -const DATE_FORMAT_DAY_MONTH = 'd mmm'; - type Props = Pick; type Value = { start: DateValue; @@ -135,18 +132,7 @@ const formattedRange = computed(() => { if (!start) return 'Select range'; - const startStr = start.toString(); - const endStr = end?.toString(); - - if (!end || startStr === endStr) { - return dateformat(startStr, DATE_FORMAT_DAY_MONTH_YEAR); - } - - if (start.year === end.year) { - return `${dateformat(startStr, DATE_FORMAT_DAY_MONTH)} - ${dateformat(endStr, DATE_FORMAT_DAY_MONTH_YEAR)}`; - } - - return `${dateformat(startStr, DATE_FORMAT_DAY_MONTH_YEAR)} - ${dateformat(endStr, DATE_FORMAT_DAY_MONTH_YEAR)}`; + return formatDateRange({ start, end }); }); function isActiveRange(presetValue: number) { diff --git a/packages/frontend/editor-ui/src/features/execution/insights/components/InsightsSummary.test.ts b/packages/frontend/editor-ui/src/features/execution/insights/components/InsightsSummary.test.ts index 3ad8f4acde3..a83524cb22f 100644 --- a/packages/frontend/editor-ui/src/features/execution/insights/components/InsightsSummary.test.ts +++ b/packages/frontend/editor-ui/src/features/execution/insights/components/InsightsSummary.test.ts @@ -4,6 +4,7 @@ import { createComponentRenderer } from '@/__tests__/render'; import type { InsightsSummaryDisplay } from '@/features/execution/insights/insights.types'; import { createTestingPinia } from '@pinia/testing'; import { defaultSettings } from '@/__tests__/defaults'; +import { getLocalTimeZone, today } from '@internationalized/date'; vi.mock('vue-router', () => ({ useRouter: () => ({}), @@ -25,6 +26,9 @@ const renderComponent = createComponentRenderer(InsightsSummary, { }); describe('InsightsSummary', () => { + const endDate = today(getLocalTimeZone()); + const startDate = endDate.subtract({ days: 7 }); + beforeEach(() => { createTestingPinia({ initialState: { settings: { settings: defaultSettings } }, @@ -36,7 +40,8 @@ describe('InsightsSummary', () => { renderComponent({ props: { summary: [], - timeRange: 'week', + startDate, + endDate, }, }), ).not.toThrow(); @@ -105,10 +110,102 @@ describe('InsightsSummary', () => { const { html } = renderComponent({ props: { summary, - timeRange: 'week', + startDate, + endDate, }, }); expect(html()).toMatchSnapshot(); }); + + describe('with different date ranges', () => { + const testSummary: InsightsSummaryDisplay = [ + { 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.55, deviation: -5.16, unit: 'h', deviationUnit: 'h' }, + { id: 'averageRunTime', value: 2.5, deviation: -0.5, unit: 's', deviationUnit: 's' }, + ]; + + test.each<{ + description: string; + getDates: () => { start: ReturnType; end?: ReturnType }; + }>([ + { + description: 'last 24 hours (day preset)', + getDates: () => { + const end = today(getLocalTimeZone()); + return { start: end.subtract({ days: 1 }), end }; + }, + }, + { + description: 'last 7 days (week preset)', + getDates: () => { + const end = today(getLocalTimeZone()); + return { start: end.subtract({ days: 7 }), end }; + }, + }, + { + description: 'last 14 days (2weeks preset)', + getDates: () => { + const end = today(getLocalTimeZone()); + return { start: end.subtract({ days: 14 }), end }; + }, + }, + { + description: 'last 30 days (month preset)', + getDates: () => { + const end = today(getLocalTimeZone()); + return { start: end.subtract({ days: 30 }), end }; + }, + }, + { + description: 'last 90 days (quarter preset)', + getDates: () => { + const end = today(getLocalTimeZone()); + return { start: end.subtract({ days: 90 }), end }; + }, + }, + { + description: 'last 180 days (6months preset)', + getDates: () => { + const end = today(getLocalTimeZone()); + return { start: end.subtract({ days: 180 }), end }; + }, + }, + { + description: 'last 365 days (year preset)', + getDates: () => { + const end = today(getLocalTimeZone()); + return { start: end.subtract({ days: 365 }), end }; + }, + }, + { + description: 'custom range ending today', + getDates: () => { + const end = today(getLocalTimeZone()); + return { start: end.subtract({ days: 15 }), end }; + }, + }, + { + description: 'custom range not ending today', + getDates: () => { + const end = today(getLocalTimeZone()).subtract({ days: 2 }); + return { start: end.subtract({ days: 7 }), end }; + }, + }, + ])('should render with $description', ({ getDates }) => { + const { start, end } = getDates(); + + const { html } = renderComponent({ + props: { + summary: testSummary, + startDate: start, + endDate: end, + }, + }); + + expect(html()).toMatchSnapshot(); + }); + }); }); diff --git a/packages/frontend/editor-ui/src/features/execution/insights/components/InsightsSummary.vue b/packages/frontend/editor-ui/src/features/execution/insights/components/InsightsSummary.vue index cf56cab4036..4ec69287e44 100644 --- a/packages/frontend/editor-ui/src/features/execution/insights/components/InsightsSummary.vue +++ b/packages/frontend/editor-ui/src/features/execution/insights/components/InsightsSummary.vue @@ -1,26 +1,28 @@