diff --git a/ee/app/assets/javascripts/analytics/analytics_dashboards/components/visualization_designer/analytics_visualization_preview.vue b/ee/app/assets/javascripts/analytics/analytics_dashboards/components/visualization_designer/analytics_visualization_preview.vue index fd673be4db69b60651eab216206809c91e595d27..272a9f7e68cd2e487e98342937dc9a5deb21932d 100644 --- a/ee/app/assets/javascripts/analytics/analytics_dashboards/components/visualization_designer/analytics_visualization_preview.vue +++ b/ee/app/assets/javascripts/analytics/analytics_dashboards/components/visualization_designer/analytics_visualization_preview.vue @@ -1,5 +1,5 @@ <script> -import { GlButton, GlButtonGroup, GlLoadingIcon } from '@gitlab/ui'; +import { GlButton, GlButtonGroup, GlLoadingIcon, GlIcon, GlTooltipDirective } from '@gitlab/ui'; import { safeDump } from 'js-yaml'; import { createAlert } from '~/alert'; import { s__, sprintf } from '~/locale'; @@ -21,8 +21,12 @@ export default { GlButton, GlButtonGroup, GlLoadingIcon, + GlIcon, AnalyticsDashboardPanel, }, + directives: { + GlTooltip: GlTooltipDirective, + }, props: { selectedVisualizationType: { type: String, @@ -98,17 +102,29 @@ export default { <div class="gl-m-5 gl-gap-5 gl-display-flex gl-flex-wrap-reverse gl-justify-content-space-between gl-align-items-center" > - <gl-button-group> - <gl-button - v-for="buttonDisplayType in $options.PANEL_DISPLAY_TYPE_ITEMS" - :key="buttonDisplayType.type" - :selected="displayType === buttonDisplayType.type" - :icon="buttonDisplayType.icon" - :data-testid="`select-${buttonDisplayType.type}-button`" - @click="$emit('selectedDisplayType', buttonDisplayType.type)" - >{{ buttonDisplayType.title }}</gl-button - > - </gl-button-group> + <div class="gl-display-flex gl-gap-3"> + <gl-button-group> + <gl-button + v-for="buttonDisplayType in $options.PANEL_DISPLAY_TYPE_ITEMS" + :key="buttonDisplayType.type" + :selected="displayType === buttonDisplayType.type" + :icon="buttonDisplayType.icon" + :data-testid="`select-${buttonDisplayType.type}-button`" + @click="$emit('selectedDisplayType', buttonDisplayType.type)" + >{{ buttonDisplayType.title }}</gl-button + > + </gl-button-group> + <gl-icon + v-gl-tooltip + :title=" + s__( + 'Analytics|The visualization preview displays only the last 7 days. Dashboard visualizations can display the entire date range.', + ) + " + name="information-o" + class="gl-align-self-end gl-mb-3 gl-text-gray-500 gl-min-w-5" + /> + </div> <ai-cube-query-feedback v-if="aiPromptCorrelationId" :correlation-id="aiPromptCorrelationId" diff --git a/ee/app/assets/javascripts/analytics/analytics_dashboards/data_sources/cube_analytics.js b/ee/app/assets/javascripts/analytics/analytics_dashboards/data_sources/cube_analytics.js index 6f4ff062f5f3f8d24b6eb7f353c8fbf2b28eb606..59b4be2f08f228aa5d3c724ef0c9225e7b4f5a62 100644 --- a/ee/app/assets/javascripts/analytics/analytics_dashboards/data_sources/cube_analytics.js +++ b/ee/app/assets/javascripts/analytics/analytics_dashboards/data_sources/cube_analytics.js @@ -13,6 +13,10 @@ import { VISUALIZATION_TYPE_COLUMN_CHART, VISUALIZATION_TYPE_SINGLE_STAT, } from 'ee/analytics/analytics_dashboards/constants'; +import { + TODAY, + SEVEN_DAYS_AGO, +} from 'ee/vue_shared/components/customizable_dashboard/filters/constants'; // This can be any value because the cube proxy adds the real API token. const CUBE_API_TOKEN = '1'; @@ -106,21 +110,17 @@ const getDateRangeDimension = (query) => { return DATE_RANGE_FILTER_DIMENSIONS[tableKey] ?? getDynamicSchemaDateRangeDimension(query); }; -const buildDateRangeFilter = (query, queryOverrides, { startDate, endDate }) => { - if (!startDate && !endDate) return {}; - - return { - filters: [ - ...(query.filters ?? []), - ...(queryOverrides.filters ?? []), - { - member: getDateRangeDimension(query), - operator: 'inDateRange', - values: [pikadayToString(startDate), pikadayToString(endDate)], - }, - ], - }; -}; +const buildDateRangeFilter = (query, queryOverrides, { startDate, endDate }) => ({ + filters: [ + ...(query.filters ?? []), + ...(queryOverrides.filters ?? []), + { + member: getDateRangeDimension(query), + operator: 'inDateRange', + values: [pikadayToString(startDate ?? SEVEN_DAYS_AGO), pikadayToString(endDate ?? TODAY)], + }, + ], +}); const buildAnonUsersFilter = (query, queryOverrides, { filterAnonUsers }) => { if (!filterAnonUsers) return {}; diff --git a/ee/app/assets/javascripts/vue_shared/components/customizable_dashboard/filters/constants.js b/ee/app/assets/javascripts/vue_shared/components/customizable_dashboard/filters/constants.js index 17dbdb02644376f2cd8205f9dbad9276e2eda2d6..e16786112c8cfed26bfe73960137d3bff9f96e08 100644 --- a/ee/app/assets/javascripts/vue_shared/components/customizable_dashboard/filters/constants.js +++ b/ee/app/assets/javascripts/vue_shared/components/customizable_dashboard/filters/constants.js @@ -2,6 +2,7 @@ import { __, sprintf } from '~/locale'; import { getCurrentUtcDate, getDateInPast } from '~/lib/utils/datetime_utility'; export const TODAY = getCurrentUtcDate(); +export const SEVEN_DAYS_AGO = getDateInPast(TODAY, 7); export const CUSTOM_DATE_RANGE_KEY = 'custom'; @@ -27,7 +28,7 @@ export const DATE_RANGE_OPTIONS = [ { key: 'last_7_days', text: sprintf(__('Last %{days} days'), { days: 7 }), - startDate: getDateInPast(TODAY, 7), + startDate: SEVEN_DAYS_AGO, endDate: TODAY, }, { diff --git a/ee/spec/frontend/analytics/analytics_dashboards/components/data_sources/cube_analytics_spec.js b/ee/spec/frontend/analytics/analytics_dashboards/components/data_sources/cube_analytics_spec.js index f96c4b75245363f0bf7836acbd9453e62237b4f6..5e9f50e2187cf010b2a65262a952980ab09c783c 100644 --- a/ee/spec/frontend/analytics/analytics_dashboards/components/data_sources/cube_analytics_spec.js +++ b/ee/spec/frontend/analytics/analytics_dashboards/components/data_sources/cube_analytics_spec.js @@ -1,5 +1,9 @@ import { CubeApi, HttpTransport, __setMockLoad } from '@cubejs-client/core'; import fetch from 'ee/analytics/analytics_dashboards/data_sources/cube_analytics'; +import { + TODAY, + SEVEN_DAYS_AGO, +} from 'ee/vue_shared/components/customizable_dashboard/filters/constants'; import { pikadayToString } from '~/lib/utils/datetime_utility'; import { mockResultSet, @@ -51,8 +55,22 @@ describe('Cube Analytics Data Source', () => { itSetsUpCube(); - it('loads the query with the query override', () => { - expect(mockLoad).toHaveBeenCalledWith(queryOverrides, cubeJsOptions); + it('loads the query with the query override and default filters', () => { + expect(mockLoad).toHaveBeenCalledWith(expect.objectContaining(queryOverrides), cubeJsOptions); + }); + + it('loads the query with the default 7 days date range filters', () => { + const defaultFilters = { + filters: [ + { + member: 'TrackedEvents.derivedTstamp', + operator: 'inDateRange', + values: [pikadayToString(SEVEN_DAYS_AGO), pikadayToString(TODAY)], + }, + ], + }; + + expect(mockLoad).toHaveBeenCalledWith(expect.objectContaining(defaultFilters), cubeJsOptions); }); }); @@ -294,7 +312,7 @@ describe('Cube Analytics Data Source', () => { expect(mockLoad).toHaveBeenCalledWith( { - filters: existingFilters, + filters: expect.arrayContaining(existingFilters), measures: [queryMeasurement], ...expectedSegments, }, diff --git a/ee/spec/frontend/analytics/analytics_dashboards/components/visualization_designer/analytics_visualization_preview_spec.js b/ee/spec/frontend/analytics/analytics_dashboards/components/visualization_designer/analytics_visualization_preview_spec.js index 71960786fbeb8931f0a29712088341e420a415b9..efcf174b600f77e1bfdf85a8b383de0a9a112f08 100644 --- a/ee/spec/frontend/analytics/analytics_dashboards/components/visualization_designer/analytics_visualization_preview_spec.js +++ b/ee/spec/frontend/analytics/analytics_dashboards/components/visualization_designer/analytics_visualization_preview_spec.js @@ -1,6 +1,8 @@ +import { GlIcon } from '@gitlab/ui'; import { safeDump } from 'js-yaml'; import AnalyticsVisualizationPreview from 'ee/analytics/analytics_dashboards/components/visualization_designer/analytics_visualization_preview.vue'; import AiCubeQueryFeedback from 'ee/analytics/analytics_dashboards/components/visualization_designer/ai_cube_query_feedback.vue'; +import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; import { PANEL_DISPLAY_TYPES, @@ -20,6 +22,7 @@ describe('AnalyticsVisualizationPreview', () => { const findVisualizationButton = () => wrapper.findByTestId('select-visualization-button'); const findCodeButton = () => wrapper.findByTestId('select-code-button'); const findAiCubeQueryFeedback = () => wrapper.findComponent(AiCubeQueryFeedback); + const findHelpIcon = () => wrapper.findComponent(GlIcon); const selectDisplayType = jest.fn(); @@ -27,6 +30,9 @@ describe('AnalyticsVisualizationPreview', () => { const createWrapper = (props = {}) => { wrapper = shallowMountExtended(AnalyticsVisualizationPreview, { + directives: { + GlTooltip: createMockDirective('gl-tooltip'), + }, propsData: { selectedVisualizationType: '', displayType: '', @@ -48,6 +54,10 @@ describe('AnalyticsVisualizationPreview', () => { it('should render measurement headline', () => { expect(wrapper.findByTestId('measurement-hl').text()).toBe('Start by choosing a metric'); }); + + it('should not render the help icon', () => { + expect(findHelpIcon().exists()).toBe(false); + }); }); describe('when loading', () => { @@ -84,6 +94,17 @@ describe('AnalyticsVisualizationPreview', () => { findCodeButton().vm.$emit('click'); expect(wrapper.emitted('selectedDisplayType')).toEqual([[PANEL_DISPLAY_TYPES.CODE]]); }); + + it('should show an icon with a tooltip explaining the preview date range', () => { + const helpIcon = findHelpIcon(); + const tooltip = getBinding(helpIcon.element, 'gl-tooltip'); + + expect(helpIcon.props('name')).toBe('information-o'); + expect(helpIcon.attributes('title')).toBe( + 'The visualization preview displays only the last 7 days. Dashboard visualizations can display the entire date range.', + ); + expect(tooltip).toBeDefined(); + }); }); describe('when there is an AI prompt correlation id', () => { diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 7355cd8384a06629989f3b072239333605ed4b1b..4922f57c1b4aae27f6fc0f3d27bb6197c2c8da03 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -6151,6 +6151,9 @@ msgstr "" msgid "Analytics|Tables" msgstr "" +msgid "Analytics|The visualization preview displays only the last 7 days. Dashboard visualizations can display the entire date range." +msgstr "" + msgid "Analytics|There was a problem generating your query. Please try again." msgstr ""