Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion redisinsight/api/config/features-config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": 2.56,
"version": 2.57,
"features": {
"redisDataIntegration": {
"flag": true,
Expand Down Expand Up @@ -111,6 +111,10 @@
"data": {
"strategy": "ioredis"
}
},
"enhancedCloudUI": {
"flag": true,
"perc": [[0, 50]]
}
}
}
1 change: 1 addition & 0 deletions redisinsight/api/src/modules/feature/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export enum KnownFeatures {
DatabaseChat = 'databaseChat',
Rdi = 'redisDataIntegration',
HashFieldExpiration = 'hashFieldExpiration',
EnhancedCloudUI = 'enhancedCloudUI',
}

export interface IFeatureFlag {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,8 @@ export const knownFeatures: Record<KnownFeatures, IFeatureFlag> = {
name: KnownFeatures.Rdi,
storage: FeatureStorage.Database,
},
[KnownFeatures.EnhancedCloudUI]: {
name: KnownFeatures.EnhancedCloudUI,
storage: FeatureStorage.Database,
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ export class FeatureFlagProvider {
this.featuresConfigService,
this.settingsService,
));
this.strategies.set(KnownFeatures.EnhancedCloudUI, new WithDataFlagStrategy(
this.featuresConfigService,
this.settingsService,
));
}

