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
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export const analyticsViewTabs: AnalyticsTabs[] = [
},
{
id: AnalyticsViewTab.DatabaseAnalysis,
label: 'Memory Efficiency',
label: 'Redis Database Analysis',
},
{
id: AnalyticsViewTab.SlowLog,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useParams } from 'react-router-dom'

import {
dbAnalysisSelector,
DBAnalysisReportsSelector,
dbAnalysisReportsSelector,
fetchDBAnalysisAction,
fetchDBAnalysisReportsHistory,
setSelectedAnalysisId
Expand All @@ -14,6 +14,7 @@ import { appAnalyticsInfoSelector } from 'uiSrc/slices/app/info'
import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances'
import { AnalyticsViewTab } from 'uiSrc/slices/interfaces/analytics'
import { sendPageViewTelemetry, sendEventTelemetry, TelemetryPageView, TelemetryEvent } from 'uiSrc/telemetry'
import { formatLongName, getDbIndex, setTitle } from 'uiSrc/utils'

import Header from './components/header'
import AnalysisDataView from './components/analysis-data-view'
Expand All @@ -24,12 +25,14 @@ const DatabaseAnalysisPage = () => {
const { viewTab } = useSelector(analyticsSettingsSelector)
const { identified: analyticsIdentified } = useSelector(appAnalyticsInfoSelector)
const { loading: analysisLoading, data } = useSelector(dbAnalysisSelector)
const { data: reports, selectedAnalysis } = useSelector(DBAnalysisReportsSelector)
const { name: connectedInstanceName } = useSelector(connectedInstanceSelector)
const { data: reports, selectedAnalysis } = useSelector(dbAnalysisReportsSelector)
const { name: connectedInstanceName, db } = useSelector(connectedInstanceSelector)

const [isPageViewSent, setIsPageViewSent] = useState<boolean>(false)

const dispatch = useDispatch()
const dbName = `${formatLongName(connectedInstanceName, 33, 0, '...')} ${getDbIndex(db)}`
setTitle(`${dbName} - Database Analysis`)

useEffect(() => {
dispatch(fetchDBAnalysisReportsHistory(instanceId))
Expand All @@ -51,7 +54,7 @@ const DatabaseAnalysisPage = () => {

const handleSelectAnalysis = (reportId: string) => {
sendEventTelemetry({
event: TelemetryEvent.MEMORY_ANALYSIS_HISTORY_VIEWED,
event: TelemetryEvent.DATABASE_ANALYSIS_HISTORY_VIEWED,
eventData: {
databaseId: instanceId,
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
import React from 'react'
import { instance, mock } from 'ts-mockito'
import { MOCK_ANALYSIS_REPORT_DATA } from 'uiSrc/mocks/data/analysis'
import { INSTANCE_ID_MOCK } from 'uiSrc/mocks/handlers/analytics/clusterDetailsHandlers'
import { SectionName } from 'uiSrc/pages/databaseAnalysis'
import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry'
import { formatBytes, getGroupTypeDisplay } from 'uiSrc/utils'
import { numberWithSpaces } from 'uiSrc/utils/numbers'
import { fireEvent, render, screen, within } from 'uiSrc/utils/test-utils'

import AnalysisDataView, { Props } from './AnalysisDataView'

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

const mockedProps = mock<Props>()
const mockReports = [
{
id: MOCK_ANALYSIS_REPORT_DATA.id,
Expand All @@ -20,6 +27,11 @@ const mockReports = [
}
]

const summaryContainerId = 'summary-per-data'
const analyticsTTLContainerId = 'analysis-ttl'
const topNameSpacesContainerId = 'top-namespaces'
const extrapolateResultsId = 'extrapolate-results'

describe('AnalysisDataView', () => {
it('should render', () => {
expect(render(<AnalysisDataView {...instance(mockedProps)} />)).toBeTruthy()
Expand Down Expand Up @@ -104,7 +116,7 @@ describe('AnalysisDataView', () => {
<AnalysisDataView {...instance(mockedProps)} reports={mockReports} data={mockedData} />
)

fireEvent.click(within(screen.getByTestId('summary-per-data')).getByTestId('extrapolate-results'))
fireEvent.click(within(screen.getByTestId(summaryContainerId)).getByTestId(extrapolateResultsId))

expect(screen.getByTestId('total-memory-value')).toHaveTextContent(`${formatBytes(mockedData.totalMemory.total, 3)}`)
expect(screen.getByTestId('total-keys-value')).toHaveTextContent(`${numberWithSpaces(mockedData.totalKeys.total)}`)
Expand Down Expand Up @@ -157,7 +169,7 @@ describe('AnalysisDataView', () => {
render(
<AnalysisDataView {...instance(mockedProps)} reports={mockReports} data={mockedData} />
)
fireEvent.click(within(screen.getByTestId('analysis-ttl')).getByTestId('extrapolate-results'))
fireEvent.click(within(screen.getByTestId(analyticsTTLContainerId)).getByTestId(extrapolateResultsId))

const expirationGroup = mockedData.expirationGroups[1]

Expand Down Expand Up @@ -198,7 +210,7 @@ describe('AnalysisDataView', () => {
render(
<AnalysisDataView {...instance(mockedProps)} reports={mockReports} data={mockedData} />
)
fireEvent.click(within(screen.getByTestId('top-namespaces')).getByTestId('extrapolate-results'))
fireEvent.click(within(screen.getByTestId(topNameSpacesContainerId)).getByTestId(extrapolateResultsId))

const nspTopKeyItem = mockedData.topKeysNsp[0]
expect(screen.getByTestId(`nsp-usedMemory-value=${nspTopKeyItem.memory}`))
Expand All @@ -221,7 +233,7 @@ describe('AnalysisDataView', () => {
<AnalysisDataView {...instance(mockedProps)} reports={mockReports} data={mockedData} />
)

expect(screen.queryByTestId('extrapolate-results')).not.toBeInTheDocument()
expect(screen.queryByTestId(extrapolateResultsId)).not.toBeInTheDocument()

expect(screen.getByTestId('total-memory-value')).toHaveTextContent(`${formatBytes(mockedData.totalMemory.total, 3)}`)
expect(screen.getByTestId('total-keys-value')).toHaveTextContent(`${numberWithSpaces(mockedData.totalKeys.total)}`)
Expand All @@ -238,4 +250,45 @@ describe('AnalysisDataView', () => {
expect(screen.getAllByTestId(`keys-value-${nspTopKeyItem.keys}`)[0])
.toHaveTextContent(`${numberWithSpaces(nspTopKeyItem.keys)}`)
})

it('should call proper telemetry events after click extrapolation', () => {
const mockedData = {
...MOCK_ANALYSIS_REPORT_DATA,
progress: {
total: 80,
scanned: 10000,
processed: 40
}
}
const sendEventTelemetryMock = jest.fn()
sendEventTelemetry.mockImplementation(() => sendEventTelemetryMock)

render(
<AnalysisDataView {...instance(mockedProps)} reports={mockReports} data={mockedData} />
)

const clickAndCheckTelemetry = (el: HTMLInputElement, section: SectionName) => {
fireEvent.click(el)
expect(sendEventTelemetry).toBeCalledWith({
event: TelemetryEvent.DATABASE_ANALYSIS_EXTRAPOLATION_CHANGED,
eventData: {
databaseId: INSTANCE_ID_MOCK,
from: !el.checked,
to: el.checked,
section
}
})
sendEventTelemetry.mockRestore()
}

[
{ id: summaryContainerId, section: SectionName.SUMMARY_PER_DATA },
{ id: analyticsTTLContainerId, section: SectionName.MEMORY_LIKELY_TO_BE_FREED },
{ id: topNameSpacesContainerId, section: SectionName.TOP_NAMESPACES },
].forEach(({ id, section }) => {
const extrapolateSwitch = within(screen.getByTestId(id)).getByTestId(extrapolateResultsId)
clickAndCheckTelemetry(extrapolateSwitch as HTMLInputElement, section)
clickAndCheckTelemetry(extrapolateSwitch as HTMLInputElement, section)
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { isNull } from 'lodash'
import { useParams } from 'react-router-dom'
import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry'
import { Nullable } from 'uiSrc/utils'
import { DEFAULT_EXTRAPOLATION, EmptyMessage } from 'uiSrc/pages/databaseAnalysis/constants'
import { DEFAULT_EXTRAPOLATION, EmptyMessage, SectionName } from 'uiSrc/pages/databaseAnalysis/constants'
import {
TopKeys,
EmptyAnalysisMessage,
Expand Down Expand Up @@ -34,13 +34,14 @@ const AnalysisDataView = (props: Props) => {
}
}, [data])

const onSwitchExtrapolation = (value: boolean) => {
const onSwitchExtrapolation = (value: boolean, section: SectionName) => {
sendEventTelemetry({
event: TelemetryEvent.MEMORY_ANALYSIS_EXTRAPOLATION_CHANGED,
event: TelemetryEvent.DATABASE_ANALYSIS_EXTRAPOLATION_CHANGED,
eventData: {
databaseId: instanceId,
from: !value,
to: value
to: value,
section
}
})
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
import React, { useEffect, useState } from 'react'
import { EuiSwitch, EuiTitle } from '@elastic/eui'
import AutoSizer from 'react-virtualized-auto-sizer'
import { useDispatch, useSelector } from 'react-redux'
import cx from 'classnames'

import { DEFAULT_EXTRAPOLATION } from 'uiSrc/pages/databaseAnalysis'
import { extrapolate, formatBytes, formatExtrapolation, Nullable } from 'uiSrc/utils'
import cx from 'classnames'
import React, { useEffect, useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import AutoSizer from 'react-virtualized-auto-sizer'
import { AreaChart } from 'uiSrc/components/charts'
import { AreaChartData, AreaChartDataType, DEFAULT_MULTIPLIER_GRID } from 'uiSrc/components/charts/area-chart/AreaChart'
import { DBAnalysisReportsSelector, setShowNoExpiryGroup } from 'uiSrc/slices/analytics/dbAnalysis'

import { DEFAULT_EXTRAPOLATION, SectionName } from 'uiSrc/pages/databaseAnalysis'
import { dbAnalysisReportsSelector, setShowNoExpiryGroup } from 'uiSrc/slices/analytics/dbAnalysis'
import { extrapolate, formatBytes, formatExtrapolation, Nullable } from 'uiSrc/utils'
import { DatabaseAnalysis } from 'apiSrc/modules/database-analysis/models'

import styles from './styles.module.scss'

export interface Props {
data: Nullable<DatabaseAnalysis>
loading: boolean
extrapolation: number
onSwitchExtrapolation?: (value: boolean) => void
onSwitchExtrapolation?: (value: boolean, section: SectionName) => void
}

const ExpirationGroupsView = (props: Props) => {
const { data, loading, extrapolation, onSwitchExtrapolation } = props
const { totalMemory, totalKeys } = data || {}

const { showNoExpiryGroup } = useSelector(DBAnalysisReportsSelector)
const { showNoExpiryGroup } = useSelector(dbAnalysisReportsSelector)
const [expirationGroups, setExpirationGroups] = useState<AreaChartData[]>([])
const [isExtrapolated, setIsExtrapolated] = useState<boolean>(true)

Expand Down Expand Up @@ -90,7 +92,7 @@ const ExpirationGroupsView = (props: Props) => {
checked={isExtrapolated}
onChange={(e) => {
setIsExtrapolated(e.target.checked)
onSwitchExtrapolation?.(e.target.checked)
onSwitchExtrapolation?.(e.target.checked, SectionName.MEMORY_LIKELY_TO_BE_FREED)
}}
data-testid="extrapolate-results"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ describe('DatabaseAnalysisHeader', () => {
fireEvent.click(screen.getByTestId('start-database-analysis-btn'))

expect(sendEventTelemetry).toBeCalledWith({
event: TelemetryEvent.MEMORY_ANALYSIS_STARTED,
event: TelemetryEvent.DATABASE_ANALYSIS_STARTED,
eventData: {
databaseId: INSTANCE_ID_MOCK,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const Header = (props: Props) => {

const handleClick = () => {
sendEventTelemetry({
event: TelemetryEvent.MEMORY_ANALYSIS_STARTED,
event: TelemetryEvent.DATABASE_ANALYSIS_STARTED,
eventData: {
databaseId: instanceId,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { DonutChart } from 'uiSrc/components/charts'
import { ChartData } from 'uiSrc/components/charts/donut-chart/DonutChart'
import { KeyIconSvg, MemoryIconSvg } from 'uiSrc/components/database-overview/components/icons'
import { GROUP_TYPES_COLORS, GroupTypesColors } from 'uiSrc/constants'
import { DEFAULT_EXTRAPOLATION } from 'uiSrc/pages/databaseAnalysis'
import { DEFAULT_EXTRAPOLATION, SectionName } from 'uiSrc/pages/databaseAnalysis'
import { extrapolate, formatBytes, getGroupTypeDisplay, Nullable } from 'uiSrc/utils'
import { getPercentage, numberWithSpaces } from 'uiSrc/utils/numbers'

Expand All @@ -18,7 +18,7 @@ export interface Props {
data: Nullable<DatabaseAnalysis>
loading: boolean
extrapolation?: number
onSwitchExtrapolation?: (value: boolean) => void
onSwitchExtrapolation?: (value: boolean, section: SectionName) => void
}

const widthResponsiveSize = 1024
Expand Down Expand Up @@ -132,7 +132,7 @@ const SummaryPerData = ({ data, loading, extrapolation, onSwitchExtrapolation }:
checked={isExtrapolated}
onChange={(e) => {
setIsExtrapolated(e.target.checked)
onSwitchExtrapolation?.(e.target.checked)
onSwitchExtrapolation?.(e.target.checked, SectionName.SUMMARY_PER_DATA)
}}
data-testid="extrapolate-results"
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import React, { useEffect, useState } from 'react'
import cx from 'classnames'
import { EuiButton, EuiSwitch, EuiTitle } from '@elastic/eui'
import { Nullable } from 'uiSrc/utils'
import { DEFAULT_EXTRAPOLATION, TableView } from 'uiSrc/pages/databaseAnalysis'
import cx from 'classnames'
import React, { useEffect, useState } from 'react'
import { DEFAULT_EXTRAPOLATION, SectionName, TableView } from 'uiSrc/pages/databaseAnalysis'
import { TableLoader } from 'uiSrc/pages/databaseAnalysis/components'
import { Nullable } from 'uiSrc/utils'
import { DatabaseAnalysis } from 'apiSrc/modules/database-analysis/models'

import Table from './Table'
import styles from './styles.module.scss'

export interface Props {
data: Nullable<DatabaseAnalysis>
loading: boolean
extrapolation: number
onSwitchExtrapolation?: (value: boolean) => void
onSwitchExtrapolation?: (value: boolean, section: SectionName) => void
}

const TopNamespace = (props: Props) => {
Expand Down Expand Up @@ -70,7 +69,7 @@ const TopNamespace = (props: Props) => {
checked={isExtrapolated}
onChange={(e) => {
setIsExtrapolated(e.target.checked)
onSwitchExtrapolation?.(e.target.checked)
onSwitchExtrapolation?.(e.target.checked, SectionName.TOP_NAMESPACES)
}}
data-testid="extrapolate-results"
/>
Expand Down
6 changes: 6 additions & 0 deletions redisinsight/ui/src/pages/databaseAnalysis/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,9 @@ export type Content = {
}

export const DEFAULT_EXTRAPOLATION = 1

export enum SectionName {
SUMMARY_PER_DATA = 'SUMMARY_PER_DATA',
MEMORY_LIKELY_TO_BE_FREED = 'MEMORY_LIKELY_TO_BE_FREED',
TOP_NAMESPACES = 'TOP_NAMESPACES',
}
2 changes: 1 addition & 1 deletion redisinsight/ui/src/slices/analytics/dbAnalysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const databaseAnalysisSlice = createSlice({
})

export const dbAnalysisSelector = (state: RootState) => state.analytics.databaseAnalysis
export const DBAnalysisReportsSelector = (state: RootState) => state.analytics.databaseAnalysis.history
export const dbAnalysisReportsSelector = (state: RootState) => state.analytics.databaseAnalysis.history

export const {
setDatabaseAnalysisInitialState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import reducer, {
fetchDBAnalysisAction,
createNewAnalysis,
fetchDBAnalysisReportsHistory,
DBAnalysisReportsSelector,
dbAnalysisReportsSelector,
dbAnalysisSelector,
setShowNoExpiryGroup,
} from 'uiSrc/slices/analytics/dbAnalysis'
Expand Down Expand Up @@ -110,7 +110,7 @@ describe('db analysis slice', () => {
const rootState = Object.assign(initialStateDefault, {
analytics: { databaseAnalysis: nextState },
})
expect(DBAnalysisReportsSelector(rootState)).toEqual(stateHistory)
expect(dbAnalysisReportsSelector(rootState)).toEqual(stateHistory)
})
})

Expand Down Expand Up @@ -235,7 +235,7 @@ describe('db analysis slice', () => {
const rootState = Object.assign(initialStateDefault, {
analytics: { databaseAnalysis: nextState },
})
expect(DBAnalysisReportsSelector(rootState)).toEqual(stateHistory)
expect(dbAnalysisReportsSelector(rootState)).toEqual(stateHistory)
})
})
describe('setShowNoExpiryGroup', () => {
Expand All @@ -254,7 +254,7 @@ describe('db analysis slice', () => {
const rootState = Object.assign(initialStateDefault, {
analytics: { databaseAnalysis: nextState },
})
expect(DBAnalysisReportsSelector(rootState)).toEqual(stateHistory)
expect(dbAnalysisReportsSelector(rootState)).toEqual(stateHistory)
})
})
})
Expand Down
6 changes: 3 additions & 3 deletions redisinsight/ui/src/telemetry/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,9 @@ export enum TelemetryEvent {
BULK_ACTIONS_WARNING = 'BULK_ACTIONS_WARNING',
BULK_ACTIONS_CANCELLED = 'BULK_ACTIONS_CANCELLED',

MEMORY_ANALYSIS_STARTED = 'MEMORY_ANALYSIS_STARTED',
MEMORY_ANALYSIS_HISTORY_VIEWED = 'MEMORY_ANALYSIS_HISTORY_VIEWED',
MEMORY_ANALYSIS_EXTRAPOLATION_CHANGED = 'MEMORY_ANALYSIS_EXTRAPOLATION_CHANGED',
DATABASE_ANALYSIS_STARTED = 'DATABASE_ANALYSIS_STARTED',
DATABASE_ANALYSIS_HISTORY_VIEWED = 'DATABASE_ANALYSIS_HISTORY_VIEWED',
DATABASE_ANALYSIS_EXTRAPOLATION_CHANGED = 'DATABASE_ANALYSIS_EXTRAPOLATION_CHANGED',

USER_SURVEY_LINK_CLICKED = 'USER_SURVEY_LINK_CLICKED',
}
2 changes: 1 addition & 1 deletion redisinsight/ui/src/telemetry/pageViews.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ export enum TelemetryPageView {
SLOWLOG_PAGE = 'Slow Log',
CLUSTER_DETAILS_PAGE = 'Overview',
PUBSUB_PAGE = 'Pub/Sub',
DATABASE_ANALYSIS = 'Memory analysis'
DATABASE_ANALYSIS = 'Database Analysis'
}