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 5512cc2c89642e0211f43cc7f3e9eedcbcf66618..83e40405389c964eee2bdb7c9d7da0f0ea0af2a7 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 d6122729003ad3c8c5a918b60e6b0e391276310a..740807f2c735e2d3b4e4704db5a45268d47e4b0a 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 55a5e5b6f1771dfa4146ab84dad8b32874df7dad..04b548073affa2e6eb9d52420cedbe65a98bc4c9 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 c88875a71d58475309ca58fe0cfec82de92dc423..f64c9430b4d80750d5ce2de9029154f2efbb9504 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 c43d068de71a9957332ab8822f32b57f3d99bdaf..e7f4c55354e4194d9e7b0f9c3db650e14d4e08f9 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 8763a8e2cbfe3da1e5a5f3d72fbfb92234a2f6b0..e80cfc90e26ec2f5349f92fe8276a889d1db60b5 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 9cf4ff2422dc3def333eb84e88fd9d6f0acfa3a0..a6a698846c2b70e9fc532758209a173b6dcaed0f 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 34f4c677d543cd5934b8f741ecbc2da6fe9e5fac..30413f8de8c1c7d54bf9edfd9a10a54db737109c 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 d6b601784b30b50a69872861adf9b1e259d0eb60..f9b2b1bb8e5207cc172f013229d5c93a257fdc73 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 17a4f83d3de41c3885bc4f0f07b900042479cb14..646fd3601d2c98aa7a8f980a2c21f6ef7f9c1506 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 514a2e0b5ca182abc7fd04a47c5f939f6bc94129..a17446a3473b26f825ad11e1a958c2e14da71ca3 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 6d46d9c4e99ea1266de23f2dbbbc99a99c4b62a8..66bad7709a067f678a8bb831172708df70221cec 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 24760372d3d65acdd0961ab0ae710497bf65b1a8..62267c6a89548d9e37822211206f8f302411905d 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 04390b11a82ddccafb15a95b3c45ee96a7aca5e2..040b9fd1eec9e7abf9133bf709a757f9a6f0f523 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 707e225aab8ab896aeb01a5e842b3fcd84b7ee94..86eeff4d2e039d4bd29d520ffa023d08303f4d95 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 f11770a3edac998952e4408018816f931b7d2558..92ffbff0534f1ef22c11805ea31e6547e67df770 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 151c9a80475bbeee72506dfcdd8f16ae715a128f..567fede04363ff5ce573cc7222442fbb43b41eb7 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 2843621b111de97eeff6d194f706d99b6a99f0d9..3abe3accf0fd4880c5fbf140ca62e69d79970faf 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 63c08920b54d0549cc78b77fb5848bb9da3eb38f..fa6dec56fb6d2950f223629f5ddc98ce6239ab2f 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 baa58dea78474f4b7a7e25794f6efcaa5d859cb2..beeff16cb564fa60d92e6fedf64a573eb117c1be 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;