getStrategy(name: string): FeatureFlagStrategy {
Expand Down
1 change: 1 addition & 0 deletions redisinsight/ui/src/constants/featureFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ export enum FeatureFlags {
disabledByEnv = 'disabledByEnv',
rdi = 'redisDataIntegration',
hashFieldExpiration = 'hashFieldExpiration',
enhancedCloudUI = 'enhancedCloudUI',
}
41 changes: 41 additions & 0 deletions redisinsight/ui/src/pages/home/HomePage.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react'
import { render, screen } from 'uiSrc/utils/test-utils'
import { appFeatureFlagsFeaturesSelector } from 'uiSrc/slices/app/features'
import HomePage from './HomePage'

jest.mock('uiSrc/slices/panels/sidePanels', () => ({
Expand All @@ -9,6 +10,24 @@ jest.mock('uiSrc/slices/panels/sidePanels', () => ({
}),
}))

jest.mock('uiSrc/slices/content/create-redis-buttons', () => ({
...jest.requireActual('uiSrc/slices/content/create-redis-buttons'),
contentSelector: jest.fn().mockReturnValue({
data: {
cloud_list_of_databases: {}
}
}),
}))

jest.mock('uiSrc/slices/app/features', () => ({
...jest.requireActual('uiSrc/slices/app/features'),
appFeatureFlagsFeaturesSelector: jest.fn().mockReturnValue({
enhancedCloudUI: {
flag: false
}
}),
}))

/**
* HomePage tests
*
Expand All @@ -30,4 +49,26 @@ describe('HomePage', () => {

expect(screen.getByTestId('side-panels-insights')).toBeInTheDocument()
})

it('should not render free cloud db with feature flag disabled', async () => {
(appFeatureFlagsFeaturesSelector as jest.Mock).mockReturnValueOnce({
enhancedCloudUI: {
flag: false
}
})
await render(<HomePage />)

expect(screen.queryByTestId('db-row_create-free-cloud-db')).not.toBeInTheDocument()
})

it('should render free cloud db with feature flag enabled', async () => {
(appFeatureFlagsFeaturesSelector as jest.Mock).mockReturnValueOnce({
enhancedCloudUI: {
flag: true
}
})
await render(<HomePage />)

expect(screen.getByTestId('db-row_create-free-cloud-db')).toBeInTheDocument()
})
})
6 changes: 4 additions & 2 deletions redisinsight/ui/src/pages/home/HomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { useDispatch, useSelector } from 'react-redux'
import { clusterSelector, resetDataRedisCluster, resetInstancesRedisCluster, } from 'uiSrc/slices/instances/cluster'
import { Nullable, setTitle } from 'uiSrc/utils'
import { HomePageTemplate } from 'uiSrc/templates'
import { BrowserStorageItem } from 'uiSrc/constants'
import { BrowserStorageItem, FeatureFlags } from 'uiSrc/constants'
import { resetKeys } from 'uiSrc/slices/browser/keys'
import { resetCliHelperSettings, resetCliSettingsAction } from 'uiSrc/slices/cli/cli-settings'
import { resetRedisearchKeysData } from 'uiSrc/slices/browser/redisearch'
Expand Down Expand Up @@ -41,6 +41,7 @@ import DatabasePanelDialog from './components/database-panel-dialog'

import './styles.scss'
import styles from './styles.module.scss'
import { appFeatureFlagsFeaturesSelector } from 'uiSrc/slices/app/features'

enum OpenDialogName {
AddDatabase = 'add',
Expand All @@ -58,6 +59,7 @@ const HomePage = () => {
const { instance: sentinelInstance } = useSelector(sentinelSelector)
const { action, dbConnection } = useSelector(appRedirectionSelector)
const { data: createDbContent } = useSelector(contentSelector)
const { [FeatureFlags.enhancedCloudUI]: enhancedCloudUIFeature } = useSelector(appFeatureFlagsFeaturesSelector)

const {
loading,
Expand All @@ -73,7 +75,7 @@ const HomePage = () => {

const { contextInstanceId } = useSelector(appContextSelector)

const predefinedInstances = createDbContent?.cloud_list_of_databases ? [
const predefinedInstances = enhancedCloudUIFeature?.flag && createDbContent?.cloud_list_of_databases ? [
{ id: CREATE_CLOUD_DB_ID, ...createDbContent.cloud_list_of_databases } as Instance
] : []
const isInstanceExists = instances.length > 0 || predefinedInstances.length > 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ describe('DatabasesListWrapper', () => {

expect(store.getActions()).toEqual([
setSSOFlow(OAuthSocialAction.Create),
setSocialDialogState(OAuthSocialSource.ListOfDatabases)
setSocialDialogState(OAuthSocialSource.DatabaseConnectionList)
])
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import {
Criteria,
EuiButtonIcon,
EuiIcon,
EuiLink, EuiResizeObserver,
EuiLink,
EuiResizeObserver,
EuiTableFieldDataColumnType,
EuiText,
EuiTextColor,
Expand Down Expand Up @@ -53,7 +54,7 @@ import { setSSOFlow } from 'uiSrc/slices/instances/cloud'
import { setSocialDialogState } from 'uiSrc/slices/oauth/cloud'
import { appFeatureFlagsFeaturesSelector } from 'uiSrc/slices/app/features'
import { getUtmExternalLink } from 'uiSrc/utils/links'
import { CREATE_CLOUD_DB_ID } from 'uiSrc/pages/home/constants'
import { CREATE_CLOUD_DB_ID, HELP_LINKS } from 'uiSrc/pages/home/constants'
import styles from './styles.module.scss'

export interface Props {
Expand Down Expand Up @@ -243,10 +244,19 @@ const DatabasesListWrapper = (props: Props) => {
const handleClickFreeDb = () => {
if (cloudSsoFeature?.flag) {
dispatch(setSSOFlow(OAuthSocialAction.Create))
dispatch(setSocialDialogState(OAuthSocialSource.ListOfDatabases))
dispatch(setSocialDialogState(OAuthSocialSource.DatabaseConnectionList))
sendEventTelemetry({
event: TelemetryEvent.CLOUD_FREE_DATABASE_CLICKED,
eventData: { source: OAuthSocialSource.DatabaseConnectionList },
})
return
}

sendEventTelemetry({
event: HELP_LINKS.cloud.event,
eventData: { source: HELP_LINKS.cloud.sources.databaseConnectionList },
})

const link = document.createElement('a')
link.setAttribute('href', getUtmExternalLink(EXTERNAL_LINKS.tryFree, { campaign: 'list_of_databases' }))
link.setAttribute('target', '_blank')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,38 @@
import React from 'react'
import { instance, mock } from 'ts-mockito'
import { render } from 'uiSrc/utils/test-utils'
import { render, screen } from 'uiSrc/utils/test-utils'
import { appFeatureFlagsFeaturesSelector } from 'uiSrc/slices/app/features'
import DatabaseListHeader, { Props } from './DatabaseListHeader'

const mockedProps = mock<Props>()

jest.mock('uiSrc/slices/app/features', () => ({
...jest.requireActual('uiSrc/slices/app/features'),
appFeatureFlagsFeaturesSelector: jest.fn().mockReturnValue({
enhancedCloudUI: {
flag: false
}
}),
}))

jest.mock('uiSrc/slices/content/create-redis-buttons', () => ({
...jest.requireActual('uiSrc/slices/content/create-redis-buttons'),
contentSelector: jest.fn().mockReturnValue({
data: {
cloud: {
title: 'Try Redis Cloud: your ultimate Redis starting point',
description: 'Includes native support for JSON, Search and Query, and more',
links: {
main: {
altText: 'Try Redis Cloud.',
url: 'https://redis.io/try-free/?utm_source=redisinsight&utm_medium=main&utm_campaign=main'
}
},
}
}
}),
}))

jest.mock('uiSrc/telemetry', () => ({
...jest.requireActual('uiSrc/telemetry'),
sendEventTelemetry: jest.fn(),
Expand All @@ -14,4 +42,28 @@ describe('DatabaseListHeader', () => {
it('should render', () => {
expect(render(<DatabaseListHeader {...instance(mockedProps)} />)).toBeTruthy()
})

it('should not show promo cloud button with disabled feature flag', () => {
(appFeatureFlagsFeaturesSelector as jest.Mock).mockReturnValueOnce({
enhancedCloudUI: {
flag: true
}
})

render(<DatabaseListHeader {...instance(mockedProps)} />)

expect(screen.queryByTestId('promo-btn')).not.toBeInTheDocument()
})

it('should show promo cloud button with enabled feature flag', () => {
(appFeatureFlagsFeaturesSelector as jest.Mock).mockReturnValueOnce({
enhancedCloudUI: {
flag: false
}
})

render(<DatabaseListHeader {...instance(mockedProps)} />)

expect(screen.getByTestId('promo-btn')).toBeInTheDocument()
})
})
Loading
Loading