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
21 changes: 19 additions & 2 deletions redisinsight/ui/src/components/config/Config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { useLocation } from 'react-router-dom'
import { isNumber } from 'lodash'
import { BrowserStorageItem, FeatureFlags } from 'uiSrc/constants'
import { BrowserStorageItem, FeatureFlags, Theme } from 'uiSrc/constants'
import { BuildType } from 'uiSrc/constants/env'
import { BUILD_FEATURES } from 'uiSrc/constants/featuresHighlighting'
import { localStorageService, setObjectStorage } from 'uiSrc/services'
import {
localStorageService,
setObjectStorage,
themeService,
} from 'uiSrc/services'

import {
appFeatureFlagsFeaturesSelector,
setFeaturesToHighlight,
Expand Down Expand Up @@ -102,6 +107,12 @@ const Config = () => {
}
}, [id])

useEffect(() => {
if (config) {
checkAndSetTheme()
}
}, [config])

useEffect(() => {
if (config && spec && envDependentFeature?.flag) {
checkSettingsToShowPopup()
Expand Down Expand Up @@ -198,6 +209,12 @@ const Config = () => {
)
}

const checkAndSetTheme = () => {
const theme = config?.theme
if (theme && localStorageService.get(BrowserStorageItem.theme) !== theme)
themeService.applyTheme(theme as Theme)
}

return null
}

Expand Down
53 changes: 5 additions & 48 deletions redisinsight/ui/src/pages/settings/SettingsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,23 @@
import React, { useContext, useEffect, useState } from 'react'
import React, { useEffect, useState } from 'react'
import cx from 'classnames'
import {
EuiCallOut,
EuiCollapsibleNavGroup,
EuiForm,
EuiFormRow,
EuiLoadingSpinner,
EuiSuperSelect,
EuiText,
EuiTitle,
} from '@elastic/eui'
import { useDispatch, useSelector } from 'react-redux'

import { setTitle } from 'uiSrc/utils'
import { FeatureFlags, Theme, THEMES } from 'uiSrc/constants'
import { FeatureFlags } from 'uiSrc/constants'
import { useDebouncedEffect } from 'uiSrc/services'
import {
ConsentsNotifications,
ConsentsPrivacy,
FeatureFlagComponent,
} from 'uiSrc/components'
import {
sendEventTelemetry,
sendPageViewTelemetry,
TelemetryEvent,
TelemetryPageView,
} from 'uiSrc/telemetry'
import { ThemeContext } from 'uiSrc/contexts/themeContext'
import { sendPageViewTelemetry, TelemetryPageView } from 'uiSrc/telemetry'
import {
fetchUserConfigSettings,
fetchUserSettingsSpec,
Expand All @@ -45,6 +36,7 @@ import {
AdvancedSettings,
CloudSettings,
WorkbenchSettings,
ThemeSettings,
} from './components'
import { DateTimeFormatter } from './components/general-settings'
import styles from './styles.module.scss'
Expand All @@ -57,14 +49,6 @@ const SettingsPage = () => {

const dispatch = useDispatch()

const options = THEMES
const themeContext = useContext(ThemeContext)
let { theme, changeTheme, usingSystemTheme } = themeContext

if (usingSystemTheme) {
theme = Theme.System
}

useEffect(() => {
// componentDidMount
// fetch config settings, after that take spec
Expand All @@ -80,36 +64,9 @@ const SettingsPage = () => {
useDebouncedEffect(() => setLoading(settingsLoading), 100, [settingsLoading])
setTitle('Settings')

const onChange = (value: string) => {
const previousValue = theme
changeTheme(value)
sendEventTelemetry({
event: TelemetryEvent.SETTINGS_COLOR_THEME_CHANGED,
eventData: {
previousColorTheme: previousValue,
currentColorTheme: value,
},
})
}

const Appearance = () => (
<>
<EuiForm component="form">
<EuiTitle size="xs">
<h4>Color Theme</h4>
</EuiTitle>
<Spacer size="m" />
<EuiFormRow label="Specifies the color theme to be used in Redis Insight:">
<EuiSuperSelect
options={options}
valueOfSelected={theme}
onChange={onChange}
style={{ marginTop: '12px' }}
data-test-subj="select-theme"
/>
</EuiFormRow>
<Spacer size="xl" />
</EuiForm>
<ThemeSettings />
<ConsentsNotifications />
<Divider colorVariable="separatorColor" />
<Spacer />
Expand Down
9 changes: 8 additions & 1 deletion redisinsight/ui/src/pages/settings/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,12 @@ import AdvancedSettings from './advanced-settings'
import WorkbenchSettings from './workbench-settings'
import CloudSettings from './cloud-settings'
import GeneralSettings from './general-settings'
import ThemeSettings from './theme-settings'

export { AdvancedSettings, WorkbenchSettings, CloudSettings, GeneralSettings }
export {
AdvancedSettings,
WorkbenchSettings,
CloudSettings,
GeneralSettings,
ThemeSettings,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import React from 'react'
import { cloneDeep } from 'lodash'
import {
cleanup,
fireEvent,
mockedStore,
render,
screen,
waitFor,
} from 'uiSrc/utils/test-utils'
import { Theme, THEMES } from 'uiSrc/constants'
import { TelemetryEvent } from 'uiSrc/telemetry'
import { updateUserConfigSettingsAction } from 'uiSrc/slices/user/user-settings'

import ThemeSettings from './ThemeSettings'

jest.mock('uiSrc/telemetry', () => ({
...jest.requireActual('uiSrc/telemetry'),
sendEventTelemetry: jest.fn(),
}))

jest.mock('uiSrc/slices/user/user-settings', () => {
const original = jest.requireActual('uiSrc/slices/user/user-settings')
return {
...original,
updateUserConfigSettingsAction: jest.fn(() => ({ type: 'TEST_ACTION' })),
}
})

const { sendEventTelemetry } = require('uiSrc/telemetry')

let store: typeof mockedStore

describe('ThemeSettings', () => {
beforeEach(() => {
cleanup()
store = cloneDeep(mockedStore)
store.clearActions()
})

it('should render', () => {
expect(render(<ThemeSettings />)).toBeTruthy()
})

it('should update the selected theme and dispatch telemetry on change', async () => {
const initialTheme = Theme.Dark
const newTheme = Theme.Light

// @ts-ignore-next-line
store.getState().user.settings.config = {
...store.getState().user.settings.config,
theme: initialTheme,
}

render(<ThemeSettings />, { store })

const dropdownButton = screen.getByTestId('select-theme')
fireEvent.click(dropdownButton)

await waitFor(() => {
expect(screen.getByText('Light Theme')).toBeInTheDocument()
})

fireEvent.click(screen.getByText('Light Theme'))

expect(updateUserConfigSettingsAction).toHaveBeenCalledWith({
theme: newTheme,
})

expect(sendEventTelemetry).toHaveBeenCalledWith({
event: TelemetryEvent.SETTINGS_COLOR_THEME_CHANGED,
eventData: {
previousColorTheme: initialTheme,
currentColorTheme: newTheme,
},
})
})

it('should display all theme options from THEMES', async () => {
// @ts-ignore-next-line
store.getState().user.settings.config = {
...store.getState().user.settings.config,
theme: Theme.Dark,
}

render(<ThemeSettings />, { store })

const dropdownButton = screen.getByTestId('select-theme')
fireEvent.click(dropdownButton)

const darkTheme = THEMES.find((theme) => theme.value === Theme.Dark)

const rest = THEMES.filter((theme) => theme.value !== Theme.Dark)

await waitFor(() => {
// Selected theme name appears 2 times in the dropdown
// once in the list and once in the selected value
expect(
screen.queryAllByText(darkTheme?.inputDisplay as string).length,
).toEqual(2)

rest.forEach((theme) => {
expect(
screen.getByText(theme.inputDisplay as string),
).toBeInTheDocument()
})
})
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { useContext, useEffect, useRef, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { EuiForm, EuiFormRow, EuiSuperSelect, EuiTitle } from '@elastic/eui'
import { Spacer } from 'uiSrc/components/base/layout/spacer'
import {
updateUserConfigSettingsAction,
userSettingsSelector,
} from 'uiSrc/slices/user/user-settings'
import { ThemeContext } from 'uiSrc/contexts/themeContext'
import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry'
import { THEMES } from 'uiSrc/constants'

const ThemeSettings = () => {
const dispatch = useDispatch()
const [selectedTheme, setSelectedTheme] = useState('')
const options = THEMES
const themeContext = useContext(ThemeContext)
const { theme, changeTheme } = themeContext
const { config } = useSelector(userSettingsSelector)
const previousThemeRef = useRef<string>(theme)

useEffect(() => {
if (config) {
setSelectedTheme(config.theme)
previousThemeRef.current = config.theme
}
}, [config])

const onChange = (value: string) => {
const previousValue = previousThemeRef.current
if (previousValue === value) {
return
}
changeTheme(value)
dispatch(updateUserConfigSettingsAction({ theme: value }))
sendEventTelemetry({
event: TelemetryEvent.SETTINGS_COLOR_THEME_CHANGED,
eventData: {
previousColorTheme: previousValue,
currentColorTheme: value,
},
})
}

return (
<EuiForm component="form">
<EuiTitle size="xs">
<h4>Color Theme</h4>
</EuiTitle>
<Spacer size="m" />
<EuiFormRow label="Specifies the color theme to be used in Redis Insight:">
<EuiSuperSelect
options={options}
valueOfSelected={selectedTheme}
onChange={onChange}
style={{ marginTop: '12px' }}
data-test-subj="select-theme"
data-testid="select-theme"
/>
</EuiFormRow>
<Spacer size="xl" />
</EuiForm>
)
}

export default ThemeSettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import ThemeSettings from './ThemeSettings'

export default ThemeSettings
2 changes: 1 addition & 1 deletion redisinsight/ui/src/services/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class ThemeService {

document.adoptedStyleSheets = [sheet]

localStorageService.set(BrowserStorageItem.theme, actualTheme)
localStorageService.set(BrowserStorageItem.theme, newTheme)
document.body.classList.value = `theme_${actualTheme}`
}

Expand Down
Loading