fix: Show correct date range in insight overview

This commit is contained in:
Irénée 2025-11-25 11:28:27 +00:00 committed by GitHub
parent 5fd1702429
commit 3130d20533
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 678 additions and 36 deletions

View file

@ -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<InsightsDateRange['key']>('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"
/>
<div :class="$style.insightsContent">

View file

@ -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<N8nDateRangePickerProps, 'maxValue' | 'minValue'>;
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) {

View file

@ -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<typeof today>; end?: ReturnType<typeof today> };
}>([
{
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();
});
});
});

View file

@ -1,26 +1,28 @@
<script setup lang="ts">
import { useTelemetry } from '@/app/composables/useTelemetry';
import { useSettingsStore } from '@/app/stores/settings.store';
import { VIEWS } from '@/app/constants';
import { useSettingsStore } from '@/app/stores/settings.store';
import {
INSIGHT_IMPACT_TYPES,
INSIGHTS_UNIT_IMPACT_MAPPING,
} from '@/features/execution/insights/insights.constants';
import type { InsightsSummaryDisplay } from '@/features/execution/insights/insights.types';
import type { InsightsDateRange, InsightsSummary } from '@n8n/api-types';
import type { DateValue } from '@internationalized/date';
import type { InsightsSummary } from '@n8n/api-types';
import { N8nCallout, N8nIcon, N8nLink, N8nText, N8nTooltip } from '@n8n/design-system';
import { useI18n } from '@n8n/i18n';
import { smartDecimal } from '@n8n/utils/number/smartDecimal';
import { computed, ref, useCssModule, onMounted } from 'vue';
import { computed, onMounted, ref, useCssModule } from 'vue';
import { I18nT } from 'vue-i18n';
import { useRoute } from 'vue-router';
import { getTimeRangeLabels } from '../insights.utils';
import { N8nCallout, N8nIcon, N8nLink, N8nText, N8nTooltip } from '@n8n/design-system';
import { formatDateRange, getMatchingPreset, getTimeRangeLabels } from '../insights.utils';
const INSIGHTS_QUEUE_MODE_WARNING_DISMISSED_KEY = 'n8n-insights-queue-mode-warning-dismissed';
const props = defineProps<{
summary: InsightsSummaryDisplay;
timeRange: InsightsDateRange['key'];
startDate?: DateValue;
endDate?: DateValue;
loading?: boolean;
}>();
@ -49,6 +51,19 @@ const shouldShowQueueModeWarning = computed(() => {
return settingsStore.isQueueModeEnabled && !isQueueModeWarningDismissed.value;
});
const displayDateRangeLabel = computed(() => {
const timeRangeKey = getMatchingPreset({
start: props.startDate,
end: props.endDate,
});
if (timeRangeKey) {
return timeRangeLabels[timeRangeKey];
}
return formatDateRange({ start: props.startDate, end: props.endDate });
});
const summaryTitles = computed<Record<keyof InsightsSummary, string>>(() => ({
total: i18n.baseText('insights.banner.title.total'),
failed: i18n.baseText('insights.banner.title.failed'),
@ -158,7 +173,7 @@ const trackTabClick = (insightType: keyof InsightsSummary) => {
</N8nTooltip>
</strong>
<small :class="$style.days">
{{ timeRangeLabels[timeRange] }}
{{ displayDateRangeLabel }}
</small>
<span v-if="value === 0 && id === 'timeSaved'" :class="$style.empty">
<em>--</em>

View file

@ -212,3 +212,408 @@ exports[`InsightsSummary > should render the summary correctly 6`] = `
</div><!-- TODO: This should be removed after some time when the number issue is behind us -->
</div>"
`;
exports[`InsightsSummary > with different date ranges > should render with 'custom range ending today' 1`] = `
"<div class="insightsWrapper">
<!--v-if-->
<div class="insights">
<ul data-test-id="insights-summary-tabs">
<li data-test-id="insights-summary-tab-total"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">10 Nov - 25 Nov, 2025</small><span><em>525 <i></i></em><small class="positive"><n8n-icon-stub icon="chevron-up" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 85%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failed"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failed prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">10 Nov - 25 Nov, 2025</small><span><em>14 <i></i></em><small class="negative"><n8n-icon-stub icon="chevron-up" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 3%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failureRate"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failure rate</span><!--teleport start--><!--teleport end--></strong><small class="days">10 Nov - 25 Nov, 2025</small><span><em>1.9 <i>%</i></em><small class="positive"><n8n-icon-stub icon="chevron-down" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.8pp</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-timeSaved"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Time saved</span><!--teleport start--><!--teleport end--></strong><small class="days">10 Nov - 25 Nov, 2025</small><span><em>55.55 <i>h</i></em><small class="negative"><n8n-icon-stub icon="chevron-down" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 5.16h</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-averageRunTime"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Run time (avg.)</span><!--teleport start--><!--teleport end--></strong><small class="days">10 Nov - 25 Nov, 2025</small><span><em>2.5 <i>s</i></em><small class="neutral"><n8n-icon-stub icon="chevron-down" spin="false" class="icon neutral"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.5s</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
</ul>
</div><!-- TODO: This should be removed after some time when the number issue is behind us -->
</div>"
`;
exports[`InsightsSummary > with different date ranges > should render with 'custom range not ending today' 1`] = `
"<div class="insightsWrapper">
<!--v-if-->
<div class="insights">
<ul data-test-id="insights-summary-tabs">
<li data-test-id="insights-summary-tab-total"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">16 Nov - 23 Nov, 2025</small><span><em>525 <i></i></em><small class="positive"><n8n-icon-stub icon="chevron-up" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 85%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failed"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failed prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">16 Nov - 23 Nov, 2025</small><span><em>14 <i></i></em><small class="negative"><n8n-icon-stub icon="chevron-up" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 3%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failureRate"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failure rate</span><!--teleport start--><!--teleport end--></strong><small class="days">16 Nov - 23 Nov, 2025</small><span><em>1.9 <i>%</i></em><small class="positive"><n8n-icon-stub icon="chevron-down" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.8pp</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-timeSaved"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Time saved</span><!--teleport start--><!--teleport end--></strong><small class="days">16 Nov - 23 Nov, 2025</small><span><em>55.55 <i>h</i></em><small class="negative"><n8n-icon-stub icon="chevron-down" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 5.16h</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-averageRunTime"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Run time (avg.)</span><!--teleport start--><!--teleport end--></strong><small class="days">16 Nov - 23 Nov, 2025</small><span><em>2.5 <i>s</i></em><small class="neutral"><n8n-icon-stub icon="chevron-down" spin="false" class="icon neutral"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.5s</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
</ul>
</div><!-- TODO: This should be removed after some time when the number issue is behind us -->
</div>"
`;
exports[`InsightsSummary > with different date ranges > should render with 'last 7 days (week preset)' 1`] = `
"<div class="insightsWrapper">
<!--v-if-->
<div class="insights">
<ul data-test-id="insights-summary-tabs">
<li data-test-id="insights-summary-tab-total"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 7 days</small><span><em>525 <i></i></em><small class="positive"><n8n-icon-stub icon="chevron-up" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 85%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failed"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failed prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 7 days</small><span><em>14 <i></i></em><small class="negative"><n8n-icon-stub icon="chevron-up" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 3%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failureRate"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failure rate</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 7 days</small><span><em>1.9 <i>%</i></em><small class="positive"><n8n-icon-stub icon="chevron-down" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.8pp</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-timeSaved"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Time saved</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 7 days</small><span><em>55.55 <i>h</i></em><small class="negative"><n8n-icon-stub icon="chevron-down" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 5.16h</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-averageRunTime"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Run time (avg.)</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 7 days</small><span><em>2.5 <i>s</i></em><small class="neutral"><n8n-icon-stub icon="chevron-down" spin="false" class="icon neutral"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.5s</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
</ul>
</div><!-- TODO: This should be removed after some time when the number issue is behind us -->
</div>"
`;
exports[`InsightsSummary > with different date ranges > should render with 'last 14 days (2weeks preset)' 1`] = `
"<div class="insightsWrapper">
<!--v-if-->
<div class="insights">
<ul data-test-id="insights-summary-tabs">
<li data-test-id="insights-summary-tab-total"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 14 days</small><span><em>525 <i></i></em><small class="positive"><n8n-icon-stub icon="chevron-up" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 85%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failed"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failed prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 14 days</small><span><em>14 <i></i></em><small class="negative"><n8n-icon-stub icon="chevron-up" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 3%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failureRate"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failure rate</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 14 days</small><span><em>1.9 <i>%</i></em><small class="positive"><n8n-icon-stub icon="chevron-down" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.8pp</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-timeSaved"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Time saved</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 14 days</small><span><em>55.55 <i>h</i></em><small class="negative"><n8n-icon-stub icon="chevron-down" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 5.16h</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-averageRunTime"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Run time (avg.)</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 14 days</small><span><em>2.5 <i>s</i></em><small class="neutral"><n8n-icon-stub icon="chevron-down" spin="false" class="icon neutral"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.5s</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
</ul>
</div><!-- TODO: This should be removed after some time when the number issue is behind us -->
</div>"
`;
exports[`InsightsSummary > with different date ranges > should render with 'last 24 hours (day preset)' 1`] = `
"<div class="insightsWrapper">
<!--v-if-->
<div class="insights">
<ul data-test-id="insights-summary-tabs">
<li data-test-id="insights-summary-tab-total"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 24 hours</small><span><em>525 <i></i></em><small class="positive"><n8n-icon-stub icon="chevron-up" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 85%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failed"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failed prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 24 hours</small><span><em>14 <i></i></em><small class="negative"><n8n-icon-stub icon="chevron-up" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 3%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failureRate"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failure rate</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 24 hours</small><span><em>1.9 <i>%</i></em><small class="positive"><n8n-icon-stub icon="chevron-down" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.8pp</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-timeSaved"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Time saved</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 24 hours</small><span><em>55.55 <i>h</i></em><small class="negative"><n8n-icon-stub icon="chevron-down" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 5.16h</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-averageRunTime"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Run time (avg.)</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 24 hours</small><span><em>2.5 <i>s</i></em><small class="neutral"><n8n-icon-stub icon="chevron-down" spin="false" class="icon neutral"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.5s</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
</ul>
</div><!-- TODO: This should be removed after some time when the number issue is behind us -->
</div>"
`;
exports[`InsightsSummary > with different date ranges > should render with 'last 30 days (month preset)' 1`] = `
"<div class="insightsWrapper">
<!--v-if-->
<div class="insights">
<ul data-test-id="insights-summary-tabs">
<li data-test-id="insights-summary-tab-total"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 30 days</small><span><em>525 <i></i></em><small class="positive"><n8n-icon-stub icon="chevron-up" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 85%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failed"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failed prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 30 days</small><span><em>14 <i></i></em><small class="negative"><n8n-icon-stub icon="chevron-up" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 3%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failureRate"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failure rate</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 30 days</small><span><em>1.9 <i>%</i></em><small class="positive"><n8n-icon-stub icon="chevron-down" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.8pp</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-timeSaved"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Time saved</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 30 days</small><span><em>55.55 <i>h</i></em><small class="negative"><n8n-icon-stub icon="chevron-down" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 5.16h</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-averageRunTime"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Run time (avg.)</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 30 days</small><span><em>2.5 <i>s</i></em><small class="neutral"><n8n-icon-stub icon="chevron-down" spin="false" class="icon neutral"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.5s</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
</ul>
</div><!-- TODO: This should be removed after some time when the number issue is behind us -->
</div>"
`;
exports[`InsightsSummary > with different date ranges > should render with 'last 90 days (quarter preset)' 1`] = `
"<div class="insightsWrapper">
<!--v-if-->
<div class="insights">
<ul data-test-id="insights-summary-tabs">
<li data-test-id="insights-summary-tab-total"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 90 days</small><span><em>525 <i></i></em><small class="positive"><n8n-icon-stub icon="chevron-up" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 85%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failed"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failed prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 90 days</small><span><em>14 <i></i></em><small class="negative"><n8n-icon-stub icon="chevron-up" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 3%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failureRate"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failure rate</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 90 days</small><span><em>1.9 <i>%</i></em><small class="positive"><n8n-icon-stub icon="chevron-down" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.8pp</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-timeSaved"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Time saved</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 90 days</small><span><em>55.55 <i>h</i></em><small class="negative"><n8n-icon-stub icon="chevron-down" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 5.16h</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-averageRunTime"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Run time (avg.)</span><!--teleport start--><!--teleport end--></strong><small class="days">Last 90 days</small><span><em>2.5 <i>s</i></em><small class="neutral"><n8n-icon-stub icon="chevron-down" spin="false" class="icon neutral"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.5s</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
</ul>
</div><!-- TODO: This should be removed after some time when the number issue is behind us -->
</div>"
`;
exports[`InsightsSummary > with different date ranges > should render with 'last 180 days (6months preset)' 1`] = `
"<div class="insightsWrapper">
<!--v-if-->
<div class="insights">
<ul data-test-id="insights-summary-tabs">
<li data-test-id="insights-summary-tab-total"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">6 months</small><span><em>525 <i></i></em><small class="positive"><n8n-icon-stub icon="chevron-up" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 85%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failed"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failed prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">6 months</small><span><em>14 <i></i></em><small class="negative"><n8n-icon-stub icon="chevron-up" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 3%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failureRate"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failure rate</span><!--teleport start--><!--teleport end--></strong><small class="days">6 months</small><span><em>1.9 <i>%</i></em><small class="positive"><n8n-icon-stub icon="chevron-down" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.8pp</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-timeSaved"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Time saved</span><!--teleport start--><!--teleport end--></strong><small class="days">6 months</small><span><em>55.55 <i>h</i></em><small class="negative"><n8n-icon-stub icon="chevron-down" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 5.16h</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-averageRunTime"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Run time (avg.)</span><!--teleport start--><!--teleport end--></strong><small class="days">6 months</small><span><em>2.5 <i>s</i></em><small class="neutral"><n8n-icon-stub icon="chevron-down" spin="false" class="icon neutral"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.5s</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
</ul>
</div><!-- TODO: This should be removed after some time when the number issue is behind us -->
</div>"
`;
exports[`InsightsSummary > with different date ranges > should render with 'last 365 days (year preset)' 1`] = `
"<div class="insightsWrapper">
<!--v-if-->
<div class="insights">
<ul data-test-id="insights-summary-tabs">
<li data-test-id="insights-summary-tab-total"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">One year</small><span><em>525 <i></i></em><small class="positive"><n8n-icon-stub icon="chevron-up" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 85%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failed"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failed prod. executions</span><!--teleport start--><!--teleport end--></strong><small class="days">One year</small><span><em>14 <i></i></em><small class="negative"><n8n-icon-stub icon="chevron-up" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 3%</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-failureRate"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Failure rate</span><!--teleport start--><!--teleport end--></strong><small class="days">One year</small><span><em>1.9 <i>%</i></em><small class="positive"><n8n-icon-stub icon="chevron-down" spin="false" class="icon positive"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.8pp</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-timeSaved"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Time saved</span><!--teleport start--><!--teleport end--></strong><small class="days">One year</small><span><em>55.55 <i>h</i></em><small class="negative"><n8n-icon-stub icon="chevron-down" spin="false" class="icon negative"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 5.16h</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
<li data-test-id="insights-summary-tab-averageRunTime"><a to="[object Object]" exact-active-class="activeTab" class="el-tooltip__trigger"><strong><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> Run time (avg.)</span><!--teleport start--><!--teleport end--></strong><small class="days">One year</small><span><em>2.5 <i>s</i></em><small class="neutral"><n8n-icon-stub icon="chevron-down" spin="false" class="icon neutral"></n8n-icon-stub><span class="el-only-child__content el-tooltip__trigger el-tooltip__trigger"> 0.5s</span>
<!--teleport start-->
<!--teleport end--></small></span>
</a>
<!--teleport start-->
<!--teleport end-->
</li>
</ul>
</div><!-- TODO: This should be removed after some time when the number issue is behind us -->
</div>"
`;

View file

@ -1,4 +1,6 @@
import type { InsightsSummary } from '@n8n/api-types';
import { CalendarDate, getLocalTimeZone, today } from '@internationalized/date';
import {
transformInsightsTimeSaved,
transformInsightsAverageRunTime,
@ -6,6 +8,9 @@ import {
transformInsightsValues,
transformInsightsDeviation,
transformInsightsSummary,
formatDateRange,
getMatchingPreset,
timeRangeMappings,
} from './insights.utils';
import {
@ -243,4 +248,93 @@ describe('Insights Transformers', () => {
expect(INSIGHTS_DEVIATION_UNIT_MAPPING.timeSaved).not.toHaveBeenCalled(); // deviation is null
});
});
describe('formatDateRange', () => {
afterEach(() => {
vi.clearAllMocks();
});
it('should return empty string if start date is not provided', () => {
const result = formatDateRange({ end: new CalendarDate(2025, 6, 5) });
expect(result).toBe('');
});
it('should return formatted start date if the end date is not provided', () => {
const result = formatDateRange({ start: new CalendarDate(2025, 2, 28) });
expect(result).toBe('28 Feb, 2025');
});
it('should return formatted start date if the end date is the same as the start date', () => {
const result = formatDateRange({
start: new CalendarDate(2025, 10, 20),
end: new CalendarDate(2025, 10, 20),
});
expect(result).toBe('20 Oct, 2025');
});
it('should return formatted range for same year range', () => {
const result = formatDateRange({
start: new CalendarDate(2025, 10, 20),
end: new CalendarDate(2025, 10, 25),
});
expect(result).toBe('20 Oct - 25 Oct, 2025');
});
it('should return formatted range for different year range', () => {
const result = formatDateRange({
start: new CalendarDate(2024, 12, 20),
end: new CalendarDate(2025, 1, 5),
});
expect(result).toBe('20 Dec, 2024 - 5 Jan, 2025');
});
});
describe('getMatchingPreset', () => {
it('should return null if the end date is not provided', () => {
const result = getMatchingPreset({ start: new CalendarDate(2025, 10, 20) });
expect(result).toBeNull();
});
it('should return null if the start date is not provided', () => {
const result = getMatchingPreset({ end: new CalendarDate(2025, 10, 20) });
expect(result).toBeNull();
});
it('should return null if the end date is not today', () => {
const result = getMatchingPreset({
start: new CalendarDate(2025, 10, 20),
end: new CalendarDate(2025, 10, 21),
});
expect(result).toBeNull();
});
it('should return null for custom range', () => {
const result = getMatchingPreset({
start: new CalendarDate(2025, 10, 20),
end: today(getLocalTimeZone()),
});
expect(result).toBeNull();
});
test.each(Object.entries(timeRangeMappings))(
'should return the %s" preset for for %d days',
(key, days) => {
const end = today(getLocalTimeZone());
const start = end.subtract({ days });
const result = getMatchingPreset({ start, end });
expect(result).toBe(key);
},
);
});
});

View file

@ -1,11 +1,17 @@
import { useI18n } from '@n8n/i18n';
import type { InsightsSummary, InsightsSummaryType } from '@n8n/api-types';
import type { InsightsSummaryDisplay } from '@/features/execution/insights/insights.types';
import {
INSIGHTS_DEVIATION_UNIT_MAPPING,
INSIGHTS_SUMMARY_ORDER,
INSIGHTS_UNIT_MAPPING,
INSIGHTS_DEVIATION_UNIT_MAPPING,
} from '@/features/execution/insights/insights.constants';
import type { InsightsSummaryDisplay } from '@/features/execution/insights/insights.types';
import type { DateValue } from '@internationalized/date';
import { getLocalTimeZone, isToday } from '@internationalized/date';
import type { InsightsDateRange, InsightsSummary, InsightsSummaryType } from '@n8n/api-types';
import { useI18n } from '@n8n/i18n';
import dateformat from 'dateformat';
const DATE_FORMAT_DAY_MONTH_YEAR = 'd mmm, yyyy';
const DATE_FORMAT_DAY_MONTH = 'd mmm';
export const transformInsightsTimeSaved = (minutes: number): number =>
Math.round(minutes / (Math.abs(minutes) < 60 ? 1 : 60)); // we want to show saved time in minutes or hours
@ -59,7 +65,7 @@ export const transformInsightsSummary = (data: InsightsSummary | null): Insights
}))
: [];
export const timeRangeMappings = {
export const timeRangeMappings: Record<InsightsDateRange['key'], number> = {
day: 1,
week: 7,
'2weeks': 14,
@ -67,7 +73,7 @@ export const timeRangeMappings = {
quarter: 90,
'6months': 180,
year: 365,
};
} as const;
export const getTimeRangeLabels = () => {
const i18n = useI18n();
@ -82,3 +88,42 @@ export const getTimeRangeLabels = () => {
year: i18n.baseText('insights.oneYear'),
};
};
/**
* @returns A human readable string representing the date range e.g '01 Jan - 05 Jan 2025'
*/
export const formatDateRange = (range: { start?: DateValue; end?: DateValue }): string => {
const { start, end } = range;
if (!start) return '';
const startDate = start.toDate(getLocalTimeZone());
const endDate = end?.toDate(getLocalTimeZone());
if (!end || start.compare(end) === 0) {
return dateformat(startDate, DATE_FORMAT_DAY_MONTH_YEAR);
}
if (start.year === end.year) {
return `${dateformat(startDate, DATE_FORMAT_DAY_MONTH)} - ${dateformat(endDate, DATE_FORMAT_DAY_MONTH_YEAR)}`;
}
return `${dateformat(startDate, DATE_FORMAT_DAY_MONTH_YEAR)} - ${dateformat(endDate, DATE_FORMAT_DAY_MONTH_YEAR)}`;
};
/**
* @returns The matching preset key if the range matches a preset, null for custom ranges
*/
export const getMatchingPreset = (range: { start?: DateValue; end?: DateValue }):
| InsightsDateRange['key']
| null => {
const { start, end } = range;
if (!start || !end || !isToday(end, getLocalTimeZone())) return null;
const daysDiff = end.compare(start);
for (const [key, days] of Object.entries(timeRangeMappings)) {
if (daysDiff === days) return key as InsightsDateRange['key'];
}
return null;
};