From 5a6226a22723245820ff1aad65c5d2d0319846c9 Mon Sep 17 00:00:00 2001 From: Jiaan Louw Date: Fri, 18 Jul 2025 14:50:23 +0200 Subject: [PATCH] Move analytics specific utils and constants Move utils and constants that are specific to analytics out of the vue shared directory and into the analytics dasshboard directory. This is in preperation for moving the current customizable dashboard component to the analytics dir. --- .../customizable_dashboard/constants.js | 17 --- .../customizable_dashboard.vue | 8 +- .../available_visualizations_drawer.vue | 8 +- .../customizable_dashboard/utils.js | 71 ------------ .../components/analytics_dashboard.vue | 6 +- .../components/analytics_data_explorer.vue | 2 - .../components/dashboards_list.vue | 3 +- .../analytics_visualization_type_selector.vue | 2 +- .../analytics_dashboards/constants.js | 16 ++- .../data_sources/cube_analytics.js | 4 +- .../analytics_dashboards/utils/index.js | 71 +++++++++++- .../components/analytics_dashboard_spec.js | 5 +- .../analytics_data_explorer_spec.js | 2 +- .../components/dashboards_list_spec.js | 3 +- .../analytics_dashboards/mock_data.js | 2 +- .../analytics_dashboards/utils/index_spec.js | 107 ++++++++++++++++- .../customizable_dashboard_spec.js | 2 +- .../gridstack_wrapper_spec.js | 6 +- .../customizable_dashboard/mock_data.js | 2 +- .../customizable_dashboard/utils_spec.js | 109 +----------------- 20 files changed, 217 insertions(+), 229 deletions(-) diff --git a/app/assets/javascripts/vue_shared/components/customizable_dashboard/constants.js b/app/assets/javascripts/vue_shared/components/customizable_dashboard/constants.js index 5512cc2c89642e..83e40405389c96 100644 --- a/app/assets/javascripts/vue_shared/components/customizable_dashboard/constants.js +++ b/app/assets/javascripts/vue_shared/components/customizable_dashboard/constants.js @@ -26,20 +26,3 @@ export const PANEL_POPOVER_DELAY = { }; export const CURSOR_GRABBING_CLASS = '!gl-cursor-grabbing'; - -export const NEW_DASHBOARD_SLUG = 'new'; - -export const CATEGORY_SINGLE_STATS = 'singleStats'; -export const CATEGORY_TABLES = 'tables'; -export const CATEGORY_CHARTS = 'charts'; - -export const DASHBOARD_STATUS_BETA = 'beta'; -export const DASHBOARD_STATUS_EXPERIMENT = 'experiment'; - -export const DASHBOARD_SCHEMA_VERSION = '2'; -export const VISUALIZATION_TYPE_DATA_TABLE = 'DataTable'; -export const VISUALIZATION_TYPE_LINE_CHART = 'LineChart'; -export const VISUALIZATION_TYPE_COLUMN_CHART = 'ColumnChart'; -export const VISUALIZATION_TYPE_SINGLE_STAT = 'SingleStat'; - -export const EVENT_LABEL_VIEWED_DASHBOARD_DESIGNER = 'user_viewed_dashboard_designer'; diff --git a/app/assets/javascripts/vue_shared/components/customizable_dashboard/customizable_dashboard.vue b/app/assets/javascripts/vue_shared/components/customizable_dashboard/customizable_dashboard.vue index d6122729003ad3..740807f2c735e2 100644 --- a/app/assets/javascripts/vue_shared/components/customizable_dashboard/customizable_dashboard.vue +++ b/app/assets/javascripts/vue_shared/components/customizable_dashboard/customizable_dashboard.vue @@ -8,14 +8,14 @@ import { s__, __ } from '~/locale'; import { InternalEvents } from '~/tracking'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal'; -import { EVENT_LABEL_VIEWED_DASHBOARD_DESIGNER } from './constants'; -import GridstackWrapper from './gridstack_wrapper.vue'; -import AvailableVisualizationsDrawer from './dashboard_editor/available_visualizations_drawer.vue'; +import { EVENT_LABEL_VIEWED_DASHBOARD_DESIGNER } from 'ee/analytics/analytics_dashboards/constants'; import { getDashboardConfig, availableVisualizationsValidator, createNewVisualizationPanel, -} from './utils'; +} from 'ee/analytics/analytics_dashboards/utils'; +import GridstackWrapper from './gridstack_wrapper.vue'; +import AvailableVisualizationsDrawer from './dashboard_editor/available_visualizations_drawer.vue'; export default { name: 'CustomizableDashboard', diff --git a/app/assets/javascripts/vue_shared/components/customizable_dashboard/dashboard_editor/available_visualizations_drawer.vue b/app/assets/javascripts/vue_shared/components/customizable_dashboard/dashboard_editor/available_visualizations_drawer.vue index 55a5e5b6f1771d..04b548073affa2 100644 --- a/app/assets/javascripts/vue_shared/components/customizable_dashboard/dashboard_editor/available_visualizations_drawer.vue +++ b/app/assets/javascripts/vue_shared/components/customizable_dashboard/dashboard_editor/available_visualizations_drawer.vue @@ -5,8 +5,12 @@ import { getContentWrapperHeight } from '~/lib/utils/dom_utils'; import { DRAWER_Z_INDEX } from '~/lib/utils/constants'; import { s__ } from '~/locale'; import { toggleArrayItem } from '~/lib/utils/array_utility'; -import { getVisualizationCategory } from '../utils'; -import { CATEGORY_SINGLE_STATS, CATEGORY_CHARTS, CATEGORY_TABLES } from '../constants'; +import { + CATEGORY_SINGLE_STATS, + CATEGORY_CHARTS, + CATEGORY_TABLES, +} from 'ee/analytics/analytics_dashboards/constants'; +import { getVisualizationCategory } from 'ee/analytics/analytics_dashboards/utils'; export default { name: 'AvailableVisualizatiosnDrawer', diff --git a/app/assets/javascripts/vue_shared/components/customizable_dashboard/utils.js b/app/assets/javascripts/vue_shared/components/customizable_dashboard/utils.js index c88875a71d5847..f64c9430b4d807 100644 --- a/app/assets/javascripts/vue_shared/components/customizable_dashboard/utils.js +++ b/app/assets/javascripts/vue_shared/components/customizable_dashboard/utils.js @@ -1,17 +1,4 @@ import isEmpty from 'lodash/isEmpty'; -import uniqueId from 'lodash/uniqueId'; - -import { humanize } from '~/lib/utils/text_utility'; -import { cloneWithoutReferences } from '~/lib/utils/common_utils'; - -import { - DASHBOARD_SCHEMA_VERSION, - VISUALIZATION_TYPE_DATA_TABLE, - VISUALIZATION_TYPE_SINGLE_STAT, - CATEGORY_SINGLE_STATS, - CATEGORY_CHARTS, - CATEGORY_TABLES, -} from './constants'; export const isEmptyPanelData = (visualizationType, data) => { if (visualizationType === 'SingleStat') { @@ -22,52 +9,6 @@ export const isEmptyPanelData = (visualizationType, data) => { return isEmpty(data); }; -/** - * Validator for the availableVisualizations property - */ -export const availableVisualizationsValidator = ({ loading, hasError, visualizations }) => { - return ( - typeof loading === 'boolean' && typeof hasError === 'boolean' && Array.isArray(visualizations) - ); -}; - -/** - * Get the category key for visualizations by their type. Default is "charts". - */ -export const getVisualizationCategory = (visualization) => { - if (visualization.type === VISUALIZATION_TYPE_SINGLE_STAT) { - return CATEGORY_SINGLE_STATS; - } - if (visualization.type === VISUALIZATION_TYPE_DATA_TABLE) { - return CATEGORY_TABLES; - } - return CATEGORY_CHARTS; -}; - -export const getUniquePanelId = () => uniqueId('panel-'); - -/** - * Maps a full hydrated dashboard (including GraphQL __typenames, and full visualization definitions) into a slimmed down version that complies with the dashboard schema definition - */ -export const getDashboardConfig = (hydratedDashboard) => { - const { __typename: dashboardTypename, userDefined, slug, ...dashboardRest } = hydratedDashboard; - - return { - ...dashboardRest, - version: DASHBOARD_SCHEMA_VERSION, - panels: hydratedDashboard.panels.map((panel) => { - const { __typename: panelTypename, id, ...panelRest } = panel; - const { __typename: visualizationTypename, ...visualizationRest } = panel.visualization; - - return { - ...panelRest, - queryOverrides: panel.queryOverrides ?? {}, - visualization: visualizationRest, - }; - }), - }; -}; - const filterUndefinedValues = (obj) => { // eslint-disable-next-line no-unused-vars return Object.fromEntries(Object.entries(obj).filter(([_, value]) => value !== undefined)); @@ -98,18 +39,6 @@ export const parsePanelToGridItem = ({ }, }); -export const createNewVisualizationPanel = (visualization) => ({ - id: getUniquePanelId(), - title: humanize(visualization.slug), - gridAttributes: { - width: 4, - height: 3, - }, - queryOverrides: {}, - options: {}, - visualization: cloneWithoutReferences({ ...visualization, errors: null }), -}); - export const dashboardConfigValidator = (config) => { if (config.panels) { if (!Array.isArray(config.panels)) return false; diff --git a/ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_dashboard.vue b/ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_dashboard.vue index c43d068de71a99..e7f4c55354e419 100644 --- a/ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_dashboard.vue +++ b/ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_dashboard.vue @@ -9,10 +9,6 @@ import { InternalEvents } from '~/tracking'; import CustomizableDashboard from '~/vue_shared/components/customizable_dashboard/customizable_dashboard.vue'; import ProductAnalyticsFeedbackBanner from 'ee/analytics/dashboards/components/product_analytics_feedback_banner.vue'; import ValueStreamFeedbackBanner from 'ee/analytics/dashboards/components/value_stream_feedback_banner.vue'; -import { - getDashboardConfig, - getUniquePanelId, -} from '~/vue_shared/components/customizable_dashboard/utils'; import { saveCustomDashboard } from 'ee/analytics/analytics_dashboards/api/dashboards_api'; import { BUILT_IN_PRODUCT_ANALYTICS_DASHBOARDS } from 'ee/analytics/dashboards/constants'; import UsageOverviewBackgroundAggregationWarning from 'ee/analytics/dashboards/components/usage_overview_background_aggregation_warning.vue'; @@ -20,7 +16,7 @@ import UrlSync, { HISTORY_REPLACE_UPDATE_METHOD, URL_SET_PARAMS_STRATEGY, } from '~/vue_shared/components/url_sync.vue'; -import { updateApolloCache } from '../utils'; +import { updateApolloCache, getDashboardConfig, getUniquePanelId } from '../utils'; import { AI_IMPACT_DASHBOARD, BUILT_IN_VALUE_STREAM_DASHBOARD, diff --git a/ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_data_explorer.vue b/ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_data_explorer.vue index 8763a8e2cbfe3d..e80cfc90e26ec2 100644 --- a/ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_data_explorer.vue +++ b/ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_data_explorer.vue @@ -16,8 +16,6 @@ import { saveProductAnalyticsVisualization } from 'ee/analytics/analytics_dashbo import { NEW_DASHBOARD_SLUG, VISUALIZATION_TYPE_DATA_TABLE, -} from '~/vue_shared/components/customizable_dashboard/constants'; -import { FILE_ALREADY_EXISTS_SERVER_RESPONSE, PANEL_DISPLAY_TYPES, EVENT_LABEL_USER_VIEWED_DATA_EXPLORER, diff --git a/ee/app/assets/javascripts/analytics/analytics_dashboards/components/dashboards_list.vue b/ee/app/assets/javascripts/analytics/analytics_dashboards/components/dashboards_list.vue index 9cf4ff2422dc3d..a6a698846c2b70 100644 --- a/ee/app/assets/javascripts/analytics/analytics_dashboards/components/dashboards_list.vue +++ b/ee/app/assets/javascripts/analytics/analytics_dashboards/components/dashboards_list.vue @@ -4,14 +4,13 @@ import { InternalEvents } from '~/tracking'; import { helpPagePath } from '~/helpers/help_page_helper'; import { createAlert } from '~/alert'; import PageHeading from '~/vue_shared/components/page_heading.vue'; -import { getDashboardConfig } from '~/vue_shared/components/customizable_dashboard/utils'; import { HTTP_STATUS_CREATED } from '~/lib/utils/http_status'; import { s__, __ } from '~/locale'; import { uniquifyString } from '~/lib/utils/text_utility'; import getAllCustomizableDashboardsQuery from '../graphql/queries/get_all_customizable_dashboards.query.graphql'; import getCustomizableDashboardQuery from '../graphql/queries/get_customizable_dashboard.query.graphql'; import { saveCustomDashboard } from '../api/dashboards_api'; -import { updateApolloCache } from '../utils'; +import { getDashboardConfig, updateApolloCache } from '../utils'; import DashboardListItem from './list/dashboard_list_item.vue'; const productAnalyticsOnboardingType = 'productAnalytics'; diff --git a/ee/app/assets/javascripts/analytics/analytics_dashboards/components/data_explorer/analytics_visualization_type_selector.vue b/ee/app/assets/javascripts/analytics/analytics_dashboards/components/data_explorer/analytics_visualization_type_selector.vue index 34f4c677d543cd..30413f8de8c1c7 100644 --- a/ee/app/assets/javascripts/analytics/analytics_dashboards/components/data_explorer/analytics_visualization_type_selector.vue +++ b/ee/app/assets/javascripts/analytics/analytics_dashboards/components/data_explorer/analytics_visualization_type_selector.vue @@ -6,7 +6,7 @@ import { VISUALIZATION_TYPE_LINE_CHART, VISUALIZATION_TYPE_COLUMN_CHART, VISUALIZATION_TYPE_SINGLE_STAT, -} from '~/vue_shared/components/customizable_dashboard/constants'; +} from 'ee/analytics/analytics_dashboards/constants'; const TYPES = [ { diff --git a/ee/app/assets/javascripts/analytics/analytics_dashboards/constants.js b/ee/app/assets/javascripts/analytics/analytics_dashboards/constants.js index d6b601784b30b5..f9b2b1bb8e5207 100644 --- a/ee/app/assets/javascripts/analytics/analytics_dashboards/constants.js +++ b/ee/app/assets/javascripts/analytics/analytics_dashboards/constants.js @@ -2,9 +2,10 @@ import { humanizeTimeInterval } from '~/lib/utils/datetime_utility'; import { __, s__ } from '~/locale'; import { helpPagePath } from '~/helpers/help_page_helper'; import { DORA_METRICS } from '~/analytics/shared/constants'; -import { DASHBOARD_SCHEMA_VERSION } from '~/vue_shared/components/customizable_dashboard/constants'; import { formatAsPercentage } from 'ee/analytics/dora/components/util'; +export const DASHBOARD_SCHEMA_VERSION = '2'; + export const EVENTS_TYPES = ['pageViews', 'linkClickEvents', 'events']; export const GRANULARITIES = [ @@ -200,3 +201,16 @@ export const VISUALIZATION_DOCUMENTATION_LINKS = { 'user/analytics/value_streams_dashboard.md#devsecops-metrics-comparison', ), }; + +export const NEW_DASHBOARD_SLUG = 'new'; + +export const VISUALIZATION_TYPE_DATA_TABLE = 'DataTable'; +export const VISUALIZATION_TYPE_LINE_CHART = 'LineChart'; +export const VISUALIZATION_TYPE_COLUMN_CHART = 'ColumnChart'; +export const VISUALIZATION_TYPE_SINGLE_STAT = 'SingleStat'; + +export const CATEGORY_SINGLE_STATS = 'singleStats'; +export const CATEGORY_TABLES = 'tables'; +export const CATEGORY_CHARTS = 'charts'; + +export const EVENT_LABEL_VIEWED_DASHBOARD_DESIGNER = 'user_viewed_dashboard_designer'; 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 17a4f83d3de41c..646fd3601d2c98 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 @@ -12,13 +12,11 @@ import { RETURNING_USERS_TABLE_NAME, SESSIONS_TABLE_NAME, TRACKED_EVENTS_KEY, -} from 'ee/analytics/analytics_dashboards/constants'; -import { VISUALIZATION_TYPE_DATA_TABLE, VISUALIZATION_TYPE_LINE_CHART, VISUALIZATION_TYPE_COLUMN_CHART, VISUALIZATION_TYPE_SINGLE_STAT, -} from '~/vue_shared/components/customizable_dashboard/constants'; +} from 'ee/analytics/analytics_dashboards/constants'; // This can be any value because the cube proxy adds the real API token. const CUBE_API_TOKEN = '1'; diff --git a/ee/app/assets/javascripts/analytics/analytics_dashboards/utils/index.js b/ee/app/assets/javascripts/analytics/analytics_dashboards/utils/index.js index 514a2e0b5ca182..a17446a3473b26 100644 --- a/ee/app/assets/javascripts/analytics/analytics_dashboards/utils/index.js +++ b/ee/app/assets/javascripts/analytics/analytics_dashboards/utils/index.js @@ -1,6 +1,17 @@ import produce from 'immer'; -import { SESSIONS_TABLE_NAME } from 'ee/analytics/analytics_dashboards/constants'; +import uniqueId from 'lodash/uniqueId'; +import { + SESSIONS_TABLE_NAME, + DASHBOARD_SCHEMA_VERSION, + CATEGORY_SINGLE_STATS, + CATEGORY_CHARTS, + CATEGORY_TABLES, + VISUALIZATION_TYPE_DATA_TABLE, + VISUALIZATION_TYPE_SINGLE_STAT, +} from 'ee/analytics/analytics_dashboards/constants'; import { DATE_RANGE_FILTER_DIMENSIONS } from 'ee/analytics/analytics_dashboards/data_sources/cube_analytics'; +import { humanize } from '~/lib/utils/text_utility'; +import { cloneWithoutReferences } from '~/lib/utils/common_utils'; import getAllCustomizableDashboardsQuery from '../graphql/queries/get_all_customizable_dashboards.query.graphql'; import getCustomizableDashboardQuery from '../graphql/queries/get_customizable_dashboard.query.graphql'; import { TYPENAME_ANALYTICS_DASHBOARD_PANEL } from '../graphql/constants'; @@ -173,3 +184,61 @@ export const updateApolloCache = ({ }); updateDashboardsListApolloCache({ apolloClient, slug, dashboard, fullPath, isProject, isGroup }); }; + +/** + * Get the category key for visualizations by their type. Default is "charts". + */ +export const getVisualizationCategory = (visualization) => { + if (visualization.type === VISUALIZATION_TYPE_SINGLE_STAT) { + return CATEGORY_SINGLE_STATS; + } + if (visualization.type === VISUALIZATION_TYPE_DATA_TABLE) { + return CATEGORY_TABLES; + } + return CATEGORY_CHARTS; +}; + +/** + * Maps a full hydrated dashboard (including GraphQL __typenames, and full visualization definitions) into a slimmed down version that complies with the dashboard schema definition + */ +export const getDashboardConfig = (hydratedDashboard) => { + const { __typename: dashboardTypename, userDefined, slug, ...dashboardRest } = hydratedDashboard; + + return { + ...dashboardRest, + version: DASHBOARD_SCHEMA_VERSION, + panels: hydratedDashboard.panels.map((panel) => { + const { __typename: panelTypename, id, ...panelRest } = panel; + const { __typename: visualizationTypename, ...visualizationRest } = panel.visualization; + + return { + ...panelRest, + queryOverrides: panel.queryOverrides ?? {}, + visualization: visualizationRest, + }; + }), + }; +}; + +export const getUniquePanelId = () => uniqueId('panel-'); + +export const createNewVisualizationPanel = (visualization) => ({ + id: getUniquePanelId(), + title: humanize(visualization.slug), + gridAttributes: { + width: 4, + height: 3, + }, + queryOverrides: {}, + options: {}, + visualization: cloneWithoutReferences({ ...visualization, errors: null }), +}); + +/** + * Validator for the availableVisualizations property + */ +export const availableVisualizationsValidator = ({ loading, hasError, visualizations }) => { + return ( + typeof loading === 'boolean' && typeof hasError === 'boolean' && Array.isArray(visualizations) + ); +}; diff --git a/ee/spec/frontend/analytics/analytics_dashboards/components/analytics_dashboard_spec.js b/ee/spec/frontend/analytics/analytics_dashboards/components/analytics_dashboard_spec.js index 6d46d9c4e99ea1..66bad7709a067f 100644 --- a/ee/spec/frontend/analytics/analytics_dashboards/components/analytics_dashboard_spec.js +++ b/ee/spec/frontend/analytics/analytics_dashboards/components/analytics_dashboard_spec.js @@ -88,7 +88,10 @@ jest.mock('ee/analytics/analytics_dashboards/api/dashboards_api', () => ({ saveCustomDashboard: jest.fn(), })); -jest.mock('ee/analytics/analytics_dashboards/utils'); +jest.mock('ee/analytics/analytics_dashboards/utils', () => ({ + ...jest.requireActual('ee/analytics/analytics_dashboards/utils'), + updateApolloCache: jest.fn(), +})); const showToast = jest.fn(); diff --git a/ee/spec/frontend/analytics/analytics_dashboards/components/analytics_data_explorer_spec.js b/ee/spec/frontend/analytics/analytics_dashboards/components/analytics_data_explorer_spec.js index 24760372d3d65a..62267c6a89548d 100644 --- a/ee/spec/frontend/analytics/analytics_dashboards/components/analytics_data_explorer_spec.js +++ b/ee/spec/frontend/analytics/analytics_dashboards/components/analytics_data_explorer_spec.js @@ -17,10 +17,10 @@ import AnalyticsDataExplorer from 'ee/analytics/analytics_dashboards/components/ import VisualizationTypeSelector from 'ee/analytics/analytics_dashboards/components/data_explorer/analytics_visualization_type_selector.vue'; import { + NEW_DASHBOARD_SLUG, EVENT_LABEL_USER_VIEWED_DATA_EXPLORER, EVENT_LABEL_USER_CREATED_CUSTOM_VISUALIZATION, } from 'ee/analytics/analytics_dashboards/constants'; -import { NEW_DASHBOARD_SLUG } from '~/vue_shared/components/customizable_dashboard/constants'; import { mockFilterOptions, TEST_CUSTOM_DASHBOARDS_PROJECT } from '../mock_data'; diff --git a/ee/spec/frontend/analytics/analytics_dashboards/components/dashboards_list_spec.js b/ee/spec/frontend/analytics/analytics_dashboards/components/dashboards_list_spec.js index 04390b11a82ddc..040b9fd1eec9e7 100644 --- a/ee/spec/frontend/analytics/analytics_dashboards/components/dashboards_list_spec.js +++ b/ee/spec/frontend/analytics/analytics_dashboards/components/dashboards_list_spec.js @@ -16,8 +16,7 @@ import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; import { saveCustomDashboard } from 'ee/analytics/analytics_dashboards/api/dashboards_api'; import { HTTP_STATUS_CREATED } from '~/lib/utils/http_status'; -import { getDashboardConfig } from '~/vue_shared/components/customizable_dashboard/utils'; -import { updateApolloCache } from 'ee/analytics/analytics_dashboards/utils'; +import { getDashboardConfig, updateApolloCache } from 'ee/analytics/analytics_dashboards/utils'; import { TEST_COLLECTOR_HOST, TEST_TRACKING_KEY, diff --git a/ee/spec/frontend/analytics/analytics_dashboards/mock_data.js b/ee/spec/frontend/analytics/analytics_dashboards/mock_data.js index 707e225aab8ab8..86eeff4d2e039d 100644 --- a/ee/spec/frontend/analytics/analytics_dashboards/mock_data.js +++ b/ee/spec/frontend/analytics/analytics_dashboards/mock_data.js @@ -1,5 +1,5 @@ import { TEST_HOST } from 'spec/test_constants'; -import { getUniquePanelId } from '~/vue_shared/components/customizable_dashboard/utils'; +import { getUniquePanelId } from 'ee/analytics/analytics_dashboards/utils'; import { FILTERED_SEARCH_TERM, OPERATORS_IS, diff --git a/ee/spec/frontend/analytics/analytics_dashboards/utils/index_spec.js b/ee/spec/frontend/analytics/analytics_dashboards/utils/index_spec.js index f11770a3edac99..92ffbff0534f1e 100644 --- a/ee/spec/frontend/analytics/analytics_dashboards/utils/index_spec.js +++ b/ee/spec/frontend/analytics/analytics_dashboards/utils/index_spec.js @@ -1,6 +1,12 @@ import getCustomizableDashboardQuery from 'ee/analytics/analytics_dashboards/graphql/queries/get_customizable_dashboard.query.graphql'; import getAllCustomizableDashboardsQuery from 'ee/analytics/analytics_dashboards/graphql/queries/get_all_customizable_dashboards.query.graphql'; import * as utils from 'ee/analytics/analytics_dashboards/utils'; +import { + DASHBOARD_SCHEMA_VERSION, + CATEGORY_SINGLE_STATS, + CATEGORY_CHARTS, + CATEGORY_TABLES, +} from 'ee/analytics/analytics_dashboards/constants'; import { mockFilterOptions, TEST_CUSTOM_DASHBOARDS_PROJECT, @@ -9,7 +15,10 @@ import { TEST_ALL_DASHBOARDS_GRAPHQL_SUCCESS_RESPONSE, TEST_DASHBOARD_GRAPHQL_SUCCESS_RESPONSE, } from 'ee_jest/analytics/analytics_dashboards/mock_data'; -import { dashboard } from 'jest/vue_shared/components/customizable_dashboard/mock_data'; +import { + dashboard, + createVisualization, +} from 'jest/vue_shared/components/customizable_dashboard/mock_data'; import { createMockClient } from 'helpers/mock_apollo_helper'; describe('Analytics dashboard utils', () => { @@ -276,4 +285,100 @@ describe('Analytics dashboard utils', () => { }); }); }); + + describe('getVisualizationCategory', () => { + it.each` + category | type + ${CATEGORY_SINGLE_STATS} | ${'SingleStat'} + ${CATEGORY_TABLES} | ${'DataTable'} + ${CATEGORY_CHARTS} | ${'LineChart'} + ${CATEGORY_CHARTS} | ${'FooBar'} + `('returns $category when the visualization type is $type', ({ category, type }) => { + expect(utils.getVisualizationCategory({ type })).toBe(category); + }); + }); + + describe('getDashboardConfig', () => { + it('maps dashboard to expected value', () => { + const result = utils.getDashboardConfig(dashboard); + const visualization = createVisualization(); + + expect(result).toMatchObject({ + id: 'analytics_overview', + version: DASHBOARD_SCHEMA_VERSION, + panels: [ + { + gridAttributes: { + height: 3, + width: 3, + }, + queryOverrides: {}, + title: 'Test A', + visualization, + }, + { + gridAttributes: { + height: 4, + width: 2, + }, + queryOverrides: { + limit: 200, + }, + title: 'Test B', + visualization, + }, + ], + title: 'Analytics Overview', + status: null, + errors: null, + }); + }); + + ['userDefined', 'slug'].forEach((omitted) => { + it(`omits "${omitted}" dashboard property`, () => { + const result = utils.getDashboardConfig(dashboard); + + expect(result[omitted]).not.toBeDefined(); + }); + }); + }); + + describe('availableVisualizationsValidator', () => { + it('returns true when the object contains all properties', () => { + const result = utils.availableVisualizationsValidator({ + loading: false, + hasError: false, + visualizations: [], + }); + expect(result).toBe(true); + }); + + it.each([ + { visualizations: [] }, + { hasError: false }, + { loading: true }, + { loading: true, hasError: false }, + ])('returns false when the object does not contain all properties', (testCase) => { + const result = utils.availableVisualizationsValidator(testCase); + expect(result).toBe(false); + }); + }); + + describe('#createNewVisualizationPanel', () => { + it('returns the expected object', () => { + const visualization = createVisualization(); + expect(utils.createNewVisualizationPanel(visualization)).toMatchObject({ + visualization: { + ...visualization, + errors: null, + }, + title: 'Test visualization', + gridAttributes: { + width: 4, + height: 3, + }, + options: {}, + }); + }); + }); }); diff --git a/spec/frontend/vue_shared/components/customizable_dashboard/customizable_dashboard_spec.js b/spec/frontend/vue_shared/components/customizable_dashboard/customizable_dashboard_spec.js index 151c9a80475bbe..567fede04363ff 100644 --- a/spec/frontend/vue_shared/components/customizable_dashboard/customizable_dashboard_spec.js +++ b/spec/frontend/vue_shared/components/customizable_dashboard/customizable_dashboard_spec.js @@ -11,7 +11,7 @@ import AvailableVisualizationsDrawer from '~/vue_shared/components/customizable_ import { EVENT_LABEL_VIEWED_DASHBOARD_DESIGNER, DASHBOARD_SCHEMA_VERSION, -} from '~/vue_shared/components/customizable_dashboard/constants'; +} from 'ee/analytics/analytics_dashboards/constants'; import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal'; import { stubComponent } from 'helpers/stub_component'; import { trimText } from 'helpers/text_helper'; diff --git a/spec/frontend/vue_shared/components/customizable_dashboard/gridstack_wrapper_spec.js b/spec/frontend/vue_shared/components/customizable_dashboard/gridstack_wrapper_spec.js index 2843621b111de9..3abe3accf0fd48 100644 --- a/spec/frontend/vue_shared/components/customizable_dashboard/gridstack_wrapper_spec.js +++ b/spec/frontend/vue_shared/components/customizable_dashboard/gridstack_wrapper_spec.js @@ -10,12 +10,10 @@ import { GRIDSTACK_CELL_HEIGHT, GRIDSTACK_MIN_ROW, } from '~/vue_shared/components/customizable_dashboard/constants'; +import { createNewVisualizationPanel } from 'ee/analytics/analytics_dashboards/utils'; import { loadCSSFile } from '~/lib/utils/css_utils'; import waitForPromises from 'helpers/wait_for_promises'; -import { - parsePanelToGridItem, - createNewVisualizationPanel, -} from '~/vue_shared/components/customizable_dashboard/utils'; +import { parsePanelToGridItem } from '~/vue_shared/components/customizable_dashboard/utils'; import { dashboard, builtinDashboard } from './mock_data'; const mockGridSetStatic = jest.fn(); diff --git a/spec/frontend/vue_shared/components/customizable_dashboard/mock_data.js b/spec/frontend/vue_shared/components/customizable_dashboard/mock_data.js index 63c08920b54d05..fa6dec56fb6d29 100644 --- a/spec/frontend/vue_shared/components/customizable_dashboard/mock_data.js +++ b/spec/frontend/vue_shared/components/customizable_dashboard/mock_data.js @@ -1,4 +1,4 @@ -import { getUniquePanelId } from '~/vue_shared/components/customizable_dashboard/utils'; +import { getUniquePanelId } from 'ee/analytics/analytics_dashboards/utils'; export const createVisualization = () => ({ version: 1, diff --git a/spec/frontend/vue_shared/components/customizable_dashboard/utils_spec.js b/spec/frontend/vue_shared/components/customizable_dashboard/utils_spec.js index baa58dea78474f..beeff16cb564fa 100644 --- a/spec/frontend/vue_shared/components/customizable_dashboard/utils_spec.js +++ b/spec/frontend/vue_shared/components/customizable_dashboard/utils_spec.js @@ -1,39 +1,10 @@ import { isEmptyPanelData, - availableVisualizationsValidator, - getDashboardConfig, - getVisualizationCategory, parsePanelToGridItem, - createNewVisualizationPanel, dashboardConfigValidator, } from '~/vue_shared/components/customizable_dashboard/utils'; -import { - CATEGORY_SINGLE_STATS, - CATEGORY_CHARTS, - CATEGORY_TABLES, - DASHBOARD_SCHEMA_VERSION, -} from '~/vue_shared/components/customizable_dashboard/constants'; - -import { dashboard, mockPanel, createVisualization } from './mock_data'; - -describe('#createNewVisualizationPanel', () => { - it('returns the expected object', () => { - const visualization = createVisualization(); - expect(createNewVisualizationPanel(visualization)).toMatchObject({ - visualization: { - ...visualization, - errors: null, - }, - title: 'Test visualization', - gridAttributes: { - width: 4, - height: 3, - }, - options: {}, - }); - }); -}); +import { dashboard, mockPanel } from './mock_data'; describe('isEmptyPanelData', () => { it.each` @@ -51,84 +22,6 @@ describe('isEmptyPanelData', () => { ); }); -describe('availableVisualizationsValidator', () => { - it('returns true when the object contains all properties', () => { - const result = availableVisualizationsValidator({ - loading: false, - hasError: false, - visualizations: [], - }); - expect(result).toBe(true); - }); - - it.each([ - { visualizations: [] }, - { hasError: false }, - { loading: true }, - { loading: true, hasError: false }, - ])('returns false when the object does not contain all properties', (testCase) => { - const result = availableVisualizationsValidator(testCase); - expect(result).toBe(false); - }); -}); - -describe('getDashboardConfig', () => { - it('maps dashboard to expected value', () => { - const result = getDashboardConfig(dashboard); - const visualization = createVisualization(); - - expect(result).toMatchObject({ - id: 'analytics_overview', - version: DASHBOARD_SCHEMA_VERSION, - panels: [ - { - gridAttributes: { - height: 3, - width: 3, - }, - queryOverrides: {}, - title: 'Test A', - visualization, - }, - { - gridAttributes: { - height: 4, - width: 2, - }, - queryOverrides: { - limit: 200, - }, - title: 'Test B', - visualization, - }, - ], - title: 'Analytics Overview', - status: null, - errors: null, - }); - }); - - ['userDefined', 'slug'].forEach((omitted) => { - it(`omits "${omitted}" dashboard property`, () => { - const result = getDashboardConfig(dashboard); - - expect(result[omitted]).not.toBeDefined(); - }); - }); -}); - -describe('getVisualizationCategory', () => { - it.each` - category | type - ${CATEGORY_SINGLE_STATS} | ${'SingleStat'} - ${CATEGORY_TABLES} | ${'DataTable'} - ${CATEGORY_CHARTS} | ${'LineChart'} - ${CATEGORY_CHARTS} | ${'FooBar'} - `('returns $category when the visualization type is $type', ({ category, type }) => { - expect(getVisualizationCategory({ type })).toBe(category); - }); -}); - describe('parsePanelToGridItem', () => { it('parses all panel configs to GridStack format', () => { const { gridAttributes, ...rest } = mockPanel; -- GitLab