diff --git a/redisinsight/ui/src/components/config/Config.spec.tsx b/redisinsight/ui/src/components/config/Config.spec.tsx index b7134bd176..c4f4aa65de 100644 --- a/redisinsight/ui/src/components/config/Config.spec.tsx +++ b/redisinsight/ui/src/components/config/Config.spec.tsx @@ -2,7 +2,7 @@ import React from 'react' import { cloneDeep } from 'lodash' import { BuildType } from 'uiSrc/constants/env' import { localStorageService } from 'uiSrc/services' -import { setFeaturesToHighlight, setOnboarding } from 'uiSrc/slices/app/features' +import { getFeatureFlags, setFeaturesToHighlight, setOnboarding } from 'uiSrc/slices/app/features' import { getNotifications } from 'uiSrc/slices/app/notifications' import { render, mockedStore, cleanup, MOCKED_HIGHLIGHTING_FEATURES } from 'uiSrc/utils/test-utils' @@ -63,6 +63,7 @@ describe('Config', () => { getNotifications(), getWBGuides(), getWBTutorials(), + getFeatureFlags(), getUserConfigSettings(), ] expect(store.getActions()).toEqual([...afterRenderActions]) @@ -95,6 +96,7 @@ describe('Config', () => { getNotifications(), getWBGuides(), getWBTutorials(), + getFeatureFlags(), getUserConfigSettings(), setSettingsPopupState(true), ] diff --git a/redisinsight/ui/src/components/config/Config.tsx b/redisinsight/ui/src/components/config/Config.tsx index da0c53696b..1fec3b36c9 100644 --- a/redisinsight/ui/src/components/config/Config.tsx +++ b/redisinsight/ui/src/components/config/Config.tsx @@ -6,7 +6,7 @@ import { BrowserStorageItem } from 'uiSrc/constants' import { BuildType } from 'uiSrc/constants/env' import { BUILD_FEATURES } from 'uiSrc/constants/featuresHighlighting' import { localStorageService } from 'uiSrc/services' -import { setFeaturesToHighlight, setOnboarding } from 'uiSrc/slices/app/features' +import { fetchFeatureFlags, setFeaturesToHighlight, setOnboarding } from 'uiSrc/slices/app/features' import { fetchNotificationsAction } from 'uiSrc/slices/app/notifications' import { @@ -53,6 +53,8 @@ const Config = () => { dispatch(fetchGuides()) dispatch(fetchTutorials()) + dispatch(fetchFeatureFlags()) + // fetch config settings, after that take spec if (pathname !== SETTINGS_PAGE_PATH) { dispatch(fetchUserConfigSettings(() => dispatch(fetchUserSettingsSpec()))) diff --git a/redisinsight/ui/src/components/feature-flag-component/FeatureFlagComponent.spec.tsx b/redisinsight/ui/src/components/feature-flag-component/FeatureFlagComponent.spec.tsx new file mode 100644 index 0000000000..8149c07827 --- /dev/null +++ b/redisinsight/ui/src/components/feature-flag-component/FeatureFlagComponent.spec.tsx @@ -0,0 +1,45 @@ +import React from 'react' +import { render, screen } from 'uiSrc/utils/test-utils' + +import { appFeatureFlagsFeaturesSelector } from 'uiSrc/slices/app/features' +import { FeatureFlags } from 'uiSrc/constants' + +import FeatureFlagComponent from './FeatureFlagComponent' + +jest.mock('uiSrc/slices/app/features', () => ({ + ...jest.requireActual('uiSrc/slices/app/features'), + appFeatureFlagsFeaturesSelector: jest.fn().mockReturnValue({ + name: { + flag: false + } + }), +})) + +const InnerComponent = () => () +describe('FeatureFlagComponent', () => { + it('should not render component by default', () => { + render( + + + + ) + + expect(screen.queryByTestId('inner-component')).not.toBeInTheDocument() + }) + + it('should render component', () => { + (appFeatureFlagsFeaturesSelector as jest.Mock).mockReturnValueOnce({ + name: { + flag: true + } + }) + + render( + + + + ) + + expect(screen.getByTestId('inner-component')).toBeInTheDocument() + }) +}) diff --git a/redisinsight/ui/src/components/feature-flag-component/FeatureFlagComponent.tsx b/redisinsight/ui/src/components/feature-flag-component/FeatureFlagComponent.tsx new file mode 100644 index 0000000000..4a717b1b83 --- /dev/null +++ b/redisinsight/ui/src/components/feature-flag-component/FeatureFlagComponent.tsx @@ -0,0 +1,19 @@ +import React from 'react' +import { useSelector } from 'react-redux' +import { FeatureFlags } from 'uiSrc/constants' +import { appFeatureFlagsFeaturesSelector } from 'uiSrc/slices/app/features' + +export interface Props { + name: FeatureFlags + children: React.ReactElement +} + +const FeatureFlagComponent = (props: Props) => { + const { children, name } = props + const { [name]: feature } = useSelector(appFeatureFlagsFeaturesSelector) + const { flag, variant } = feature ?? { flag: false } + + return flag ? React.cloneElement(children, { variant }) : null +} + +export default FeatureFlagComponent diff --git a/redisinsight/ui/src/components/feature-flag-component/index.ts b/redisinsight/ui/src/components/feature-flag-component/index.ts new file mode 100644 index 0000000000..0061aed91d --- /dev/null +++ b/redisinsight/ui/src/components/feature-flag-component/index.ts @@ -0,0 +1,3 @@ +import FeatureFlagComponent from './FeatureFlagComponent' + +export default FeatureFlagComponent diff --git a/redisinsight/ui/src/components/global-subscriptions/CommonAppSubscription/CommonAppSubscription.tsx b/redisinsight/ui/src/components/global-subscriptions/CommonAppSubscription/CommonAppSubscription.tsx index 757da3a2ac..e4726f72bf 100644 --- a/redisinsight/ui/src/components/global-subscriptions/CommonAppSubscription/CommonAppSubscription.tsx +++ b/redisinsight/ui/src/components/global-subscriptions/CommonAppSubscription/CommonAppSubscription.tsx @@ -3,7 +3,7 @@ import { useDispatch, useSelector } from 'react-redux' import { io, Socket } from 'socket.io-client' import { remove } from 'lodash' -import { SocketEvent } from 'uiSrc/constants' +import { SocketEvent, SocketFeaturesEvent } from 'uiSrc/constants' import { NotificationEvent } from 'uiSrc/constants/notifications' import { setNewNotificationAction } from 'uiSrc/slices/app/notifications' import { setIsConnected } from 'uiSrc/slices/app/socket-connection' @@ -11,6 +11,7 @@ import { getBaseApiUrl, Nullable } from 'uiSrc/utils' import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' import { setTotalUnread } from 'uiSrc/slices/recommendations/recommendations' import { RecommendationsSocketEvents } from 'uiSrc/constants/recommendations' +import { getFeatureFlagsSuccess } from 'uiSrc/slices/app/features' const CommonAppSubscription = () => { const { id: instanceId } = useSelector(connectedInstanceSelector) @@ -38,6 +39,13 @@ const CommonAppSubscription = () => { dispatch(setNewNotificationAction(data)) }) + socketRef.current.on(SocketFeaturesEvent.Features, (data) => { + dispatch(getFeatureFlagsSuccess(data)) + + // or + // dispatch(fetchFeatureFlags()) + }) + // Catch disconnect socketRef.current?.on(SocketEvent.Disconnect, () => { unSubscribeFromAllRecommendations() diff --git a/redisinsight/ui/src/components/index.ts b/redisinsight/ui/src/components/index.ts index 9261f2c7ca..495a8350fb 100644 --- a/redisinsight/ui/src/components/index.ts +++ b/redisinsight/ui/src/components/index.ts @@ -25,6 +25,7 @@ import CodeBlock from './code-block' import ShowChildByCondition from './show-child-by-condition' import RecommendationVoting from './recommendation-voting' import RecommendationCopyComponent from './recommendation-copy-component' +import FeatureFlagComponent from './feature-flag-component' export { NavigationMenu, @@ -57,4 +58,5 @@ export { ShowChildByCondition, RecommendationVoting, RecommendationCopyComponent, + FeatureFlagComponent, } diff --git a/redisinsight/ui/src/constants/api.ts b/redisinsight/ui/src/constants/api.ts index 3695f8ac1e..cb530c0165 100644 --- a/redisinsight/ui/src/constants/api.ts +++ b/redisinsight/ui/src/constants/api.ts @@ -109,6 +109,8 @@ enum ApiEndpoints { REDISEARCH = 'redisearch', REDISEARCH_SEARCH = 'redisearch/search', HISTORY = 'history', + + FEATURES = 'features', } export const DEFAULT_SEARCH_MATCH = '*' diff --git a/redisinsight/ui/src/constants/featureFlags.ts b/redisinsight/ui/src/constants/featureFlags.ts new file mode 100644 index 0000000000..7ad469600d --- /dev/null +++ b/redisinsight/ui/src/constants/featureFlags.ts @@ -0,0 +1,3 @@ +export enum FeatureFlags { + liveRecommendations = 'liveRecommendations' +} diff --git a/redisinsight/ui/src/constants/index.ts b/redisinsight/ui/src/constants/index.ts index 2dd89c36c9..a424dea36d 100644 --- a/redisinsight/ui/src/constants/index.ts +++ b/redisinsight/ui/src/constants/index.ts @@ -25,4 +25,5 @@ export * from './durationUnits' export * from './streamViews' export * from './bulkActions' export * from './workbench' +export * from './featureFlags' export { ApiEndpoints, BrowserStorageItem, ApiStatusCode, apiErrors } diff --git a/redisinsight/ui/src/constants/socketEvents.ts b/redisinsight/ui/src/constants/socketEvents.ts index 903cdb29f9..303c58d6c3 100644 --- a/redisinsight/ui/src/constants/socketEvents.ts +++ b/redisinsight/ui/src/constants/socketEvents.ts @@ -3,3 +3,7 @@ export enum SocketEvent { Disconnect = 'disconnect', ConnectionError = 'connect_error', } + +export enum SocketFeaturesEvent { + Features = 'features' +} diff --git a/redisinsight/ui/src/pages/instance/InstancePage.spec.tsx b/redisinsight/ui/src/pages/instance/InstancePage.spec.tsx index 6b73edf8f2..5674b8bec9 100644 --- a/redisinsight/ui/src/pages/instance/InstancePage.spec.tsx +++ b/redisinsight/ui/src/pages/instance/InstancePage.spec.tsx @@ -6,6 +6,7 @@ import { instance, mock } from 'ts-mockito' import { cleanup, mockedStore, render } from 'uiSrc/utils/test-utils' import { BrowserStorageItem } from 'uiSrc/constants' import { localStorageService } from 'uiSrc/services' +import { appFeatureFlagsFeaturesSelector } from 'uiSrc/slices/app/features' import InstancePage, { getDefaultSizes, Props } from './InstancePage' const mockedProps = mock() @@ -17,6 +18,15 @@ jest.mock('uiSrc/services', () => ({ }, })) +jest.mock('uiSrc/slices/app/features', () => ({ + ...jest.requireActual('uiSrc/slices/app/features'), + appFeatureFlagsFeaturesSelector: jest.fn().mockReturnValue({ + liveRecommendations: { + flag: false + } + }), +})) + let store: typeof mockedStore beforeEach(() => { cleanup() @@ -50,7 +60,22 @@ describe('InstancePage', () => { expect(queryByTestId('expand-cli')).toBeInTheDocument() }) - it('should render with LiveTimeRecommendations Component', () => { + it('should not render LiveTimeRecommendations Component by default', () => { + const { queryByTestId } = render( + + + + ) + + expect(queryByTestId('recommendations-trigger')).not.toBeInTheDocument() + }) + + it('should render LiveTimeRecommendations Component with feature flag', () => { + (appFeatureFlagsFeaturesSelector as jest.Mock).mockReturnValueOnce({ + liveRecommendations: { + flag: true + } + }) const { queryByTestId } = render( diff --git a/redisinsight/ui/src/pages/instance/InstancePage.tsx b/redisinsight/ui/src/pages/instance/InstancePage.tsx index 07dc55baff..df3e1428b1 100644 --- a/redisinsight/ui/src/pages/instance/InstancePage.tsx +++ b/redisinsight/ui/src/pages/instance/InstancePage.tsx @@ -6,12 +6,16 @@ import cx from 'classnames' import { setInitialAnalyticsSettings } from 'uiSrc/slices/analytics/settings' import { - fetchConnectedInstanceAction, fetchConnectedInstanceInfoAction, + fetchConnectedInstanceAction, + fetchConnectedInstanceInfoAction, fetchInstancesAction, getDatabaseConfigInfoAction, instancesSelector, } from 'uiSrc/slices/instances/instances' -import { fetchRecommendationsAction, resetRecommendationsHighlighting } from 'uiSrc/slices/recommendations/recommendations' +import { + fetchRecommendationsAction, + resetRecommendationsHighlighting +} from 'uiSrc/slices/recommendations/recommendations' import { appContextSelector, setAppContextConnectedInstanceId, @@ -19,8 +23,9 @@ import { setDbConfig, } from 'uiSrc/slices/app/context' import { resetPatternKeysData } from 'uiSrc/slices/browser/keys' -import { BrowserStorageItem } from 'uiSrc/constants' +import { BrowserStorageItem, FeatureFlags } from 'uiSrc/constants' import { localStorageService } from 'uiSrc/services' +import { FeatureFlagComponent } from 'uiSrc/components' import { resetOutput } from 'uiSrc/slices/cli/cli-output' import { cliSettingsSelector } from 'uiSrc/slices/cli/cli-settings' import BottomGroupComponents from 'uiSrc/components/bottom-group-components/BottomGroupComponents' @@ -123,7 +128,9 @@ const InstancePage = ({ routes = [] }: Props) => { return ( <> - + + + { + state.featureFlags.loading = true + }, + getFeatureFlagsSuccess: (state, { payload }) => { + state.featureFlags.loading = false + state.featureFlags.features = payload.features + }, + getFeatureFlagsFailure: (state) => { + state.featureFlags.loading = false + }, } }) @@ -92,7 +110,10 @@ export const { skipOnboarding, setOnboardPrevStep, setOnboardNextStep, - setOnboarding + setOnboarding, + getFeatureFlags, + getFeatureFlagsSuccess, + getFeatureFlagsFailure } = appFeaturesSlice.actions export const appFeatureSelector = (state: RootState) => state.app.features @@ -100,6 +121,8 @@ export const appFeatureHighlightingSelector = (state: RootState) => state.app.fe export const appFeaturePagesHighlightingSelector = (state: RootState) => state.app.features.highlighting.pages export const appFeatureOnboardingSelector = (state: RootState) => state.app.features.onboarding +export const appFeatureFlagsSelector = (state: RootState) => state.app.features.featureFlags +export const appFeatureFlagsFeaturesSelector = (state: RootState) => state.app.features.featureFlags.features export default appFeaturesSlice.reducer @@ -113,3 +136,26 @@ export function incrementOnboardStepAction(step: OnboardingSteps, skipCount = 0, } } } + +export function fetchFeatureFlags( + onSuccessAction?: (data: any) => void, + onFailAction?: () => void +) { + return async (dispatch: AppDispatch) => { + dispatch(getFeatureFlags()) + + try { + const { data, status } = await apiService.get( + ApiEndpoints.FEATURES + ) + + if (isStatusSuccessful(status)) { + dispatch(getFeatureFlagsSuccess(data)) + onSuccessAction?.(data) + } + } catch (error) { + dispatch(getFeatureFlagsFailure()) + onFailAction?.() + } + } +} diff --git a/redisinsight/ui/src/slices/interfaces/app.ts b/redisinsight/ui/src/slices/interfaces/app.ts index 260801ade1..7623de7439 100644 --- a/redisinsight/ui/src/slices/interfaces/app.ts +++ b/redisinsight/ui/src/slices/interfaces/app.ts @@ -1,7 +1,7 @@ import { AxiosError } from 'axios' import { RelativeWidthSizes } from 'uiSrc/components/virtual-table/interfaces' import { Nullable } from 'uiSrc/utils' -import { DurationUnits, ICommands } from 'uiSrc/constants' +import { DurationUnits, FeatureFlags, ICommands } from 'uiSrc/constants' import { IKeyPropTypes } from 'uiSrc/constants/prop-types/keys' import { GetServerInfoResponse } from 'apiSrc/modules/server/dto/server.dto' import { RedisString as RedisStringAPI } from 'apiSrc/common/constants/redis-string' @@ -146,6 +146,11 @@ export interface StateAppSocketConnection { isConnected: boolean } +export interface FeatureFlagComponent { + flag: boolean + variant?: string +} + export interface StateAppFeatures { highlighting: { version: string @@ -158,6 +163,12 @@ export interface StateAppFeatures { currentStep: number totalSteps: number isActive: boolean + }, + featureFlags: { + loading: boolean + features: { + [key in FeatureFlags]?: FeatureFlagComponent + } } } export enum NotificationType { diff --git a/redisinsight/ui/src/slices/tests/app/features.spec.ts b/redisinsight/ui/src/slices/tests/app/features.spec.ts index ce598b937a..429adbf49b 100644 --- a/redisinsight/ui/src/slices/tests/app/features.spec.ts +++ b/redisinsight/ui/src/slices/tests/app/features.spec.ts @@ -9,7 +9,11 @@ import reducer, { skipOnboarding, setOnboardPrevStep, setOnboardNextStep, - incrementOnboardStepAction + incrementOnboardStepAction, + getFeatureFlags, + getFeatureFlagsSuccess, + getFeatureFlagsFailure, + fetchFeatureFlags } from 'uiSrc/slices/app/features' import { cleanup, @@ -18,6 +22,7 @@ import { mockedStore, mockStore } from 'uiSrc/utils/test-utils' +import { apiService } from 'uiSrc/services' let store: typeof mockedStore beforeEach(() => { @@ -366,6 +371,87 @@ describe('slices', () => { }) }) + describe('getFeatureFlags', () => { + it('should properly set state', () => { + const state = { + ...initialState, + featureFlags: { + ...initialState.featureFlags, + loading: true + } + } + + // Act + const nextState = reducer(initialState, getFeatureFlags()) + + // Assert + const rootState = Object.assign(initialStateDefault, { + app: { features: nextState }, + }) + + expect(appFeatureSelector(rootState)).toEqual(state) + }) + }) + + describe('getFeatureFlagsSuccess', () => { + it('should properly set state', () => { + const payload = { + features: { + liveRecommendations: { + flag: true + } + } + } + const state = { + ...initialState, + featureFlags: { + ...initialState.featureFlags, + features: payload.features, + } + } + + // Act + const nextState = reducer(initialState, getFeatureFlagsSuccess(payload)) + + // Assert + const rootState = Object.assign(initialStateDefault, { + app: { features: nextState }, + }) + + expect(appFeatureSelector(rootState)).toEqual(state) + }) + }) + + describe('getFeatureFlagsFailure', () => { + it('should properly set state', () => { + const currentState = { + ...initialState, + featureFlags: { + ...initialState.featureFlags, + loading: true + } + } + + const state = { + ...initialState, + featureFlags: { + ...initialState.featureFlags, + loading: false + } + } + + // Act + const nextState = reducer(currentState, getFeatureFlagsFailure()) + + // Assert + const rootState = Object.assign(initialStateDefault, { + app: { features: nextState }, + }) + + expect(appFeatureSelector(rootState)).toEqual(state) + }) + }) + // thunks describe('incrementOnboardStepAction', () => { it('should call setOnboardNextStep', async () => { @@ -431,4 +517,48 @@ describe('slices', () => { expect(mockedStore.getActions()).toEqual([]) }) }) + + describe('fetchFeatureFlags', () => { + it('succeed to fetch data', async () => { + // Arrange + const data = { features: { liveRecommendations: true } } + const responsePayload = { data, status: 200 } + + apiService.get = jest.fn().mockResolvedValue(responsePayload) + + // Act + await store.dispatch(fetchFeatureFlags()) + + // Assert + const expectedActions = [ + getFeatureFlags(), + getFeatureFlagsSuccess(data), + ] + + expect(store.getActions()).toEqual(expectedActions) + }) + + it('failed to fetch data', async () => { + const errorMessage = 'Something was wrong!' + const responsePayload = { + response: { + status: 500, + data: { message: errorMessage }, + }, + } + + apiService.get = jest.fn().mockRejectedValue(responsePayload) + + // Act + await store.dispatch(fetchFeatureFlags()) + + // Assert + const expectedActions = [ + getFeatureFlags(), + getFeatureFlagsFailure(), + ] + + expect(store.getActions()).toEqual(expectedActions) + }) + }) }) diff --git a/redisinsight/ui/src/telemetry/checkAnalytics.ts b/redisinsight/ui/src/telemetry/checkAnalytics.ts index 5ee4be792a..c38c2ac51e 100644 --- a/redisinsight/ui/src/telemetry/checkAnalytics.ts +++ b/redisinsight/ui/src/telemetry/checkAnalytics.ts @@ -5,4 +5,5 @@ import store from 'uiSrc/slices/store' export const checkIsAnalyticsGranted = () => !!get(store.getState(), 'user.settings.config.agreements.analytics', false) +export const getInfoServer = () => get(store.getState(), 'app.info.server', {}) export const getAppType = () => get(store.getState(), 'app.info.server.appType') diff --git a/redisinsight/ui/src/telemetry/interfaces.ts b/redisinsight/ui/src/telemetry/interfaces.ts index 87c4fe84c2..ee9243509b 100644 --- a/redisinsight/ui/src/telemetry/interfaces.ts +++ b/redisinsight/ui/src/telemetry/interfaces.ts @@ -8,7 +8,15 @@ export interface ITelemetryIdentify { export interface ITelemetryService { initialize(): Promise - pageView(name: string, appType: string, databaseId?: string): Promise + pageView( + name: string, + params: { + buildType?: string + controlNumber?: number + controlGroup?: string + databaseId?: string + } + ): Promise identify(opts: ITelemetryIdentify): Promise event(opts: ITelemetryEvent): Promise anonymousId: string diff --git a/redisinsight/ui/src/telemetry/segment.ts b/redisinsight/ui/src/telemetry/segment.ts index 035d02a7ff..db3b9b26c9 100644 --- a/redisinsight/ui/src/telemetry/segment.ts +++ b/redisinsight/ui/src/telemetry/segment.ts @@ -51,12 +51,15 @@ export class SegmentTelemetryService implements ITelemetryService { return this._anonymousId } - async pageView(name: string, appType: string, databaseId?: string): Promise { + async pageView( + name: string, + properties: object + ): Promise { return new Promise((resolve, reject) => { try { const pageInfo = this._getPageInfo() const { page = {} } = { ...pageInfo } - window.analytics.page(name, { databaseId, buildType: appType, ...page }, { + window.analytics.page(name, { ...properties, ...page }, { context: { ip: '0.0.0.0', ...pageInfo diff --git a/redisinsight/ui/src/telemetry/telemetryUtils.ts b/redisinsight/ui/src/telemetry/telemetryUtils.ts index 6217739b37..ed4659cc55 100644 --- a/redisinsight/ui/src/telemetry/telemetryUtils.ts +++ b/redisinsight/ui/src/telemetry/telemetryUtils.ts @@ -10,7 +10,7 @@ import { localStorageService } from 'uiSrc/services' import { ApiEndpoints, BrowserStorageItem, KeyTypes, StreamViews } from 'uiSrc/constants' import { KeyViewType } from 'uiSrc/slices/interfaces/keys' import { StreamViewType } from 'uiSrc/slices/interfaces/stream' -import { checkIsAnalyticsGranted, getAppType } from 'uiSrc/telemetry/checkAnalytics' +import { checkIsAnalyticsGranted, getInfoServer } from 'uiSrc/telemetry/checkAnalytics' import { AdditionalRedisModule } from 'apiSrc/modules/database/models/additional.redis.module' import { ITelemetrySendEvent, @@ -60,13 +60,15 @@ const sendEventTelemetry = (payload: ITelemetrySendEvent) => { const isAnalyticsGranted = checkIsAnalyticsGranted() setAnonymousId(isAnalyticsGranted) - const appType = getAppType() + const { appType: buildType, controlNumber, controlGroup } = getInfoServer() as Record if (isAnalyticsGranted || nonTracking) { return telemetryService?.event({ event, properties: { - buildType: appType, + buildType, + controlNumber, + controlGroup, ...eventData, }, }) @@ -86,10 +88,19 @@ const sendPageViewTelemetry = (payload: ITelemetrySendPageView) => { const isAnalyticsGranted = checkIsAnalyticsGranted() setAnonymousId(isAnalyticsGranted) - const appType = getAppType() + + const { appType: buildType, controlNumber, controlGroup } = getInfoServer() as Record if (isAnalyticsGranted || nonTracking) { - telemetryService?.pageView(name, appType, databaseId) + telemetryService?.pageView( + name, + { + buildType, + controlNumber, + controlGroup, + databaseId + } + ) } } diff --git a/redisinsight/ui/src/utils/test-utils.tsx b/redisinsight/ui/src/utils/test-utils.tsx index 8ec1e0507d..719f1b3e1a 100644 --- a/redisinsight/ui/src/utils/test-utils.tsx +++ b/redisinsight/ui/src/utils/test-utils.tsx @@ -216,7 +216,8 @@ jest.mock( 'uiSrc/telemetry/checkAnalytics', () => ({ checkIsAnalyticsGranted: jest.fn(), - getAppType: jest.fn() + getAppType: jest.fn(), + getInfoServer: jest.fn().mockReturnValue({}), }) )